我知道所有编译文件(翻译单元)都会被编译为目标文件,然后链接器会通过查看这些目标文件来解析编译器在编译阶段找不到的符号。但这也是链接到静态库时发生的情况。那么链接到预编译的静态库和链接到目标文件有什么区别呢?我有一个大约 300k 行的 c 文件(sqlite),我想知道是否应该将其编译为静态库,而不是仅将 c 文件作为编译单元传递给编译器。我知道在这两种情况下,编译器直到链接阶段才会“看到”该文件中的代码。我想有一次我在试验这些东西时看到最终二进制大小的差异,但我不记得我是否正确设置了优化设置(即函数级链接 -ffunction-sections -fdata-sections)。

9

  • 3
    库只是对象文件的集合。库用于许多不同应用程序将要使用的功能,因此您不必为每个应用程序复制它们。


    – 

  • 3
    库只是对象文件的集合。优点:一次编译即可在多个项目中使用。缺点:需要确保所有库和应用程序之间的编译选项兼容。


    – 


  • 1
    库还允许动态链接。因此,库代码不必复制到可执行文件中。动态链接通常使用共享内存,因此使用相同库的所有进程都共享到目标文件的相同内存映射。


    – 

  • 1
    答案和往常一样,视情况而定。使用静态库可以节省编译时间,但(理论上)对于每个项目配置,您都需要创建一个单独的静态库。您还会错过在链接期间完成的完整程序优化,因为编译器看不到代码。最后,(理论上)对于每个新的编译器版本,您都需要重新编译库。因此,除非编译时间至关重要,否则我只会将所有源代码与可执行文件一起编译,而且编译器知道何时重新编译 obj 文件,并且除非必要,否则不会这样做。


    – 


  • 1
    对我来说,有一个重要的区别:将目标文件传递给链接器命令行通常会强制将对象链接到二进制文件中,而静态库(实际上只是一个档案)内的对象只有存在依赖关系时才会被链接。


    – 


最佳答案
1

链接到预编译静态库与链接到目标文件之间有什么区别。

假设其他所有条件都相同,则链接独立目标文件获得的结果与链接从静态库中提取的相同目标文件获得的结果之间没有任何区别。

静态库的主要用途是

  • 避免不必要的重新编译
  • 将相关的目标文件打包到更易于重用的单元中

当然,第一种也可以通过保留构建的目标文件来实现。如果我们谈论的是只在单个项目中使用的东西,那么保留目标文件就更简单了,而且不需要考虑重用。

在某些构建系统中,静态库可能具有组织优势,但这是一个相当特殊的情况,如果它与您相关,您就会认识到这一点。

4

  • LTO 的行为是否相同(或者在最后一段中介绍过)?


    – 


  • 我希望如此,@EugeneSh.,但很难找到确认。


    – 

  • 使用库而不是对象文件的一个优点是,对象文件将无条件链接,但库中的同一文件仅在使用代码时才会链接。大多数情况下,这没有什么区别——您将使用对象文件中的代码。但如果代码可能被有条件地使用,那么库可能会更好。


    – 

  • 同意,@JonathanLeffler,这与这个答案并不冲突。另外,尽管这是一个普遍的考虑因素,但我不认为这是这个问题的原始作者所关心的问题,他似乎正在决定是否将他们知道需要链接的目标文件放入库中。


    –