编写插件系统? [英] Writing a plugin system?

查看:204
本文介绍了编写插件系统?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

经过多个小时的研究,我没有什么,所以我转向你好的人希望一个解决方案。我将在c ++中编写一个bot,并且在某个时候想为它制作一个插件系统。现在我知道我可以写一个脚本语言,但是,我知道它可能只是写一个api,并有程序链接到在运行时动态。我的问题是,我如何得到动态链接(像什么hexchat为其插件)?是否有任何优雅的解决方案,或至少是关于典型设计的理论?

解决方案

在Linux和Posix系统上, dlopen(3)& dlsym (或某些包含这些函数的库,例如 Glib < a>来自GTK, Qt POCO 等)。更确切地说,



构建位置无关代码共享库作为插件:

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

注意,如果插件是用C ++编写的,你将使用 g ++ 编译它,你应该声明插件函数为 externC code>,以避免名称错误



然后将您的插件链接为

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



您可以添加动态库(例如 -lreadline 上面的命令结束如果你的插件需要GNU readline)。



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

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

(通常 dlh 全局数据)



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

  typedef int readerfun_t(FILE *); 

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

  readerfun_t * readplugfun; 

并使用 dlsym code> dlh

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

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

  externCint plugin_reader(FILE * inf){// .. 

您可以在插件中定义一些构造函数https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html =nofollow> GCC函数属性);将在 dlopen (或 dlclose )时调用。在C ++中,你应该简单地使用静态对象。 (它们的构造函数在 dlopen 时调用,它们的析构函数在 dlclose 时调用;因此函数属性)。



在程序调用结束时

  dlclose ,dlh = NULL; 

在实践中,你可以做很多(也许百万) dlopen



您通常要将主程序与 -rdynamic 链接

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

阅读程序库HowTo & C ++ dlopen mini HowTo & Drepper的论文:如何编写共享库



最重要的部分是定义和文档一个插件约定(即protocol),这是一个函数的集合在你的插件中需要的 dlsym -ed)以及如何使用它们,它们被调用的顺序,内存所有权策略是什么等。如果允许几个类似的插件,你可能在你的主程序中有一些很好记录的钩子,它调用相关 dlopen 的所有 dlsym ed插件。示例: GCC插件约定 GNU make modules Gedit插件,...


After many hours of research I have turned up nothing, so I turn to you good folks in hopes of a solution. I am going to be writing a bot in c++, and at some point would like to make a plugin system for it. Now I know I could just write a scripting language for it, however, I know its possible to just write an api and have the program link to that dynamically at run time. My question is, how do i get that dynamic linkage (like what hexchat has for its plugins)? Are there any elegant solutions, or at least theories on the typical design?

解决方案

On Linux and Posix systems, you want to use dlopen(3) & dlsym (or some libraries wrapping these functions, e.g. Glib from GTK, Qt, POCO, etc...). More precisely,

Build a position independent code shared library as your plugin:

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

Notice that if the plugin is coded in C++ you'll compile it with g++ and you should declare the plugin functions as extern "C" to avoid name mangling.

Then link your plugin as

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

You may add dynamic libraries (e.g. a -lreadline at end of command above if your plugin wants GNU readline).

At last, call dlopen with a full path in your main program, e.g.

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

(often dlh is a global data)

Then use dlsym to get the function pointers. So declare their signature in some header included both by program and plugin code like

 typedef int readerfun_t (FILE*);

declare some (often) global function pointers

 readerfun_t* readplugfun;

and use dlsym on the plugin handle dlh:

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

Of course in your plugin source code (e.g. in plugin1.cc) you'll define

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

You might define some constructor (or destructor) functions in your plugin (see GCC function attributes); the would be called at dlopen (or dlclose) time. In C++ you should simply use static objects. (their constructor is called at dlopen time, their destructor is called at dlclose time; hence the name of the function attributes).

At the end of your program call

 dlclose(dlh), dlh = NULL;

In practice, you can do a lot (perhaps a million) of dlopen calls.

You generally want to link your main program with -rdynamic to let its symbols be visible from plugins.

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

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

The most important part is to define and document a plugin convention (i.e. "protocol"), that is a set (and API) of functions (to be dlsym-ed) required in your plugin and how to use them, in which order they are called, what is the memory ownership policy, etc. If you allow several similar plugins, you might have some well documented hooks in your main program which calls all the dlsym-ed functions of relevant dlopen-ed plugins. Examples: GCC plugins conventions, GNU make modules, Gedit plugins, ...

这篇关于编写插件系统?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆