【问题标题】:Writing a plugin system?编写插件系统?
【发布时间】:2014-10-31 07:14:37
【问题描述】:

经过数小时的研究,我一无所获,所以我向各位好心人寻求解决方案。我将用 C++ 编写一个机器人,并且在某个时候想为它制作一个插件系统。现在我知道我可以为它编写一种脚本语言,但是,我知道只编写一个 api 并让程序在运行时动态链接到它是可能的。我的问题是,我如何获得这种动态链接(就像 hexchat 的插件一样)?是否有任何优雅的解决方案,或者至少有关于典型设计的理论?

【问题讨论】:

  • 插件系统没有一个协议。您需要编写一组类工厂/加载器模块并在运行时从动态库加载代码,具体取决于您的应用程序的需求(我不知道 hexchat 是什么以及它如何与插件一起使用)。实际上,您的问题太宽泛而无法回答(但是,请查看 WinAPI LoadLibrary 和 Linux API dlopen 并考虑围绕这些构建一些东西)。投票结束。
  • 既然您标记了 C:请查看 GLibs GModule,然后查看 GTypeModule 以获得具有自动界面加载功能的更复杂的版本。
  • 我不确定是否理解了您的问题。我给出了一些答案。

标签: c++ c linux plugins posix


【解决方案1】:

在 Linux 和 Posix 系统上,您想使用 dlopen(3)dlsym(或一些包装这些函数的库,例如来自 GTK 的 GlibQtPOCO 等...)。更准确地说,

构建一个position independent code 共享库作为您的插件:

 gcc -fPIC -Wall -c plugin1.c -o plugin1.pic.o
 gcc -fPIC -Wall -c plugin2.c -o plugin2.pic.o

请注意,如果插件是用 C++ 编写的,您将使用 g++ 编译它,并且您应该将插件函数声明为 extern "C" 以避免 name mangling

然后将你的插件链接为

 gcc -shared -Wall plugin1.pic.o plugin2.pic.o -o plugin.so

您可以添加动态库(例如,如果您的插件需要 GNU readline,则在上述命令末尾添加 -lreadline)。

最后,在主程序中调用dlopen,并提供完整路径,例如

 void* dlh = dlopen("./plugin.so", RTLD_NOW);
 if (!dlh) { fprintf(stderr, "dlopen failed: %s\n", dlerror()); 
             exit(EXIT_FAILURE); };

(通常dlh 是一个全局数据)

然后使用dlsym 获取函数指针。所以在程序和插件代码中包含的一些头文件中声明他们的签名,比如

 typedef int readerfun_t (FILE*);

声明一些(通常)全局函数指针

 readerfun_t* readplugfun;

并在插件句柄dlh上使用dlsym

 readplugfun = (readerfun_t*) dlsym(dlh, "plugin_reader");
 if (!readplugfun) { fprintf (stderr, "dlsym failed: %s\n", dlerror());
                     exit(EXIT_FAILURE); };

当然在你的插件源代码中(例如plugin1.cc)你会定义

 extern "C" int plugin_reader (FILE*inf) { // etc...

您可以在插件中定义一些构造函数(或析构函数)(参见GCC function attributes);将在dlopen(或dlclose)时间调用。在 C++ 中,您应该简单地使用静态对象。 (它们的构造函数在dlopen 时间调用,它们的析构函数在dlclose 时间调用;因此是函数属性的名称)。

在程序调用结束时

 dlclose(dlh), dlh = NULL;

在实践中,您可以进行很多(可能是一百万)dlopen 调用。

您通常希望将您的主程序与-rdynamic 链接,以使其符号在插件中可见。

gcc -rdynamic prog1.o prog2.o -o yourprog -ldl

阅读Program Library HowTo & C++ dlopen mini HowTo & Drepper's paper: How to Write a Shared Library

最重要的部分是定义和记录一个插件约定(即“协议”),即一组(和 API)函数(将是dlsym-ed)你的插件以及如何使用它们,它们被调用的顺序,内存所有权策略是什么,等等。如果你允许几个类似的插件,你可能在你的主程序中有一些有据可查的钩子,它调用所有的dlsym-相关dlopen-ed 插件的编辑功能。示例:GCC plugins conventionsGNU make modulesGedit plugins、...

【讨论】:

    猜你喜欢
    • 2010-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-31
    • 1970-01-01
    • 2012-01-23
    相关资源
    最近更新 更多