【发布时间】:2011-01-26 11:15:43
【问题描述】:
我希望在我们当前的应用程序(Unix、C++)中实现一个插件架构,并且一直在审查 Boost 库中的选项(待批准)。
编辑:我希望在运行时动态添加类。
Boost.Plugin
Boost.Reflection
Boost.Extension
我想知道大家对这些和其他实现的经验/意见是什么。
【问题讨论】:
-
您针对未说明的问题发布了建议的解决方案。您有什么要求?
我希望在我们当前的应用程序(Unix、C++)中实现一个插件架构,并且一直在审查 Boost 库中的选项(待批准)。
编辑:我希望在运行时动态添加类。
Boost.Plugin
Boost.Reflection
Boost.Extension
我想知道大家对这些和其他实现的经验/意见是什么。
【问题讨论】:
嗯。我们刚刚使用了dlopen 和dlsym 以及一对必须在dll 中定义的extern "C" static 函数
extern "C" static plugin* create( arg_pack* );
extern "C" static errno_t destroy( plugin* );
让插件管理器查找“.dll”或“.so”文件并将它们加载到map<string, pair< plugin*(*)(arg_pack*), errno_t(*)(plugin*)> >
然后您可以根据名称(上面的字符串)查找插件并获取它的“构造函数”或“析构函数”
另请参阅:gmodule
【讨论】:
extern "C" 保证 c 风格的修改。 API -> dlsym 从库中加载所有相关函数。如果缺少任何内容,则它不是插件,您需要丢弃函数指针和 dlclose 库。
map< string, pair< type_info, boost::any> > 之类的东西,让被调用者检查这个映射的所有参数。当然,被调用者可能恶意获取 0 个或 2 个或更多参数。我想您可以指定 cdecl 约定,以便调用者(您的代码)清理堆栈。我没有看到通过插入内联 asm 来防止被调用者对堆栈进行攻击的方法。
您不能在运行时加载类,因为 C++ 是一种编译语言,并且类在运行时不存在。对象(类的实例)可以。
您可以做的是在运行时加载共享库并让它们创建某个接口的对象。
最小的插件实现将定义插件的接口以及将使用该接口创建对象的工厂函数的接口。您将在运行时加载共享库,找到具有特定名称的工厂函数,并调用工厂函数来创建对象。然后通过接口使用该对象:
// plugin.h start
#include <memory>
struct PlugIn // interface
{
virtual ~PlugIn() = 0;
virtual void doSomething() = 0;
};
extern "C" {
typedef std::auto_ptr<PlugIn> PlugInFactoryFn();
// A plugin .so must export this one factory function.
std::auto_ptr<PlugIn> createPlugIn();
}
// plugin.h end
// somewhere in you application
#include "plugin.h"
#include <assert.h>
#include <dlfcn.h>
std::auto_ptr<PlugIn> loadPlugIn(char const* filename)
{
void* so = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
assert(so);
void* factory_function = dlsym(so, "createPlugIn");
assert(factory_function);
return reinterpret_cast<PlugInFactoryFn*>(factory_function)();
}
int main()
{
std::auto_ptr<PlugIn> a(loadPlugIn("a.so"));
std::auto_ptr<PlugIn> b(loadPlugIn("b.so"));
a->doSomething();
b->doSomething();
}
【讨论】: