2010-05-05 198 views
0

我读过gcc编译器在编译引用静态库的应用程序时可以执行某些优化,例如 - 它只会从静态中“拉”代码应用程序依赖的库。如果应用程序未使用静态库的某些部分,这有助于将应用程序的可执行文件的大小降至最低。GCC如何编译引用静态库的应用程序

1)这是真的吗?

2)GCC如何知道应用程序实际使用的静态库中的代码?它是否只查看包含(直接和间接)应用程序中的头文件,然后相应地提取代码?或者它真的在查看静态库中的哪些方法被调用?

回答

2

静态库只是一大堆目标文件。链接器(ld)将跟踪使用哪些目标文件(即包含从某处引用的函数),并且不包括最终可执行映像中的未引用代码。

1

gcc没有做任何事情。你所描述的一切是链接,这是由ld处理。

ld检查目标文件的符号表以确定哪些符号需要链接,然后从库中提取相关目标文件并将它们链接到可执行文件中。

1

答案
1)是的,只有引用的代码才会被引入。除了较小的尺寸外,由于静态库包含库导出的所有符号的索引表,因此链接速度也有所增加。在这个表中查找更快,而不是逐个查找目标文件。
或者,如果您想要引用静态库中的所有符号,无论引用如何。您可以将--whole-archive开关传递给ld。

2)在ld(gnu链接器)的上下文中提出这个问题会更正确,因为这实际上是引用了引用。 GCC在完成编译后调用链接器(除非你做了gcc -c,这会导致它在编译后停止)。 因此,编译完成后,ld会使用对象(.o)文件和库的有序列表调用。 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后,链接器知道它需要解析条形图,这会从静态库中解析出来,然而在解析条形时,链接器会注意到条形图需要baz。这再次从libstatic.a解析。 moreBar()和moreBaz()没有引用并被忽略。