C 中静态链接模块的插件系统?

发布于 2024-12-08 15:17:29 字数 1198 浏览 7 评论 0原文

我需要编写一个与 Linux 上的静态链接模块一起使用的插件系统。 我不希望核心(主函数)显式调用模块的 init 函数。

对于我想要实现的目标,我能想到的最接近的类比是 Linux 内核。 在那里,可能会静态编译和链接未知数量的模块/插件,但这些模块的启动方式与动态加载时的情况相同。

到目前为止,我有这个

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);

,但我不知道如何让核心实际启动已完成的模块模块初始化。

这里有人可以给我指点吗? (没有双关语)

编辑: 我将 core/main.c 更改为

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

,但它没有显示对“适应”的调用,该调用位于提供给链接器的库列表中的第一个。

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

地狱即天堂 2024-12-15 15:17:29

如果您使用的是 GCC,则可以使用 __attribute__((constructor)) 说明符在启动时(在 main 之前)为每个“模块”。 (也适用于 clang 和 ICC。)

例如:(

$ 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

提供的代码仅用于说明目的。)

一旦你有了它,你就可以开始了。让“构造函数”函数执行模块初始化自身所需的任何操作,并“注册”到您的插件框架中。 (带有一堆函数指针的结构,添加到链接列表或类似的东西中就可以了。)

请注意,链接顺序将决定您的插件初始化顺序,这是一个蠕虫病毒 - 如果您的模块相互依赖,那么事情变得非常棘手。确保您的全局变量尽可能少。

更新:

如果您需要使用静态库而不是普通的 .o 文件,则需要一些额外的链接器魔法。

假设上面的内容已经运行:

$ 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

我不完全确定在这种情况下是否可以依赖(反向)链接顺序。

或者:(

$ 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

在这里我不知道你会得到什么建造者订单。)

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

在梵高的星空下 2024-12-15 15:17:29

程序中只有一个入口点,默认情况下是 main。如果我理解正确的话,你的建议是有多个入口点。据我所知,这在标准 C 中是不可能的。

如果您静态加载库(意味着它们被传递到链接器中,无论它们是否包含在生成的可执行文件中),那么您将必须导出它们头文件中的初始值设定项,并在其中的每个文件上显式调用 module_init

如果您要动态加载库(使用 dlfcn.h),那么一旦确定要加载哪些模块以及何时加载它们,就可以按需调用module_init

无论哪种情况,如果您希望运行它,您必须调用 module_init。您可以重构以隐藏它,但在某些时候必须调用它。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文