2008-10-19 6 views
1

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

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

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

EDIT: BTW плагин будет рабом не мастер , Основное действие подключаемого модуля будет заключаться в том, что в данной ситуации он будет призван «выполнить свою задачу» и получит объект среды, который он должен использовать, чтобы получить то, что ему нужно для работы.

+0

Моя первая идея состояла в том, чтобы включить подключаемый модуль, содержащий статический конструктор, который регистрирует подключаемый модуль при запуске. Однако C# (один из языков, с которым мне нужно работать), по-видимому, не вызывает статические конструкторы, кроме как по требованию, и это не работает. Есть идеи? – BCS 2008-10-19 23:38:42

ответ

2

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

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

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

+0

Хороший ответ. Это тип информации, которую я ищу. – BCS 2008-10-20 02:33:37

0

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

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

+0

OK, что может быть полезно в целом, но как вызывается вызов Register? Кто это делает, как основное приложение, как известно, ссылается на это? – BCS 2008-10-20 02:26:17

1

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

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

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

+0

Я бы хотел избежать «умного» в конечном счете. В краткосрочной перспективе это может быть приемлемо для первоначального подключения (перекомпилировать временные плагины) – BCS 2008-10-20 02:28:54

3

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

+0

Я даже не смотрю/не знаю, как пользователь это получает. Я все еще работаю над тем, как избежать необходимости взломать каждую дополнительную функцию в основную базу кода. – BCS 2008-10-20 02:30:31

+0

http://codeelegance.blogspot.com/2009/06/monoaddins-in-msnet-20-application-part.html – 2009-06-04 17:54:55

0

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

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

+0

Шахта идет во 2-ом направлении. – BCS 2008-10-20 02:32:22

1

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

0

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

1

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

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

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