Организация plug-in'нной системы
Кто-нибудь может пояснить как организуется система plug-in'ов?
Поясню, что я имею ввиду. Вот, допустим, решил я написать какую-то программу (просмотрщик, проигрыватель, коммандер и т.д.) и мне хочется что бы программа была максимально простой и вместе с тем максимально универсальной. Универсальность должна достигаться плагинами. Чтобы не автор, а посторонние люди могли сами писать плагины, расширяющие функциональность программы....
Как правильно организовать программу чтобы она могла понимать плагины? Есть стандарты на это дело?
Павел Кисляк в своём Ral Commander'е все сделал по правилам или он придумал что-то своё?
Разложите, пожалуйста, по полочкам, кто знает. Уверен, что ответы на этот вопрос окажутся полезными не только мне.
Динамическая компоновка рулит
С теоретической точки зрение самый "правильный" способ - это динамическая компоновка. То есть, имеется динамический компоновщик, а с каждым модулем предоставляется дополнительная информация (метаинформация) о расположении и связи с именами точек входа в процедуры, переменных, и т. д. Обращение к процедурам и переменным во внешних модулях осуществляется по именам. При загрузке модуля динамический компоновщик использует информацию о именах и пропатчивает код модуля подставляя актуальные адреса, смещения и константы.
Преимущества динамической компоновки:
-- Возможна полностью раздельная компиляция как импортируемого так и импортирующего модуля. Правда, понадобится компилятор, который умеет создавать информацию о символах.
-- После того как компоновка завершена, модули могут напрямую вызывать процедуры и обращаться к данным друг друга - повышение производительности.
Недостатки:
-- Требуется память под код динамического компоновщика.
-- Требуется время для его работы (обычно это несущественно).
-- Требуется память под информацию о символах. Однако, после операции динамической компоновки её можно использовать повторно.
Другой популярный способ - таблица точек входа в процедуры, расположенная по общеизвестному адресу. Идея в том, имеется фиксированый адрес, обозначенный в документации и не меняющийся от одной версии программы к другой. По этому адресу располагается таблица адресов точек входа в процедуры (могут располагаться также адреса переменных), причём для каждой процедуры смещение её адреса в таблице также не меняется от версии к версии, сам записанный адрес может меняться от версии к версии. Подгружаемый модуль знает адрес таблицы, извлекает из него адрес и использует его для вызова процедуры.
Достоинства:
-- Таблицу адресов можно очень просто автоматически формировать пользуясь уже имеющимися трансляторами ассемблера
Недостатки:
-- Замедление исполнения. Каждый вызов требует обращения к таблице.
-- Раздувание модуля. Дополнительный код для обращения к таблице занимает память.
-- Сама таблица тоже занимает память и её нельзя освободить.
-- Потенциально меньшая гибкость. Адрес таблицы не должен меняться от версии к версии.