如何解决为什么使用共享库时对象和库的顺序不影响链接?
-
foo.h
void foo();
-
foo.cpp
#include "foo.h" #include <iostream> void foo(){ std::cout << "This is foo" << std::endl; }
-
main.cpp
:#include "foo.h" int main(){ foo(); return 0; }
然后我运行以下命令来生成 foo.cpp 的静态和共享版本:
g++ -c -fPIC foo.cpp
ar rvs libfoo.a foo.o
g++ -shared -o libfoo.so foo.o
g++ -c main.cpp
如果我尝试使用静态 libfoo.a
和 main.o
生成可执行文件,则目标文件和库文件的顺序很重要:
g++ main.o libfoo.a -o main # works
g++ libfoo.a main.o -o main # fails with undefined references to `foo()`
如this post中所述,顺序很重要。
但是,如果我尝试使用共享的 libfoo.so
和 main.o
构建可执行文件,则目标文件和库文件的顺序不再重要:
g++ main.o libfoo.so -o main # works
g++ libfoo.so main.o -o main # also works without errors
这是否意味着当我们链接目标文件和共享库时顺序并不重要?或者这只是一个特例或一些我不知道的巧合?
以上代码和命令在以下平台上测试:
- Linux:CentOS 7.4
- gcc:7.3.1 或 4.8.5(均已测试)
解决方法
如本文所述,顺序很重要。
更详细的解释是here。
顺序对于传统 UNIX 链接器很重要,但最近 LLD 决定打破传统,记录归档库中符号的可用性,即使它们没有立即被引用。
目前在 Linux 上可以使用三种不同的链接器:原始 BFD 链接器、Gold 链接器(大约 2008 年)和 LLD(大约 2019 年)。
使用“正确”的顺序可以成功(自然地)所有三个。
使用“错误”的顺序:g++ libfoo.a main.o
使用 BFD 和 Gold 失败,但使用 LLD 成功:
g++ libfoo.a main.o -fuse-ld=lld && echo $?
0
但是,如果我尝试使用共享的 libfoo.so 和 main.o 构建可执行文件,则目标文件和库文件的顺序不再重要
无关紧要的原因是链接器对待 .so
的方式与对待 .o
的方式类似。特别是,没有必要“拉出部分”.so
——你会得到整个.so
(就像你使用{{1}时会1 })
因此,当您链接 foo.o
时,此链接几乎等同于使用 g++ libfoo.so main.o
,并且前一个命令中的顺序无关紧要,原因与它无关在后一个命令中无关紧要。
1使用 g++ foo.o main.o
构建并使用 -ffunction-sections
。
因为在第二种情况下不需要强符号名称解析。在 ELF 解释期间(即在您运行程序时)查找和解析共享对象中的符号。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。