C和C++静态链接:只是一个副本?

Geo*_*rge 12 c c++ linker static-linking

当某人静态链接.lib时,链接器会将lib的全部内容复制到最终的可执行文件中,还是只复制目标文件中使用的函数?

Dig*_*oss 18

  • 整个图书馆? - 没有.
  • 只是你叫的功能? - 没有.
  • 别的什么? - 是的

它肯定不会投入整个图书馆.

但它不一定只包括" 目标文件中使用的函数 ".

链接器将生成一个递归构建的列表,其中库中的哪些对象模块满足未定义的符号.

然后,它将包括每个对象模块.

通常,给定的对象模块将包含多个函数,如果其中一些函数未被您调用的函数调用,则将获得一些您不需要的函数(和数据对象).

  • +1这个答案是最正确的,并突出了库作者经常陷入的陷阱,使静态链接导致大量文件大小. (4认同)
  • @托马斯。我不同意。虽然可以设计一种可以省略各个功能的对象格式,但当今所有常见操作系统上的所有流行对象格式都源自 COFF 和 ELF。在这些格式中,无法从任何一个模块中的文本或数据中删除任何内容,因为您不知道每个引用的位置,只能调整模块间引用。我从未见过链接器抛出整个库,这肯定是需要修复的首要错误。 (2认同)

J T*_*J T 5

链接器通常不会在构建最终可执行文件之前删除死代码。也就是说,它会(通常)链接所有符号,无论它们是否在最终可执行文件中使用。但是,链接器通常会明确提供优化设置,您可以使用它来强制链接器更加努力地执行此操作。

对于 GCC,这分两个阶段完成:

  1. 首先编译数据,但告诉编译器将代码分成翻译单元内的单独部分。这将通过使用以下两个编译器标志为函数、类和外部变量完成:

    -fdata-sections -ffunction-sections

  2. 使用链接器优化标志将翻译单元链接在一起(这会导致链接器丢弃未引用的部分):

    -Wl,--gc-sections

因此,如果您有一个名为 test.cpp 的文件,其中声明了两个函数,但其​​中一个未使用,您可以使用以下 gcc(g++) 命令省略未使用的一个:

gcc -Os -fdata-sections -ffunction-sections test.cpp -o test.o -Wl,--gc-sections
Run Code Online (Sandbox Code Playgroud)

(注意 -Os 是一个额外的编译器标志,它告诉 GCC 优化大小)

对于 MSVC,函数级链接完成同样的事情。我相信编译器标志是(将事情分成几部分):

/Gy
Run Code Online (Sandbox Code Playgroud)

然后是链接器标志(丢弃未使用的部分):

/OPT:REF
Run Code Online (Sandbox Code Playgroud)