Что безопасно для подключаемой системы С++?
Плагины в С++ сложны, потому что ABI не определен правильно, и каждый компилятор (или его версия) следует своим собственным правилам. Однако COM на Windows показывает, что можно создать минимальную подключаемую систему, которая позволяет программистам с разными компиляторами создавать плагины для хост-приложения с помощью простого интерфейса.
Давайте будем практичны и оставим стандарт С++, что не очень полезно в этом отношении, в сторону на минуту. Если я хочу написать приложение для Windows и Mac (и, возможно, Linux), которое поддерживает плагины С++, и если я хочу дать авторам плагинов достаточно большой выбор компиляторов (скажем, менее двух лет версий Visual С++, GCC или компилятор Intel С++), на какие функции С++ я могу рассчитывать?
Конечно, я предполагаю, что плагины будут написаны для конкретной платформы.
Сверху моей головы, вот некоторые возможности С++, о которых я могу думать, с тем, что, на мой взгляд, является ответом:
- vtable layout, использовать объекты через абстрактные классы? (Да)
- встроенные типы, указатели? (Да)
- структуры, союзы? (Да)
- исключения? (Нет)
- extern "C" функции? (Да)
- stdcall non-extern "C" функции со встроенными параметрами? (Да)
- non-stdcall non-extern "C" функции с пользовательскими параметрами? (Нет)
Я был бы признателен за любой опыт, который у вас есть в этой области, которую вы могли бы поделиться. Если вы знаете какое-нибудь умеренно успешное приложение, в котором есть подключаемая система С++, это тоже круто.
Карл
Ответы
Ответ 1
В журнале Dr Dobb Journal есть статья Создание собственной плагиновой платформы: часть 1, которая является довольно хорошим показанием по этому вопросу. Это начало серии статей, которые охватывают архитектуру, разработку и развертывание платформы межплатформенных платформ C/С++.
Ответ 2
Вы также можете рассмотреть возможность замены обычного интерфейса плагина с помощью интерфейса сценариев. Есть несколько очень хороших привязок для нескольких языков сценариев в C/С++, которые уже решили вашу проблему. Наверное, неплохо было бы задуматься над ними. Например, посмотрите Boost.Python.
Ответ 3
Qt имеет очень приятную систему для плагинов, которые я использовал в прошлом. Он использует систему мета-объектов Qt для преодоления многих проблем, обычно возникающих при разработке плагинов С++.
Один пример: Q_DECLARE_INTERFACE
работает, чтобы вы не могли использовать несовместимый плагин. Другой - ключ сборки, чтобы убедиться, что вы загрузили правильный плагин для своей архитектуры, ОС, компилятора. Если вы не используете систему плагинов Qt, вам придется беспокоиться и изобретать решения самостоятельно. Это не обязательно ракетостроение, и я не говорю, что вы потерпите неудачу, но ребята из Trolltech довольно умны и долго думали об этом, и я предпочел бы использовать то, что они создали, чем изобретать колесо самостоятельно.
Другой пример: RTTI обычно не работает через границы DLL, но при использовании Qt такие вещи, как qobject_cast, которые полагаются на метаобъектную систему, работают через границы DLL.
Ответ 4
Я думаю, что вы безопасно создаете систему плагинов на основе:
- Упаковка функций плагина в библиотеку (.dll,.so и т.д.)
- Требование о том, чтобы плагин показывал экспорт ключей на языке C.
- Требование, чтобы плагин реализовал (и вернул указатель/ссылку) абстрактный С++-интерфейс.
Вероятно, самая успешная система плагина С++: старый добрый Adobe Photoshop. И если не это, один из виртуальных форматов синтезатора, таких как VSTi и т.д.
Ответ 5
В книге Imperfect С++ от Matthew Wilson есть хорошая информация об этом.
Совет по-видимому: до тех пор, пока вы используете тот же (или эквивалентный) компилятор, вы можете использовать С++, иначе вам лучше использовать C в качестве интерфейса поверх вашего кода на С++.
Ответ 6
ACE имеет архитектуру подключаемого модуля для кросс-платформы.
Отъезд:
Я бы предложил проверить книгу
Руководство программиста ACE
Ответ 7
Firefox работает на XPCOM (http://www.mozilla.org/projects/xpcom/). Это вдохновило Microsoft COM, но оно многоплатформенное.
Ответ 8
У меня есть собственный движок игры, в котором есть плагин С++.
У меня есть код в заголовочных файлах, поэтому он попадает в блок компиляции плагинов.
Более крупные функции, которые живут в главном движке, вызывается через экспортированную функцию C (плагин вызывает MyObject_somefunction (MyObject * obj), который в движке просто вызывает obj- > somefunction()). Если вызов функции C уродлив для вашего вкуса, то с некоторым обманом заголовка, когда заголовок включен в плагин, используйте функцию-член #defined для вызова функции C:
#if defined(IN_THE_PLUGIN)
void MyObject::somefunction() { MyObject_somefunction(this); }
#endif
Виртуальные функции либо должны быть чистыми, либо код живет в файле заголовка. Если я не наследую от класса и просто просто запускаю один, виртуальный функциональный код может жить в движке, но тогда класс должен экспортировать некоторые C-функции для создания и уничтожения объекта, который вызывается из плагина.
В принципе, трюки, которые я использовал, с целью поддержания общей независимости платформы, просто составляют экспорт C и трюки с файлами заголовков.