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 and linked statically, but the modules are initiated as would be if they were loaded dynamically.
I have this
int main(void) { return 0; }
#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
#include "pluginregistrar.h"
void adap1Init(void) { fprintf(stdout, "test1\n"); }
module_init(adap1Init);
#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.
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.)