一个完整、开箱即用的 C++ 插件化系统 Demo,演示了动态库导出、工厂模式、Magic Static、生命周期钩子等核心知识点。
本项目实现了一个最小但完整的 C++ 插件化系统。宿主程序在运行时动态加载共享库(.so),通过工厂接口创建插件实例并调用其功能,展示了现代 C++ 与操作系统动态链接机制的深度结合。
| # | 知识点 | 代码位置 | 说明 |
|---|---|---|---|
| 1 | 动态库导出宏与 extern "C" |
include/plugin_core.h |
PSDK_PLUGIN_EXPORT_C 宏实现跨平台符号导出,阻止 C++ Name Mangling |
| 2 | 工厂模式 + 反射雏形 | include/plugin_core.h + plugin/my_plugin.cpp |
std::map<string, function> 注册表实现按字符串名动态创建类实例 |
| 3 | Magic Static + Lambda IIFE | plugin/my_plugin.cpp |
static T obj = [](){}() 模式确保线程安全、延迟初始化的单例工厂 |
| 4 | 动态库生命周期钩子 | plugin/my_plugin.cpp |
全局对象的构造函数/析构函数自动在 dlopen/dlclose 时执行 |
plugin_system_demo/
├── CMakeLists.txt # 现代 CMake 构建配置
├── README.md # 项目文档(本文)
├── include/
│ └── plugin_core.h # 核心接口定义(IPlugin / IPluginFactory / 导出宏)
├── plugin/
│ └── my_plugin.cpp # 插件实现(DataAggregatorPlugin + 入口函数 + 生命周期钩子)
└── host/
└── main.cpp # 宿主程序(dlopen/dlsym/dlclose + 工厂调用演示)
- C++ 编译器:GCC 7+ / Clang 5+ / MSVC 2019+
- 构建工具:CMake 3.14+
- 操作系统:Linux / macOS / WSL2 / Windows (WSL)
# 1. 进入项目根目录
cd plugin_system_demo
# 2. 创建构建目录(推荐 out-of-source 构建)
mkdir -p build && cd build
# 3. 配置 CMake(生成 Makefile)
cmake ..
# 4. 编译
make
# 5. 查看编译产物
ls -la bin/ lib/# 确保当前目录为 build/bin(或将 lib 加入 LD_LIBRARY_PATH)
cd build/bin
# 运行宿主程序
./host_app============================================
Plugin System Demo - Host Application
============================================
[Host] Loading plugin library: ./libmyplugin.so
[data_proc] Shared library data_proc plugin loaded OK <-- dlopen() 触发全局构造
[Host] Factory loaded: name='PluginSystem', version='1.0.0'
[Host] Creating plugin instance: DataAggregatorPlugin
[Host] Plugin info: name='DataAggregatorPlugin', version='1.0.0'
[Host] Initializing plugin...
[DataAggregator] Initialized with 10 data points.
[Host] Executing plugin...
========== [DataAggregator] Statistics Report ==========
Dataset size : 10
Mean : 55.00
Median : 55.00
Min : 10.00
Max : 100.00
======================================================
[Host] Shutting down plugin...
[DataAggregator] Shutdown complete.
[Host] Cleaning up...
[Host] Closing plugin library...
[data_proc] Shared library data_proc plugin unloaded OK <-- dlclose() 触发全局析构
[Host] Done.
| 输出行 | 触发时机 | 说明 |
|---|---|---|
"[data_proc] Shared library data_proc plugin loaded OK" |
dlopen() 成功返回后 |
动态库被映射到进程空间,全局对象 _DLLInit 构造函数执行 |
"Factory loaded: ... |
GetPluginFactory() 被调用后 |
工厂实例的 Magic Static 初始化完成并返回地址 |
"Initialized with ... data points" |
plugin->initialize() |
DataAggregatorPlugin 初始化内部数据集 |
"Statistics Report" |
plugin->execute() |
数据聚合逻辑执行完毕 |
"Shutdown complete" |
plugin->shutdown() |
插件释放资源 |
"[data_proc] Shared library data_proc plugin unloaded OK" |
dlclose() 被调用后 |
库的引用计数归零,库从进程空间卸载,全局对象析构 |
#if defined(_WIN32) || defined(_WIN64)
#define PSDK_PLUGIN_EXPORT_C extern "C" __declspec(dllexport)
#else
#define PSDK_PLUGIN_EXPORT_C extern "C" __attribute__((visibility("default")))
#endifextern "C":阻止 C++ Name Mangling,使符号以纯 C 方式编译/链接__attribute__((visibility("default"))):GCC/Clang 下强制将符号标记为导出可见__declspec(dllexport):MSVC 下导出动态库符号
// 注册阶段(插件代码)
p.registerClass<DataAggregatorPlugin>("DataAggregatorPlugin");
// 调用阶段(宿主代码)——无需知道 DataAggregatorPlugin 的具体类型
auto plugin = factory->createInstance("DataAggregatorPlugin");通过 std::map<std::string, std::function<...>> 实现的注册表,使宿主程序可以完全通过字符串名称来请求任意已���册的插件类型,无需编译期耦合。
static PluginFactory pinfo = []
{
auto p = PluginFactory("data_proc", "1.0.0");
p.registerClass<DataAggregatorPlugin>("DataAggregatorPlugin");
return p;
}();static局部变量保证延迟初始化(直到第一次调用时才创建)- C++11 起标准保证静态局部变量初始化线程安全
- Lambda 立即执行表达式(
[](){}())使初始化逻辑内联、紧凑
struct _DLLInit
{
_DLLInit() { std::cout << "plugin loaded OK" << std::endl; }
~_DLLInit() { std::cout << "plugin unloaded OK" << std::endl; }
} dll_init;C++ 全局对象的构造函数在动态库被 dlopen() 时自动调用,析构函数在 dlclose() 时自动调用,无需宿主程序显式介入。
- 多插件支持:在
PluginFactory::registry_中注册多个类,通过不同的字符串名称分别创建 - Windows 支持:添加
host/main_win.cpp,使用LoadLibrary/GetProcAddress/FreeLibrary - 插件版本管理:在注册表中记录每个类的版本号,宿主程序验证兼容性后再使用
- 依赖注入:在
initialize()中传入宿主程序提供的上下文对象或回调函数 - 热加载:使用
dlclose+ 重新dlopen实现插件的动态替换(需处理好对象生命周期)
本项目采用 MIT 许可证,可自由使用、修改和分发。