Что рекомендуется для подключения систем в приложениях? - PullRequest
1 голос
/ 20 октября 2008

Каковы «нормальные» способы создания плагинов на скомпилированных языках (C # / C / C ++ / D)? Меня особенно интересуют подходы, не зависящие от языка, но язык не является неприемлемым.

В настоящее время подходы «время компиляции» (просто включите код или нет, и все работает) действительны, но предпочтительны вещи, которые могут перейти на более динамичный подход.

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

РЕДАКТИРОВАТЬ: Кстати, плагин будет раб, а не хозяин. Основное действие плагина заключается в том, что в данной ситуации ему будет предложено «сделать свое дело» и получить объект среды, который он должен использовать для получения того, что ему нужно для работы.

Ответы [ 8 ]

3 голосов
/ 20 октября 2008

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

2 голосов
/ 20 октября 2008

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

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

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

1 голос
/ 20 октября 2008

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

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

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

1 голос
/ 20 октября 2008

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

1 голос
/ 20 октября 2008

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

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

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

0 голосов
/ 20 октября 2008

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

0 голосов
/ 20 октября 2008

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

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

0 голосов
/ 20 октября 2008

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

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

...