Что рекомендуется для подключаемых систем в приложениях?

StackOverflow https://stackoverflow.com/questions/217172

Вопрос

Каковы “обычные” способы создания плагинов на скомпилированных языках (C # / C / C ++ / D)?Меня особенно интересуют подходы, не зависящие от языка, но специфика языка не является неприемлемой.

На данный момент подключаемые подходы “времени компиляции” (просто включите код или нет, и все заработает) допустимы, но предпочтительнее то, что может перейти на более динамичный подход.

Что касается типа среды выполнения, меня больше интересует механика загрузки плагина и еще много чего, чем проектирование интерфейса плагина / приложения

Редактировать:Кстати, плагин будет подчиненным, а не ведущим.Основное действие подключаемого модуля будет заключаться в том, что в данной ситуации он будет призван "делать свое дело" и получит объект среды, который он должен использовать, чтобы получить то, что ему нужно для работы.

Это было полезно?

Решение

Для скомпилированных языков (где скомпилированный означает, что программа запускается как собственный исполняемый файл без какой-либо виртуальной машины), вам в значительной степени необходимо использовать какой-то подход к общей библиотеке для конкретной платформы. В Windows это означает использование DLL.

Вы определяете интерфейс своего плагина в терминах набора функций (с конкретными именами, аргументами и соглашениями о вызовах). Затем вы загружаете адреса функций в общей библиотеке и отправляетесь в город. В Windows это означает использование GetProcAddress () и затем приведение возвращаемого значения к указателю на функцию соответствующего типа в C или в любом другом эквиваленте на используемом вами языке.

Другой вариант, который может быть, а может и не быть более желательным, состоит в том, чтобы запустить виртуальную машину для другого языка из вашего собственного приложения, и чтобы плагины были кодом для этого языка. Например, вы можете запустить виртуальную машину Python с использованием CPython и динамически загружать модули Python.

Другие советы

Mono.Addins представляется хорошим решением для .NET. Я полагаю, что он включает API, позволяющий загружать плагины (или надстройки) из репозитория и динамически загружать его в работающую сборку.

Я обнаружил, что трудными частями плагинов являются: их поиск, разрешение их зависимостей и решение проблем с версиями. Как вы решаете эти проблемы, должно быть понятно вам и вашим авторам плагинов. Если вы поймете эти проблемы неправильно, это не вызовет конца боли. Я хотел бы взглянуть на языки сценариев и приложения, которые используют плагины, чтобы понять, что хорошо работает.

Статические конструкторы чаще всего являются «умными»; в плохом смысле. Поскольку вам придется загружать (C / C ++: dlopen и friends под Linux) плагины по одному в любом случае (в динамическом случае), вы также можете явно инициализировать их, как и вы. Среди прочего, это может дать вам возможность отклонить плагины без ожидаемых API.

Обратите внимание, вам не нужно использовать библиотеки динамической загрузки для плагинов. Также можно использовать другие механизмы: общая память, сокеты и т. Д.

Это действительно зависит от того, что вы хотите сделать. Обычный шаблон Unix, который можно увидеть в Emacs и Gimp, заключается в написании программы, состоящей из небольшого скомпилированного компонента, который предоставляет основные функциональные возможности, которые интерпретируемый компонент использует для всего. Плагины, которые предоставляют новые функциональные возможности, которые могут быть встроены в приложение, просты, но вы должны быть очень гибкими в тех примитивах, которые вы предоставляете, чтобы это было возможно. С другой стороны, представьте себе фоторедактор, который можно сохранять в нескольких форматах. Вы хотите позволить людям писать свои собственные обработчики формата файла. Это требует, чтобы ваш код использовал простой набор примитивов, а затем выбирал реализацию во время выполнения. В прямой (Unix) C используйте dlopen, в C ++ используйте extern C, который ограничивает то, что вы можете сделать, и dlopen. В Objective-C у вас есть класс, чтобы сделать это для вас. В первом случае вы делаете или повторно используете переводчика, поэтому у вас есть право свободно делать это так, как вы хотите.

Для плагина подчиненного типа, где каждый плагин инкапсулирует различную реализацию общего набора функций, я бы просто поместил библиотеки DLL в папку плагина, известную хост-приложению (например"c:\program files\myapp\plugins), а затем вызываем библиотеки DLL с хоста с помощью отражения.

Ты мог бы выполните какой-то сложный процесс регистрации при установке каждой библиотеки DLL, но я никогда не испытывал никаких проблем с простым подходом "плагины в одной папке".

Редактировать:Чтобы сделать это на C #, вы просто добавляете открытый класс в DLL (с именем "Plugin" или как там еще) и реализуете там необходимые функции.Затем на вашем хостинге вы создаете объект типа Plugin и вызываете его методы (все с использованием отражения).

Интерфейсы с пустым регистром (EventSource), кажется, работают хорошо - см. IHttpModule.Init (HttpApplication ) для примера.

Это позволяет автору приложения (который управляет EventSource) добавлять события по мере необходимости, без необходимости расширять интерфейс IPlugin (неизбежно приводящий к IPluginEx, IPlugin2, IPlugin2Ex и т. д.)

Подход, который я использовал (в .NET), заключается в том, чтобы хост сделал первоначальный вызов плагина (через Reflection), запустив плагин и передав ссылку на хост, который плагин сохраняет. Затем плагин вызывает методы на хосте (также через отражение) по мере необходимости.

Я думаю, что с большинством плагинов вызовы обычно делаются в другом направлении (то есть хост будет вызывать плагин по мере необходимости). В моем случае сами плагины имели элементы пользовательского интерфейса, которые должны были использовать функциональность хоста.

Помимо проблем реализации низкоуровневого модуля (например, DLL-библиотеки Windows и проблем с реализацией), игровой движок, который я использую, просто имеет глобальную функцию регистрации в DLL-библиотеках и пытается найти и вызвать ее на каждой DLL в каталоге подключаемых модулей. функция регистрации выполняет любую бухгалтерию, необходимую для раскрытия функциональности.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top