Jay*_*rod 27 c attributes constructor static-libraries
在以下示例中,程序应打印"foo called":
// foo.c
#include <stdio.h>
__attribute__((constructor)) void foo()
{
printf("foo called\n");
}
// main.c
int main()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果程序是这样编译的,它可以工作:
gcc -o test main.c foo.c
Run Code Online (Sandbox Code Playgroud)
但是,如果将foo.c编译为静态库,则程序不会打印任何内容.
gcc -c main.c
gcc -c foo.c
as rcs foo.a foo.o
gcc -o test foo.a main.o
Run Code Online (Sandbox Code Playgroud)
为什么会这样?
Jay*_*rod 14
链接器在最终程序中不包含foo.a中的代码,因为main.o中的任何内容都没有引用它.如果main.c重写如下,该程序将工作:
//main.c
void foo();
int main()
{
void (*f)() = foo;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
此外,在使用静态库进行编译时,gcc(或链接器)的参数顺序非常重要:库必须位于引用它的对象之后.
gcc -o test main.o foo.a
Run Code Online (Sandbox Code Playgroud)
如前所述,归档中未引用的符号不会使其成为输出二进制文件,因为链接器默认会丢弃它们。
要在与静态库链接时覆盖此行为,可以使用链接器的--whole-archive/ --no-whole-archive选项,如下所示:
gcc -c main.c
gcc -c foo.c
ar rcs foo.a foo.o
gcc -o test -Wl,--whole-archive foo.a -Wl,--no-whole-archive main.o
Run Code Online (Sandbox Code Playgroud)
这可能会导致二进制文件膨胀,因为foo.a链接器会将所有来自的符号都包含到输出中,但是有时这是合理的。