C静态库是如何工作的?

How does a C static library work?

使用库时,最终的可执行文件中包含哪些代码?


例如,我们有两个文件:

/*main.c*/
int main (int argc, char* argv[]){
    fc(1); /*This function is defined in fc.c*/
}

另一个文件:

/*fc.c*/
int fc(int x){
    return fe(x);
}
int fe(int y){
    return y + 1;
}

我们编译fc.c:

gcc -c fc.c

然后我们得到fc.o.

现在让我们构建一个名为 test 的库:

ar rcs libtest.a fc.o

我们现在有 libtest.a.

现在编译main.c

gcc -c main.c

然后我们得到main.o

让我们link我们的main.o到我们的libtest.a

gcc -L. main.o -ltest

我们得到了想要的a.out

检查它的符号:

nm a.out

在所有符号之间,我们发现:

080483cc T fc
080483df T fe

看起来不错。 但是!

如果我们的main.c为此改变?

/*main.c*/
int main (int argc, char* argv[]){
    fe(1); /*This function is defined in fc.c*/
}

编译 main.c 并将新的 main.o link 编译到我们的库后,我仍然会找到 fc 的符号。但我不需要那个代码。

问题

-库"give me"不应该只有我在main.c中需要的代码吗?
- 在添加到库之前,函数是否需要在单独的模块中?
-如果我有 300 个函数怎么办?我需要制作 300 个模块吗?

是的,将每个函数放在一个单独的模块中。这样,linker 将 link 只在需要的项目中。

简而言之,有编译器标志可以从最终的可执行代码中删除未使用的函数,但默认情况下不启用。

如果添加这些标志,GCC 可以执行此 "garbage collection" 未使用的函数:

  1. -ffunction-sections 作为 compile-time 标志。它指示编译器为每个函数创建一个单独的 部分 (请参阅 object file format)。还有 -fdata-sections 具有类似含义的标志,适用于变量。

  2. -Wl,--gc-sections 作为 link-time 标志。 -Wl 部分指示 GCC 将以下选项传递给链接器。 --gc-sections 表示 "garbage select sections from which all code is unsed"。由于 compile-time 选项每个函数都有一个单独的部分,它有效地执行 function-level 修剪。