11

我有一个在 Windows 上使用 MSVC 创建的静态库 *.lib。库的大小是 70KB。然后我有一个链接这个库的应用程序。但现在最终可执行文件 (*.exe) 的大小为 29KB,小于库。我想知道的是:

  1. 由于库是静态链接的,我在想它应该直接添加到可执行文件大小,最终的 exe 大小应该比这更多吗?windows exe格式是否也会对二进制数据进行一些压缩?

  2. linux 系统的情况如何,即 linux 上的库大小(*.a/*.la 文件)与 linux 可执行文件(*.out)的大小有什么关系?

-广告

4

7 回答 7

15

Windows 和 Unix 上的静态库都是 .obj/.o 文件的集合。链接器查看这些目标文件中的每一个并确定程序是否需要链接。如果不需要,那么目标文件将不会包含在最终的可执行文件中。这可能导致可执行文件比库小。

编辑:正如 MSalters 指出的,在 Windows 上,VC++ 编译器现在支持生成启用函数级链接的目标文件,例如,请参见此处。事实上,edit-and-continue 需要这样做,因为edit-and-continue 需要能够替换可执行文件的最小可能部分。

于 2008-12-16T05:58:03.180 回答
6

.lib最终可执行文件不需要的文件中有额外的簿记信息。此信息有助于链接器找到实际链接的代码。此外,调试信息可能存储在.lib文件中,但不存储在.exe文件中(我不记得在 lib 文件中为 objs 存储调试信息的位置,它可能在其他地方)。

于 2008-12-16T07:00:14.003 回答
5

静态库可能包含几个从未使用过的函数。当链接器将库与主可执行文件链接时,它发现某些函数从未使用过(并且它们的地址从未被获取并存储在函数指针中),它只是丢弃了代码。它也可以递归地执行此操作:如果从未调用函数 A(),并且 A() 调用 B(),但从未调用 B(),则它可以删除 A() 和 B() 的代码。在 Linux 上,同样的事情也会发生。

于 2008-12-16T05:56:15.647 回答
1

静态库必须包含在其源代码中定义的每个符号,因为它可能会链接到只需要该特定符号的可执行文件中。但是一旦它被链接到一个可执行文件中,我们就确切地知道哪些符号最终被使用,哪些没有。因此,链接器可以轻松删除未使用的代码,从而大大减少文件大小。同样,任何重复的符号(在静态库和它链接到的可执行文件中定义的任何东西都会合并到一个实例中。

于 2008-12-16T10:16:26.353 回答
0

免责声明:自从我处理静态链接以来已经有很长时间了,所以对我的回答持保留态度。

你写道:我在想它应该直接添加到可执行文件大小,最终的 exe 大小应该不止这些?

朴素的链接器正是以这种方式工作的——当我为 CP/M 系统进行业余开发时(很久以前),这是一个真正的问题。

然而,现代链接器更智能——它们只链接原始代码引用的函数,或者根据需要链接。

于 2008-12-16T06:10:20.360 回答
0

除了当前的答案之外,如果函数定义具有相同的目标代码,则允许链接器删除它们 - 这旨在帮助减少模板化代码的膨胀效应。

于 2008-12-16T06:56:57.990 回答
0

@All:感谢您的指点。@Greg Hewgill - 你的回答是一个很好的指针。谢谢。

我发现的答案如下:

1.)在库构建过程中,如果 MSVC(或类似的东西)中的“保持程序调试数据库”选项为 ON,则库将具有此调试信息,使其大小膨胀。但是当我静态包含该库并创建可执行文件时,链接器会在生成 exe 之前从库中删除所有调试信息,因此 exe 的大小小于库的大小。

2.) 当我禁用“保留程序调试数据库”选项时,我得到了一个大小小于最终可执行文件的库,这在大多数情况下我认为是正常的。

-广告

于 2008-12-17T12:18:20.163 回答