开发者

Plugin system for statically linked modules in C?

I need to write a plugin system which works with statically linked modules on Linux. I do not want the core (main function) to explicitly call the init function for the module.

The closest analogy which I can think of, for what I want to accomplish, is the Linux kernel. There it is possible to have a unknown number of modules/plugins compiled 开发者_C百科and linked statically, but the modules are initiated as would be if they were loaded dynamically.

I have this

core/main.c:

 int main(void) { return 0; }

core/pluginregistrar.h:

#ifndef PLUGIN_REGISTRAR_H
#define PLUGIN_REGISTRAR_H

#include <stdio.h>

#define module_init(pInitor) \
    static inline funInitor __inittest(void) \
        { fprintf(stdout, "test\n"); return pInitor; }
    int init_module(void) __attribute__((alias(#pInitor)));

typedef void (*funInitor)(void);

#endif

adap1/main.c:

#include "pluginregistrar.h"

void adap1Init(void) { fprintf(stdout, "test1\n"); }

module_init(adap1Init);

adap2/main.c:

#include "pluginregistrar.h"

void adap2Init(void) { fprintf(stdout, "test2\n"); }

module_init(adap2Init);

so far, but I have no idea on how to get the core to actually initiate the modules which have done a module_init.

Can anyone here give me a pointer? (no pun intended)

EDIT: I changed core/main.c to

extern int init_module(void);
int main(void) {
  init_module();
  return 0;
}

and it not shows the call of the "adaptation" which was first in the library list given to the linker.


If you're using GCC, you can use the __attribute__((constructor)) specifier to have one piece of code run at startup (before main) for each of your "modules". (Also works with clang and ICC.)

For example:

$ cat t.c
#include <stdio.h>
#ifdef AAA
static void  __attribute__((constructor)) myinit()
{
    printf("%s\n", AAA);
}
#else
int main()
{
    printf("bye\n");
    return 0;
}
#endif
$ gcc -DAAA=\"hello\" -o  m.o -c t.c 
$ gcc -DAAA=\"there\" -o  n.o -c t.c 
$ gcc -o t.o -c t.c
$ gcc -o foo m.o n.o t.o
$ ./foo
there
hello
bye

(Code provided for illustration purposes only.)

Once you have that, you're pretty much good to go. Have that "constructor" function do whatever the module needs to do to initialize itself, and "register" into your plugin framework. (A structure with a bunch of function pointers, added to a linked list or something like that would work.)

Note that link order will determine your plugin initialization order, and that's a can of worms - if your modules depend on each other, things get really tricky. Make sure you have as few globals as possible.

Update:

If you need to use static libraries rather than plain .o files, you need a bit of extra linker magic.

Assuming the above has already run:

$ ar cru libm.a m.o
$ ar cru libn.a n.o
$ gcc -o foo t.c -Wl,-whole-archive libn.a libm.a -Wl,-no-whole-archive
$ ./foo
hello
there
bye

I'm not entirely certain of whether you can rely on (reverse) link order in this case.

Or:

$ ar cru libmn.a m.o n.o
$ gcc -o foo t.c -Wl,-whole-archive libmn.a -Wl,-no-whole-archive
$ ./foo 
there
hello
bye

(And here I have no idea of what contructor order you'll get.)


There is only one entry point in a program, and by default that is main. What you are suggesting, if I understand it correctly, is to have multiple entry points. As far as I know, that is not possible in standard C.

If you are statically loading the libraries (meaning that they are passed into the linker, regardless of whether they get included in the resulting executable), then you will have to export their initializers in header files, and explicitly call module_init on each one of them.

If you are dynamically loading the libraries (using a mechanism like dlopen/dlsym from dlfcn.h), then you may call module_init on demand once you have determined what modules to load and when to load them.

In either case, you must call module_init if you want it to be run. You can refactor to hide it, but at some point it must be called.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜