链接时不同静态库中的相同目标文件
Same object file in different static libraries when linking
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 的重复符号会怎样?是否需要任何标志才能不产生符号重复错误?
链接多个静态库,当同一目标文件出现在多个提供的库中时,不会导致任何重复符号错误(默认情况下)。
这是因为链接器没有"combine the static libraries"进入最终的可执行文件。它仅将提供的 目标文件 组合到可执行文件中。链接器从左到右处理目标文件和归档库的列表。当遇到静态库时,链接器会检查库提供的任何目标文件是否定义了当前未定义的符号。然后,只有那时,才会拉入该目标文件。
在你的例子中:
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
中的符号:
- 链接器将处理并将
obj1.o
添加到 lib.so
,注意所述符号未定义。
- 链接器将打开
dir1/lib1.a
并检查存档中包含的任何目标文件是否定义了所述符号。因为 foo.o
定义了符号,所以 foo.o
将添加到 lib.so
并且符号将被标记为已定义。
- 链接器将打开
dir2/lib2.a
。但是当前没有未定义的符号,因此将忽略重复的目标文件。
- 链接器将处理并将
obj2.o
添加到 lib.so
。链接器不会返回并重新处理lib1.a
或lib2.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
.
中的任何符号,上述命令会导致 "multiple definition" 错误
这个答案描述了 Linux 上的行为,我相信 AIX 是不同的,它总是将所有遇到的目标文件(来自静态库)添加到输出中。
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 的重复符号会怎样?是否需要任何标志才能不产生符号重复错误?
链接多个静态库,当同一目标文件出现在多个提供的库中时,不会导致任何重复符号错误(默认情况下)。
这是因为链接器没有"combine the static libraries"进入最终的可执行文件。它仅将提供的 目标文件 组合到可执行文件中。链接器从左到右处理目标文件和归档库的列表。当遇到静态库时,链接器会检查库提供的任何目标文件是否定义了当前未定义的符号。然后,只有那时,才会拉入该目标文件。
在你的例子中:
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
中的符号:
- 链接器将处理并将
obj1.o
添加到lib.so
,注意所述符号未定义。 - 链接器将打开
dir1/lib1.a
并检查存档中包含的任何目标文件是否定义了所述符号。因为foo.o
定义了符号,所以foo.o
将添加到lib.so
并且符号将被标记为已定义。 - 链接器将打开
dir2/lib2.a
。但是当前没有未定义的符号,因此将忽略重复的目标文件。 - 链接器将处理并将
obj2.o
添加到lib.so
。链接器不会返回并重新处理lib1.a
或lib2.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 是不同的,它总是将所有遇到的目标文件(来自静态库)添加到输出中。