Здравствуйте, Rothmans, Вы писали:
K_O>>Нормально, но API для плагинов должен быть на С.
R>А что это значит? R>Основная программа может быть написана и скомпилирована на С++. Плагины (.so shared library) должны при этом писаться на С? R>Или как отделить API от самого "тела" плагина?
Это значит:
1. Экспортируются только функции и структуры (не методы, не классы, не шаблоны), объявление которых обернуто в extern "C" {}
2. Экспортируемые функции не могут быть перегружены
3. Экспортируемые функции не могут бросать исключений
4. Выделение и освобождение конкретного куска памяти должно происходить строго в одном и том же модуле
Короче, никакие С++ хвосты не должны быть видны авторам плагина.
При этом сами модули (и основной и плагины) могут быть написаны на чем угодно.
Очень хороший пример в данном случае — Far. Посмотрите, какой у него Plugin API.
R>Использовать один и тот же компилятор для обеих частей моей программы -- это исключительно единственное существующее решение?
Все еще хуже: может потребоваться одна и та же версия компилятора.
Например у g++ разных версий при одинаковом манглинге разный ABI.
Т.е. линкер соберет без ошибок, а при работе могут быть глюки — одна сторона сунула параметр в регистр, а другая читает его из стека и т.д.
Единственная гарантия — голый Си.
Поэтому например в операционке внутри честные классы, а наружу отдают сишный интерфейс с неким хэндлом (opaque) — тупые обертки над методами класса.
Потом прикладной программист на своей стороне городит плюсовые обертки к этим хэндлам, чтобы работать именно как с объектами...
Кстати, под виндой тоже весело -- у VS2005 и SV2005 SP1 рантайм по поведению отличается, а имя одно и то же.
Здравствуйте, Kh_Oleg, Вы писали:
K_O>Здравствуйте, Rothmans, Вы писали:
K_O>>>Короче, никакие С++ хвосты не должны быть видны авторам плагина. R>>С++ хвосты из главного приложения, так? K_O>Модули должны "думать", что другая сторона написана на С. Другое дело, что если предоставить грамотный API, то хвостов из плагина не увидишь при всем желании. За исключением исключений (вот такой каламбур): главное приложение должно стараться не упасть, если плагин кинет наружу исключение.
Плагин кидать исключения вообще-то не должен. А уж если кинул — то селяви, ничего ты с этим не поделаешь, если например основное приложение собрано msvc, а плагин — gcc-mingw. Как более надежная альтернатива — взаимодействия плагинов и основного приложения через IPC и держать плагины в отдельных процессах. Но это уже параноя
Здравствуйте, Kh_Oleg, Вы писали:
K_O>Здравствуйте, Rothmans, Вы писали:
A>>>Плагин кидать исключения вообще-то не должен. А уж если кинул — то селяви, ничего ты с этим не поделаешь, если например основное приложение собрано msvc, а плагин — gcc-mingw. Как более надежная альтернатива — взаимодействия плагинов и основного приложения через IPC и держать плагины в отдельных процессах. Но это уже параноя
R>>А почему параноя? Если мне важна стабильность главного приложения не взирая на то, что там кто в плагине написал? R>>Без IPC выходит exception может сбить главное приложение? IPC выходит лучший выход? K_O>Ну, например, тот же Far умеет обрабатывать исключения от плагинов и выгружать сбойные плагины, не падая сам.
Да это все полумеры, т.к. если какой плагин полезет курочить память/стек приложения, то никакой SEH не спасет. Так что если принять за аксиому, что плагин может порушить основное приложение, если он в памяти процесса оказался, то есть два варианта:
— грузить плагины в память приложения;
— НЕ грузить плагины в память приложения.
Здравствуй, Олег!
K_O>>>Короче, никакие С++ хвосты не должны быть видны авторам плагина. R>>С++ хвосты из главного приложения, так? K_O>Модули должны "думать", что другая сторона написана на С. Другое дело, что если предоставить грамотный API, то хвостов из плагина не увидишь при всем желании. За исключением исключений (вот такой каламбур): главное приложение должно стараться не упасть, если плагин кинет наружу исключение.
дай уже человеку самому почитать и подумать
K_O>>>При этом сами модули (и основной и плагины) могут быть написаны на чем угодно.
Там есть нюансы.
Есть один более менее гарантированно работающий вариант — разработчики плагинов используют shared C++ runtime в точности тот же что и приложение. Совместная работа нескольких разных рантаймов возможна но это тонкий лед. Вот например ссылка почитать про gcc здесь. Там поближе к концу ...
Здравствуйте, Rothmans, Вы писали:
R>Привет всем,
R>Я совсем не специалист по Линуксу. R>У меня есть хост, устройство, на котором работает кастомизированный Линукс, это может быть BusyBox или даже собранная под данный процессор Убунту. R>Для работы большинства программ в такой системе требуются библиотеки. Си-рантайм, stlport, z, pthread, и прочие.
... R>Как посоветуете разрешить конфликт? R>Использовать один и тот же компилятор для обеих частей моей программы -- это исключительно единственное существующее решение?
ну можно еще собрать все статикой
там нужны будут нетривиальные приседания но работать будет. Размер кода это минус — да.
зы. На счет приседаний сразу ссылка ибо узнавать это на практике неприятно.
(флеймовое имхо). В теории есть некое С++ ABI с версиями ... и тп. Но это все (аби, линкер, гдб) писали люди которые ненавидят плюсы наверное.
Здравствуйте, wander, Вы писали:
W>Здравствуйте, Rothmans, Вы писали:
R>>Привет всем,
R>>Я совсем не специалист по Линуксу. W>Все это касается не только Линукса. Поэтому в отношении С++ вообще на всех ОС единственное верное решение — R>>Использовать один и тот же компилятор для обеих частей моей программы
Ну это глупости, откровенно говоря. Вот, например Руководство по дизайну бинарно-совместимых C++ API
Опять же, COM на винде — это наглядная иллюстрация, что интерфейс exe <-> dll может быть написан на C++. И нигде нет требований использовать для всех модулей один и тот же компилятор
Я совсем не специалист по Линуксу.
У меня есть хост, устройство, на котором работает кастомизированный Линукс, это может быть BusyBox или даже собранная под данный процессор Убунту.
Для работы большинства программ в такой системе требуются библиотеки. Си-рантайм, stlport, z, pthread, и прочие.
Большинство из них уже есть в системе, вероятно скомпилированные тем же компилятором, которым готовился весь дистрибутив.
У меня есть в распоряжении именно тот самый компилятор, которым все это дело собиралось.
Теперь вопрос.
Если я возьму совсем другой компилятор, но для того же процессора, и скомпилирую часть своей программы им, а часть (shared libraries) исходным компилятором.
Программа и библиотеки написаны на С++ (не С).
Верно ли, что 100% совместимость частей моей программы не гарантируется? Т.е. даже если все на первый взгляд работает вместе, то это не гарантия совместисмоти. И что в общем бинарные файлы программ, написанных на С++, могут быть несовместимы друг с другом, если скопилированы разными компиляторами, даже несмотря на то, что линковались с одними и теми же библиотеками?
Как посоветуете разрешить конфликт?
Использовать один и тот же компилятор для обеих частей моей программы -- это исключительно единственное существующее решение?
Здравствуйте, K13, Вы писали:
R>>Использовать один и тот же компилятор для обеих частей моей программы -- это исключительно единственное существующее решение?
K13>Все еще хуже: может потребоваться одна и та же версия компилятора. K13>Например у g++ разных версий при одинаковом манглинге разный ABI.
Да да, я и имел ввиду одну и ту же версию
Ясно *вздыхает*
Здравствуйте, K13, Вы писали:
K13>Поэтому например в операционке внутри честные классы, а наружу отдают сишный интерфейс с неким хэндлом (opaque) — тупые обертки над методами класса.
Э-э.. подробнее можно? Где это "внутри операционки" есть честные классы? В ядре?
Здравствуйте, Rothmans, Вы писали:
R>Привет всем,
R>Я совсем не специалист по Линуксу.
Все это касается не только Линукса. Поэтому в отношении С++ вообще на всех ОС единственное верное решение — R>Использовать один и тот же компилятор для обеих частей моей программы
Здравствуйте, SleepyDrago, Вы писали:
SD>ну можно еще собрать все статикой SD>там нужны будут нетривиальные приседания но работать будет. Размер кода это минус — да.
Статически линковать не годится, поскольку речь именно идет о возможности использования динамически загружаемых плагин-модулей, написанных на стороне.
Как вам такая идея на базе .so для Линукса?
Здравствуйте, Rothmans, Вы писали:
R>Статически линковать не годится, поскольку речь именно идет о возможности использования динамически загружаемых плагин-модулей, написанных на стороне. R>Как вам такая идея на базе .so для Линукса?
Нормально, но API для плагинов должен быть на С.
Здравствуйте, Kh_Oleg, Вы писали:
K_O>Здравствуйте, Rothmans, Вы писали:
R>>Статически линковать не годится, поскольку речь именно идет о возможности использования динамически загружаемых плагин-модулей, написанных на стороне. R>>Как вам такая идея на базе .so для Линукса? K_O>Нормально, но API для плагинов должен быть на С.
А что это значит?
Основная программа может быть написана и скомпилирована на С++. Плагины (.so shared library) должны при этом писаться на С?
Или как отделить API от самого "тела" плагина?
Здравствуйте, Kh_Oleg, Вы писали:
K_O>Здравствуйте, Rothmans, Вы писали:
K_O>>>Нормально, но API для плагинов должен быть на С.
R>>А что это значит? R>>Основная программа может быть написана и скомпилирована на С++. Плагины (.so shared library) должны при этом писаться на С? R>>Или как отделить API от самого "тела" плагина? K_O>Это значит: K_O>1. Экспортируются только функции и структуры (не методы, не классы, не шаблоны), объявление которых обернуто в extern "C" {} K_O>2. Экспортируемые функции не могут быть перегружены K_O>3. Экспортируемые функции не могут бросать исключений K_O>4. Выделение и освобождение конкретного куска памяти должно происходить строго в одном и том же модуле K_O>Короче, никакие С++ хвосты не должны быть видны авторам плагина.
С++ хвосты из главного приложения, так?
K_O>При этом сами модули (и основной и плагины) могут быть написаны на чем угодно.
..но модули должны экспортировать реализации функций как указано выше, верно?
K_O>Очень хороший пример в данном случае — Far. Посмотрите, какой у него Plugin API.
Супер, спасибо за инфу!
(Сорри за повторные вопросы, не хочу чтобы что-то случайно ускользнуло от моего понимания)
Здравствуйте, Rothmans, Вы писали:
K_O>>Короче, никакие С++ хвосты не должны быть видны авторам плагина. R>С++ хвосты из главного приложения, так?
Модули должны "думать", что другая сторона написана на С. Другое дело, что если предоставить грамотный API, то хвостов из плагина не увидишь при всем желании. За исключением исключений (вот такой каламбур): главное приложение должно стараться не упасть, если плагин кинет наружу исключение.
K_O>>При этом сами модули (и основной и плагины) могут быть написаны на чем угодно. R>..но модули должны экспортировать реализации функций как указано выше, верно?
Да.
Здравствуйте, artem_korneev, Вы писали:
K13>>Поэтому например в операционке внутри честные классы, а наружу отдают сишный интерфейс с неким хэндлом (opaque) — тупые обертки над методами класса.
_>Э-э.. подробнее можно? Где это "внутри операционки" есть честные классы? В ядре?
Например, большинство драйверов периферии для Windows CE, поставляемых MS, писаны на C++.
Здравствуйте, alsemm, Вы писали:
A>Здравствуйте, Kh_Oleg, Вы писали:
K_O>>Здравствуйте, Rothmans, Вы писали:
K_O>>>>Короче, никакие С++ хвосты не должны быть видны авторам плагина. R>>>С++ хвосты из главного приложения, так? K_O>>Модули должны "думать", что другая сторона написана на С. Другое дело, что если предоставить грамотный API, то хвостов из плагина не увидишь при всем желании. За исключением исключений (вот такой каламбур): главное приложение должно стараться не упасть, если плагин кинет наружу исключение. A>Плагин кидать исключения вообще-то не должен. А уж если кинул — то селяви, ничего ты с этим не поделаешь, если например основное приложение собрано msvc, а плагин — gcc-mingw. Как более надежная альтернатива — взаимодействия плагинов и основного приложения через IPC и держать плагины в отдельных процессах. Но это уже параноя
А почему параноя? Если мне важна стабильность главного приложения не взирая на то, что там кто в плагине написал?
Без IPC выходит exception может сбить главное приложение? IPC выходит лучший выход?
Здравствуйте, Rothmans, Вы писали:
A>>Плагин кидать исключения вообще-то не должен. А уж если кинул — то селяви, ничего ты с этим не поделаешь, если например основное приложение собрано msvc, а плагин — gcc-mingw. Как более надежная альтернатива — взаимодействия плагинов и основного приложения через IPC и держать плагины в отдельных процессах. Но это уже параноя
R>А почему параноя? Если мне важна стабильность главного приложения не взирая на то, что там кто в плагине написал? R>Без IPC выходит exception может сбить главное приложение? IPC выходит лучший выход?
Ну, например, тот же Far умеет обрабатывать исключения от плагинов и выгружать сбойные плагины, не падая сам. Хотя я подозреваю, что в этом задействован механизм SEH и для Unix, если и есть решение, то оно будет совершенно иным.
IPC имеет свои недостатки — автор плагина должен будет четко понимать, что его творение будет работать в другом процессе, в другом адресном пространстве и возможность обмена информацией с основной программной будет ограничена.
Так что все зависит от задачи — что требуется обязательно и что желательно.
Здравствуйте, Rothmans, Вы писали:
R>А почему параноя? Если мне важна стабильность главного приложения не взирая на то, что там кто в плагине написал? R>Без IPC выходит exception может сбить главное приложение? IPC выходит лучший выход?
Если это просто десктопное приложение, я бы с IPC заморачиваться не стал — больно много возни.
Здравствуйте, alsemm, Вы писали:
A>Здравствуйте, Rothmans, Вы писали:
R>>А почему параноя? Если мне важна стабильность главного приложения не взирая на то, что там кто в плагине написал? R>>Без IPC выходит exception может сбить главное приложение? IPC выходит лучший выход? A>Если это просто десктопное приложение, я бы с IPC заморачиваться не стал — больно много возни.
Не, это такое важное сервисное приложение, позаморачиваться нужно.
Спасибо за анализ
Здравствуйте, alsemm, Вы писали:
A>Опять же, COM на винде — это наглядная иллюстрация, что интерфейс exe <-> dll может быть написан на C++. И нигде нет требований использовать для всех модулей один и тот же компилятор
Э.. как раз ниже по ссылке насчет бинарного интерфейса COM. Я сделал вывод, что разные компиляторы в этом случае можно использовать лишь потому что Микрософт протолкнуло COM ABI и все с ним совместимыми хотят быть.
Здравствуйте, alsemm, Вы писали:
A>Ну это глупости, откровенно говоря. Вот, например Руководство по дизайну бинарно-совместимых C++ API A>Опять же, COM на винде — это наглядная иллюстрация, что интерфейс exe <-> dll может быть написан на C++. И нигде нет требований использовать для всех модулей один и тот же компилятор
Не наглядная иллюстрация, а исключение, подтверждающее правило. COM ABI — это, по сути, следующие требования:
1. Указатель на VMT лежит по нулевому смещению в объекте (в общем случае это может быть не так)
2. Порядок следования методов в VMT совпадает с порядком их объявления
И при этом никаких шаблонов, множественного наследования для неинтерфейсов, исключений, перегруженных методов. Короче, от всего С++ осталась только таблица виртуальных методов. В принципе, работать будет. Но, как показывает практика, отдача плагину указателя на внутренний объект программы влечет тааакие проблемы, что намного проще отказаться от интерфейсов и реализовать API в виде простых функций-команд.
Здравствуйте, Kh_Oleg, Вы писали:
K_O>Здравствуйте, alsemm, Вы писали:
A>>Ну это глупости, откровенно говоря. Вот, например Руководство по дизайну бинарно-совместимых C++ API A>>Опять же, COM на винде — это наглядная иллюстрация, что интерфейс exe <-> dll может быть написан на C++. И нигде нет требований использовать для всех модулей один и тот же компилятор K_O>Не наглядная иллюстрация, а исключение, подтверждающее правило. COM ABI — это, по сути, следующие требования: K_O>1. Указатель на VMT лежит по нулевому смещению в объекте (в общем случае это может быть не так)
Какой распространенный компилятор размещает указатель на VMT по другому?
K_O>2. Порядок следования методов в VMT совпадает с порядком их объявления
Ну да, так же как и порядок объевления полей совпадает с тем, как они в памяти размещаются.
K_O>И при этом никаких шаблонов,
Это почему? Код шаблона инлайнится, так что на здоровье
K_O>множественного наследования для неинтерфейсов,
Полезность этой фичи недоказана
K_O>исключений, перегруженных методов.
Да, это создает определенное неудобство
K_O>Короче, от всего С++ осталась только таблица виртуальных методов. В принципе, работать будет. Но, как показывает практика, отдача плагину указателя на внутренний объект программы влечет тааакие проблемы, что намного проще отказаться от интерфейсов и реализовать API в виде простых функций-команд.
Ну это смотря что и кому отдавать.
Вообщем я согласен, что использовать C++ на всю катушку в межмодульных интерфейсах нельзя. Но те ошметки от C++ которые можно использовать все же приятнее чем голый C
Здравствуйте, alsemm, Вы писали:
K_O>>Не наглядная иллюстрация, а исключение, подтверждающее правило. COM ABI — это, по сути, следующие требования: K_O>>1. Указатель на VMT лежит по нулевому смещению в объекте (в общем случае это может быть не так) A>Какой распространенный компилятор размещает указатель на VMT по другому?
Беда в том, что у меня нет гарантий, что пользователь воспользуется распространенным компилятором.
K_O>>Короче, от всего С++ осталась только таблица виртуальных методов. В принципе, работать будет. Но, как показывает практика, отдача плагину указателя на внутренний объект программы влечет тааакие проблемы, что намного проще отказаться от интерфейсов и реализовать API в виде простых функций-команд. A>Ну это смотря что и кому отдавать.
Плагину, поведение которого нам неподвластно. А это значит, объект нельзя удалить либо до выгрузки плагина (а это очень сложно реализовать), либо вообще.
Здравствуйте, Kh_Oleg, Вы писали:
K_O>Здравствуйте, alsemm, Вы писали:
K_O>>>Не наглядная иллюстрация, а исключение, подтверждающее правило. COM ABI — это, по сути, следующие требования: K_O>>>1. Указатель на VMT лежит по нулевому смещению в объекте (в общем случае это может быть не так) A>>Какой распространенный компилятор размещает указатель на VMT по другому? K_O>Беда в том, что у меня нет гарантий, что пользователь воспользуется распространенным компилятором.
Хорошо, хоть один "нераспространенный" такой C++ компилятор найдется?
A>>Ну это смотря что и кому отдавать. K_O>Плагину, поведение которого нам неподвластно. А это значит, объект нельзя удалить либо до выгрузки плагина (а это очень сложно реализовать), либо вообще.
Про параною я уже писал — лечится через IPC. В противном случае, если временем жизни объектов приходится управлять руками, а не через подсчет ссылок, например, то в интерфейс плагина вводится метод notifyGlobalObjectDestroy(). Дергается у каждого плагина, перед тем, как убить глобальный объект, а дальше кто не спрятался я не виноват
K13>>Поэтому например в операционке внутри честные классы, а наружу отдают сишный интерфейс с неким хэндлом (opaque) — тупые обертки над методами класса.
_>Э-э.. подробнее можно? Где это "внутри операционки" есть честные классы? В ядре?
Например, Mac OS X.
Внутри — честные классы Obj-C. И из cocoa к ним есть доступ, а для C/C++ (carbon) — только через сишный апи с opaque handles.
Что внутри windows — не смотрел. Но думаю, что какая-то часть тоже объекты...
А такой вариант?
Главное приложение собирается одним компилятором, все необходимые библиотеки попадают на целевую платформу вместе с ним.
Плагины собираются другим компилятором, и необходимые компиляторо-зависимые библиотеки параллельно складываются на целевую систему.
Приложение и плагины работают, используя разные рантаймы и прочее, общение -- через IPC.
Здравствуйте, Rothmans, Вы писали:
R>А такой вариант? R>Главное приложение собирается одним компилятором, все необходимые библиотеки попадают на целевую платформу вместе с ним. R>Плагины собираются другим компилятором, и необходимые компиляторо-зависимые библиотеки параллельно складываются на целевую систему. R>Приложение и плагины работают, используя разные рантаймы и прочее, общение -- через IPC.
100% взлетит, без сомнений. Если приложение живет в своем процессе и плагины каждый в своем, то "плохой" плагин никому навредить, кроме себя не сможет. Остается выбрать подходящую библиотеку IPC, чтобы руками не писать передачу объектов м/у приложением и плагинами.