【发布时间】:2019-10-27 15:50:05
【问题描述】:
我正在开发一个由许多插件组成的 C++ 库,这些插件可以相互独立地包含在内。插件集仅取决于编译时的用户要求。
插件只是源代码,它们不是独立的二进制文件。
为此,库的主要(也是唯一的)CMakeLists.txt 具有预定义的插件列表,并且在 plugins 目录中找到的每个插件都将添加到二进制目标中。
另外,设置了一个带有插件名称的预处理器#define:
set (plugins
plugin1
plugin2
plugin3
...)
#optional plugins
foreach(library ${plugins})
file(TO_CMAKE_PATH "plugins/${library}" librarypath)
get_filename_component(librarypath ${librarypath} ABSOLUTE)
if(EXISTS ${librarypath})
message("--> found ${library}")
include_directories(${librarypath}/include)
file(GLOB libsources "${librarypath}/src/*.cpp" "${librarypath}/src/*.f90")
set(sources ${sources} ${libsources})
string(TOUPPER ${library} LIBRARY)
add_definitions(-D${LIBRARY})
endif()
endforeach(library)
现在在我的主库中,我基本上做的事情如下:
#ifdef PLUGIN1
# include "plugin1.h"
#endif
#ifdef PLUGIN2
# include "plugin2.h"
#endif
#ifdef PLUGIN3
# include "plugin3.h"
#endif
...
// each plugin has a unique id:
enum PluginID : int {
Plugin1 = 1,
Plugin2 = 2,
Plugin3 = 3,
};
// the name of each plugin is associated with its ID,
PluginID getPluginIDFromName( const std::string& PluginName )
{
static std::map<std::string, PluginID> PluginIDMap = {
{"PLUGIN1", Plugin1},
{"PLUGIN2", Plugin2},
{"PLUGIN3", Plugin3},
};
return PluginIDMap[PluginName];
}
// Load a plugin by its ID
PluginBaseClass* pluginFactory( PluginID pluginID)
{
switch ( pluginID ) {
#ifdef PLUGIN1
case Plugin1: { return new class Plugin1();}
#endif
#ifdef PLUGIN2
case Plugin2: { return new class Plugin2();}
#endif
#ifdef PLUGIN3
case Plugin3: { return new class Plugin3();}
#endif
}}
所以结果是在主源中我可以通过以下方式加载插件:
PluginBaseClass* thePlugin1 = pluginFactory ( getPluginIDFromName ("PLUGIN1") );
一切都按预期工作,但我觉得我所做的是某种滥用 cmake 和预处理器宏的行为。有没有更好的方法来实现我的目标?
此外,为每个可能的插件手动更新map 和switch 相当麻烦。
我的要求是用户不需要手动修改CMakeLists.txt。提前谢谢!
编辑:我想通过它们的 ID 或名称使插件可用,因此这两个功能。此外,静态链接是首选;我认为没有理由动态加载。
【问题讨论】:
-
将插件系统实现为动态模块。这样你就可以单独构建它们(例如,甚至作为一个完全独立的项目)。
-
谢谢,但我更喜欢静态链接;没有真正需要动态加载。
-
为什么没有动态加载?例如,在 Linux 上,
dlopen是加载插件的规范方式(否则,不要称其为插件,而是软件组件) -
事实是,并非所有“插件”都完全相互独立。一些插件导入或重用其他插件的函数和类。这意味着至少在Windows下必须导出/导入符号等等。