Writing a plugin system?

后端 未结 1 1669
花落未央
花落未央 2020-12-12 02:14

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 lik

相关标签:
1条回答
  • 2020-12-12 02:33

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

    0 讨论(0)
提交回复
热议问题