我已经读过gcc编译器在编译引用静态库的应用程序时可以执行某些优化 - 例如 - 它将仅从应用程序所依赖的静态库中“拉”出该代码。如果应用程序没有使用静态库的某些部分,这有助于将应用程序可执行文件的大小保持在最小。
1)这是真的吗?
2)GCC如何知道应用程序实际使用的静态库中的代码?它只查看应用程序中包含的(直接和间接)头文件,然后相应地提取代码吗?或者它实际上是在查看静态库中的哪些方法被调用?
答案 0 :(得分:2)
静态库只是一包目标文件。链接器(ld)将跟踪使用哪些目标文件(即包含从某处引用的函数),并且不包括最终可执行映像中的未引用代码。
答案 1 :(得分:1)
gcc
没有做任何事。您描述的所有内容都是关联,由ld
处理。
ld检查目标文件的符号表,以确定需要链接的符号,然后从库中提取相关的目标文件并将它们链接到可执行文件中。
答案 2 :(得分:1)
答案
1)是的,只会引入引用的代码。除了较小的大小外,链接速度也会增加,因为静态库包含库导出的所有符号的索引表。在这个表中查找更快,而不是逐个查找目标文件
或者,如果您想要引入静态库中的所有符号而不考虑引用。您可以将--whole-archive开关传递给ld。
2)在ld(gnu链接器)的上下文中提出这个问题会更正确,因为这实际上是引用了引用。 GCC在完成编译之后只调用链接器(除非你执行gcc -c,这会导致它在编译后停止)。
因此,在编译完成后,将使用对象(.o)文件和库的有序列表调用ld。 ld逐个处理.o文件,并为每个链接器处理
a)记下此文件所需的无法解析的外部符号。将这些添加到(比如说)未解析的表中。
b)查看此文件导出的符号(函数,全局变量),并解析它可以执行的任何先前的引用。
这是一个非常简化的链接过程概述。
现在当链接器进入静态库时,它基本上做同样的事情,这次使用静态库来解析符号。但是有一个区别,链接器只接入未解析的符号及其依赖项。所以假设我们有
a.o和libstatic.a又包含b.o和c.o.
b.o定义bar()和moreBar();
c.o定义了baz()和moreBaz();
a.o定义foo();
其中foo调用调用baz的bar。现在当你这样做
gcc -o app a.o libstatic.a
在处理完a.o后,链接器知道它需要解析bar,这会从静态库中解析出来,但是在解析bar时链接器会注意到bar需要baz。这再次从libstatic.a解决。 moreBar()和moreBaz()没有引用而被忽略。