Static libraries 库和可执行文件的大小

Static libraries 库和可执行文件的大小,static-libraries,static-linking,Static Libraries,Static Linking,我有一个在windows上使用MSVC创建的静态库*.lib。图书馆的大小是70KB。然后我有一个链接这个库的应用程序。但现在,最终可执行文件(*.exe)的大小为29KB,比库小。我想知道的是: 因为库是静态链接的,所以我认为它应该直接添加到可执行文件的大小,并且最终的可执行文件大小应该超过这个值?windows exe格式是否也对二进制数据进行压缩 linux系统的情况如何,即linux(*.a/*.la文件)上库的大小如何与linux可执行文件(*.out)的大小相关 -AD静态库可能包含

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

  • 因为库是静态链接的,所以我认为它应该直接添加到可执行文件的大小,并且最终的可执行文件大小应该超过这个值?windows exe格式是否也对二进制数据进行压缩

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


  • -AD

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

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


    编辑:正如MSalters指出的,在Windows上,VC++编译器现在支持生成启用函数级链接的对象文件,例如,请参阅。事实上,“编辑并继续”需要这样做,因为“编辑并继续”需要能够替换可执行文件中尽可能小的部分。

    免责声明:我已经很久没有处理静态链接了,所以对我的回答持保留态度

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

    天真的链接器就是这样工作的——早在我为CP/M系统开发爱好的时候(很久以前),这是一个真正的问题


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

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

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

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

    @All:谢谢您的指针。 @格雷格·休吉尔-你的回答很好,谢谢

    我得到的答案如下:

    1.)在构建库的过程中,如果MSVC中的“Keep Program debug Database”(保留程序调试数据库)选项处于启用状态(或类似选项),则库中的调试信息将增大其大小。 但是,当我静态地包含该库并创建一个可执行文件时,链接器会在升级exe之前从库中删除所有调试信息,因此exe的大小小于库的大小

    2.)当我禁用“Keep Program debug Database”选项时,我得到了一个库,它的大小小于最终可执行文件,这在大多数情况下是正常的


    -AD

    实际上不仅仅是引用的函数,而是它们加上相同的*.o文件中的任何符号(即,.o文件是链接的粒度)。你说得对,这是一个我同时忘记的细节。这几乎就像软件考古学!实际上不仅仅是引用的函数,而是它们加上相同*.o文件中的任何符号(即,整个对象被抛出到最终输出中,而不仅仅是函数),因此如果A和B与C在同一个.o中,并且C被调用,那么它们都会在那里。不一定,我可以假设GCC工具链中的GNU链接器是其中一个更智能的吗?(你确实说过“在Linux上”,这强烈暗示了GCC工具链。)文件级链接实际上是一个UNIX问题;对于MSVC来说,规范已经成为功能级链接。我认为这不是很正确:我想你是在考虑C++。删除重复项应该基于函数的签名(例如,名称和参数类型),而不是基于目标代码。如果你有两个代码不同但签名相同的函数,会发生什么…??不,实际上我想的是目标代码。如果生成的目标代码与另一个相同,则链接器可以删除一个函数。您可以在调试器中看到这一点,例如,您可以看到优化代码的堆栈跟踪,这些优化代码具有与预期不同的功能