TL;DR
- Плагины дают расширяемость: функциональность поставляется отдельными динамическими библиотеками.
- Ядро берёт на себя загрузку, жизненный цикл и контракт (ABI), а модули — бизнес‑логику.
- В PluginCore плагины общаются через “модели” (реестр зависимостей), а точки входа фиксированы: create_plugin/destroy_plugin.
Зачем нужна архитектура
- Гибкость продукта: можно поставлять разные сборки (наборы модулей) под разных клиентов и окружения, меняя только каталог плагинов.
- Снижение связанности: ядро минимально, а большие части логики изолированы в модулях с понятными контрактами.
- Масштабирование команды: плагины удобно разрабатывать параллельно, когда есть стабильный интерфейс ядра.
Как устроен PluginCore
Идея простая: хост создаёт объект ядра, а дальше “система живёт” за счёт плагинов.
#include <PluginCore/Core.hpp>
int main(int argc, char* argv[]) {
PluginCore::Core core(argc, argv);
return 0;
}
- Ядро загружает плагины из ./Plugins или из каталога, заданного переменной окружения PLUGINS_DIR.
- У каждого плагина вызывается registerArgs(), затем ядро парсит аргументы командной строки, затем вызывает registerModels().
- После регистрации моделей вызывается postInit() у всех моделей, и только потом postInit() у всех плагинов.
Такой порядок полезен тем, что аргументы доступны до создания зависимостей, а “поздняя инициализация” позволяет стартовать потоки/таски уже после того, как все модели гарантированно существуют.
ABI и точки входа
// Плагин обязан экспортировать C-ABI функции с точными именами:
extern "C" PluginCore::IPlugin* create_plugin();
extern "C" void destroy_plugin(PluginCore::IPlugin*);
// Важно: уничтожение идёт через destroy_plugin(), а не через delete в хосте.
Выделение памяти и освобождение должны происходить согласованно: такой явный destroy‑хук — простой и практичный способ снизить риск проблем на границе модуль/хост.
Модели и обмен данными
В PluginCore плагины обмениваются функциональностью через модели (PluginCore::IModel) и их реестр ModelsStorage: это похоже на DI‑контейнер/реестр сервисов, но с явным контролем порядка инициализации/удаления.
- Модель имеет пустой конструктор, а настоящая инициализация выполняется в init().
- Порядок удаления контролируется deleteOrder(): меньшие значения удаляются раньше (поддерживаются отрицательные).
- Есть удобный макрос регистрации/получения: RegisterModel(name, new_model, T) (вернёт существующую или зарегистрирует новую).
// Каркас плагина (минимум)
#include <PluginCore/IPlugin.hpp>
#include <PluginCore/ModelsStorage.hpp>
class MyPlugin final : public PluginCore::IPlugin {
public:
void registerModels(PluginCore::ModelsStorage& models) override {
// Регистрируй свои модели или получай чужие из реестра
}
};
extern "C" PluginCore::IPlugin* create_plugin() { return new MyPlugin(); }
extern "C" void destroy_plugin(PluginCore::IPlugin* p) { delete p; }
Статус проекта
Актуальное состояние и исходники: github.com/d3156/PluginCore
Другие статьи
Список строится из articles/index.json.