#c #dynamic #dll #plugins #shared
Вопрос:
Я использую систему плагинов времени компиляции на основе фабрики, которую я хотел бы перенести, чтобы она была более динамичной. На данный момент он основан на статических шаблонных классах регистраторов, где конструктор регистрирует класс на фабрике. например
template <class T>
SingleModuleRegistrar<T>::SingleModuleRegistrar(ModuleDesc description={ T::factoryName(), T::category }) : _name(description.moduleName)
{
ModuleFactoryamp; factory = ModuleFactory::Instance();
factory.Register(this, description);
}
а затем в заголовке DefaultPlugin
класса
static SingleModuleRegistrar<DefaultPlugin> DefaultPluginRegistrar;
Когда это встроено в статическую библиотеку, DefaultPlugin
оно регистрируется на заводе-изготовителе и доступно для использования.
Теперь я хочу переместить статическую библиотеку в библиотеку dll, чтобы я мог динамически добавлять новые плагины на фабрику.
Я могу загрузить dll без проблем, но статическая переменная, похоже, не создается. ожидали бы вы этого, а если нет, то как я могу запустить создание статического DefaultPluginRegistrar
объекта ?
Я могу придумать несколько обходных путей, например, добавить функцию для регистрации плагинов в библиотеке и вызвать ее, но подумал, что было бы здорово, если бы я мог как можно ближе подойти к исходному коду. Кроме того, я хотел бы понять, что происходит с созданием экземпляра статической переменной во время загрузки.
ПРАВКА: Я думаю, что мне следует добавить еще несколько деталей о структуре. В настоящее время DefaultPlugin
регистрация находится в заголовке библиотеки, которая статически связана с .dll. Он также находится в пространстве имен.
MyPlugin.dll
|_ MyStaticLibrary.lib
|_DefaultPlugin.h
SomeNamespace {
class DefaultPlugin : public IPlugin
{
public:
DefaultPlugin();
//etc.
};
// registration
static SingleModuleRegistrar<DefaultPlugin> DefaultPluginRegistrar;
}
|_ SomeOtherStaticLibrary.lib
Я также попытался удалить статическое объявление и экспортировать символ, но безрезультатно
__declspec(dllexport) SingleModuleRegistrar<DefaultPlugin> DefaultPluginRegistrar;
Комментарии:
1. Какой компилятор/набор инструментов вы используете? IIRC, поддержка среды выполнения в DLL должна обрабатывать инициализацию глобальных переменных (я думаю, в сообщении DLL_PROCESS_ATTACH).
2. В данный момент я использую visual studio, но мне также нужно будет сделать это в Linux/gcc
3. Я предполагаю, что DLL получает свою собственную копию
ModuleFactory
«синглтона» и регистрируется с ней, а не с копией, на которую смотрит EXE. Распечатайте или иным образом сбросьтеamp;ModuleFactory::Instance()
файл EXE и DLL — я подозреваю, что вы увидите два разных адреса.4. К сожалению, это не так.. Я переехал
ModuleFactory
в «а». dll специально для того, чтобы остановить это с помощью статического связывания. Конструктор дляDefaultPlugin
никогда не вызывается.5. Немного отвлекающего маневра выше, конструктор
DefaultPlugin
не должен вызываться во время регистрации 😀 Регистрация тоже не происходит, но я подумал, что должен это прояснить. Я вижу, что тестовый плагин зарегистрируется сам, если он находится в заголовке, который находится в самом проекте .dll, а не в одной из библиотек, на которые он ссылается.
Ответ №1:
Хорошо: время супер-фейспалма. Я реорганизовал свою структуру кода в такие красивые отдельные библиотеки, что на самом деле я нигде не включал заголовки, содержащие мои статические объявления плагинов, в dll-код!
Однако я оставлю этот вопрос открытым, так как обнаружил, что это довольно необычная конфигурация, и кому-то может помочь просто знать, что она может работать.
Также может быть полезно отметить, что во время выполнения MS статика инициализируется внутри _initterm
in initterm.cpp
, from dll_main_crt_process_attach
.