背景
最近遇到一个问题,就是驱动的析构函数未执行。将整个代码可以简化为如下形式。
+ testlib.c
#include <stdio.h>
__attribute__((constructor)) void print_hello()
{
printf("hello world!\n");
}
+ main.c
#include <stdio.h>
int main()
{
return 0;
}
编译脚本
#!/bin/sh
gcc -c testlib.c
ar -rsv testlib.a testlib.o
gcc -o main main.c testlib.a
执行./main,没有输出。
原因分析
当把静态库链接到可执行程序时,链接器默认情况下只会提取所需的目标文件(或符号)来满足程序的需求。这意味着,如果静态库中的某个目标文件没有被引用到,那么该目标文件不会被包含在最终的可执行程序中。最终析构函数未被执行。
解决方法
通过编译参数 -Wl,--whole-archive
导入静态库所有符号表解决。
调整后的编译脚本
#!/bin/sh
gcc -c testlib.c
ar -rsv testlib.a testlib.o
gcc -o main main.c -Wl,--whole-archive testlib.a -Wl,--no-whole-archive
这里介绍一下这2个编译参数的作用,它们是GCC编译器的一个选项,用于控制链接器对静态库的处理方式。一般的用法是 -Wl,–whole-archive 和 -Wl,–no-whole-archive。
链接静态库的时候,默认情况下,链接器只会提取所需的目标文件(或符号)来满足程序的需求。这意味着,如果静态库中的某个目标文件没有被引用到,那么该目标文件不会被包含在最终的可执行程序中。
然而,有时候我们希望强制链接器将整个静态库包含在最终的可执行程序中,而不管其中的目标文件是否被引用。这时可以使用 --whole-archive 选项来实现。
不过,–whole-archive 选项的作用范围是全局的,它会将所有的静态库都包含进最终的可执行程序中,而不管是否被引用。这可能会导致最终的可执行程序变得庞大,包含了不必要的目标文件。
为了解决这个问题,可以使用 --no-whole-archive 选项。–no-whole-archive 选项告诉链接器停止将整个静态库包含在最终的可执行程序中。这样,链接器只会提取所需的目标文件来满足程序的需求。
综上所述,
–whole-archive 强制链接器将整个静态库文件符合包含在最终的可执行程序中,缺点会导致可执行文件变大。
–no-whole-archive 只包含所需的目标文件包含在最终的可执行程序中。
附
参考链接:
https://stackoverflow.com/questions/1202494/why-doesnt-attribute-constructor-work-in-a-static-library