【问题标题】:Same object file in different static libraries when linking链接时不同静态库中的相同目标文件
【发布时间】:2020-01-30 03:44:09
【问题描述】:
clang++ ... foo.cpp ... -o dir1/foo.o
clang++ ... foo.cpp ... -o dir2/foo.o
//The only difference beween the above two clang++ command lines
//is the output directory
llvm-ar ... dir1/lib1.a ...  dir1/foo.o ...
llvm-ar ... dir2/lib2.a ...  dir2/foo.o ...
clang++ ... dir1/lib1.a dir2/lib2.a ... -o lib.so

生成 lib.so 时 foo.cpp 中的重复符号会发生什么情况?是否需要任何标志才能不产生符号重复错误?

【问题讨论】:

    标签: c++ clang static-linking


    【解决方案1】:

    链接多个静态库,当同一个对象文件出现在多个提供的库中时,不会导致任何重复符号错误(默认情况下)。

    这是因为链接器不会将静态库“组合”成最终的可执行文件。它仅将提供的目标文件组合到可执行文件中。链接器从左到右处理目标文件和存档库的列表。当遇到静态库时,链接器会检查库提供的任何目标文件是否定义了当前未定义的符号。然后,并且只有这样,才会拉入该目标文件。

    在你的例子中:

    clang++ ... dir1/lib1.a dir2/lib2.a ... -o lib.so
    

    考虑另外两个目标文件:

    clang++ obj1.o dir1/lib1.a dir2/lib2.a obj2.o -o lib.so
    

    如果obj1.o 引用了foo.cpp 中存在的符号:

    1. 链接器将处理 obj1.o 并将其添加到 lib.so,注意所述符号未定义。
    2. 链接器将打开dir1/lib1.a 并检查存档中包含的任何目标文件是否定义了所述符号。因为foo.o 定义了符号,所以foo.o 将被添加到lib.so 并且符号将被标记为已定义。
    3. 链接器将打开dir2/lib2.a。但目前没有未定义的符号,因此重复的目标文件将被忽略。
    4. 链接器将处理并将obj2.o 添加到lib.so。链接器确实返回并重新处理 lib1.alib2.a

    因此不应引发重复符号错误(默认情况下,在 Linux 上)。要更改此行为,您可以使用链接器选项--whole-archive

    clang++ ... -Wl,--whole-archive dir1/lib1.a dir2/lib2.a -Wl,--no-whole-archive ... -o lib.so
    

    使用--whole-archive,来自指定存档库的所有目标文件都将添加到输出中。然后,上述命令会导致 foo.cpp 中的任何符号出现“多重定义”错误。

    这个答案描述了 Linux 上的行为,我相信 AIX 是不同的,并且总是将所有遇到的目标文件(来自静态库)添加到输出中。

    【讨论】:

    • 那么如果 "clang++ obj1.o dir1/lib1.a obj2.o dir2/lib2.a -o lib.so" 并且 obj1 和 obj2 都引用 foo.o ,那么就会有重复的符号foo.o 中的全局符号错误,对吗?还是链接器会只使用之前添加的 foo.o 中的符号,而不会查看第二个 foo.o?
    • 用来认为链接器只是从 .a 中选择方法然后将其放入结果中。如果链接器将 .a 中的整个 .o 添加到结果中,则最好在每个源文件中使用尽可能少的代码来设计静态库。
    • 如果“obj1 和 obj2 都引用 foo.o”,仍然不会有重复的符号。处理 obj2 时,不需要再次查找,因为所有引用的符号都被视为已解析。 (链接器正在构建一个已知符号表)。
    • “如果链接器将 .a 中的整个 .o 添加到结果中,则静态库最好用尽可能少的代码来设计” - 从技术上讲,链接器会拉入部分而不是整个对象文件。默认情况下,.text 部分包含所有函数,但您可以在编译库时使用“-ffunction-sections”将它们拆分以避免浪费空间
    猜你喜欢
    • 1970-01-01
    • 2021-10-22
    • 1970-01-01
    • 2017-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多