Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
523 views
in Technique[技术] by (71.8m points)

c++ - Writing a plugin system?

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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
", 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
", 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, ...


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...