为什么 GNU ld 在链接可执行文件和共享对象时以不同的方式解析符号
Why does GNU ld resolve symbols differently when linking executables vs shared objects?
我有一段琐碎的C++代码,看起来像这样:
#include <boost/timer/timer.hpp>
int main(void) {
boost::timer::auto_cpu_timer t;
return 0;
}
我尝试编译并链接它(使用 gcc 4.8.1 和 GNU ld 2.23.52.20130828(,如下所示:
$ g++ -o test test.cc -lboost_timer
/usr/bin/ld: /tmp/cc2jP1jv.o: undefined reference to symbol '_ZN5boost6system15system_categoryEv'
/usr/lib/libboost_system.so.1.54.0: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
一种解决方案是在命令行上明确提及-lboost_system
,这行得通。但是,我也可以这样做:
$ g++ -Wl,--copy-dt-needed-entries -o test test.cc -lboost_timer
根据 ld 文档"命令行上提到的 --copy-dt-need-entries 动态库将被递归搜索,跟随它们的DT_NEEDED标签到其他库,以便解析输出二进制文件所需的符号",所以这一切都是有道理的:ld 从boost_timer中发现它还需要链接到boost_system以解析所有符号。
但是,我意识到这也有效:
$ g++ -fPIC -shared -o test test.cc -lboost_timer
显然,我现在已经生成了一个共享对象而不是可执行文件。显然,ld 能够弄清楚它需要将共享对象与boost_system链接:
$ ldd test | grep boost_system
libboost_system.so.1.54.0 => /usr/lib/libboost_system.so.1.54.0 (0x00007f385246e000)
所以我的问题是:为什么在构建共享对象和可执行文件时符号解析不同?ld 如何在没有我指定--copy-dt-needed-entries
的情况下确定我的共享对象应该与boost_system链接?
我认为,我的问题的直接答案是在 ld 的--[no-]allow-shlib-undefined
选项中。从手册页:
默认行为是报告任何未定义符号的错误 在共享库中引用(如果链接器用于创建( 可执行文件,但如果链接器用于创建 共享库。
因此,当我使用 -shared
构建时,boost_system 中的符号是未定义的,但 ld 的默认行为是不关心。可以告诉它关心:
$ g++ -fPIC -shared -Wl,--no-allow-shlib-undefined -o test test.cc -lboost_timer
/usr/bin/ld: /tmp/cc6j1de3.o: undefined reference to symbol '_ZN5boost6system15system_categoryEv'
/usr/lib/libboost_system.so.1.54.0: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
同样,我们可以告诉它在构建可执行文件时不要关心:
$ g++ -Wl,--allow-shlib-undefined -o test test.cc -lboost_timer
/tmp/ccUHoCIU.o: In function `__static_initialization_and_destruction_0(int, int)':
test.cc:(.text+0x7a): undefined reference to `boost::system::generic_category()'
test.cc:(.text+0x86): undefined reference to `boost::system::generic_category()'
test.cc:(.text+0x92): undefined reference to `boost::system::system_category()'
collect2: error: ld returned 1 exit status
但是创建二进制文件失败,无法定义这些符号。
谢谢@CharlesBailey为我指出正确的方向!
collect2 命令中可能存在相关的差异。在 https://i.stack.imgur.com/VrfGw.jpg 中比较不同的命令。右边创建共享库(-fPic -shared(,左边是普通编译。
- 如何在c++中为模板函数实例创建快捷方式
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 将无符号char*转换为std::istream*C++
- 如何在C++中将一个无符号的 int 转换为两个无符号的短裤?
- vscode g++链路故障:体系结构x86_64的未定义符号
- 在c代码之间共享数据的最佳方式
- 在线程中读取无符号整数时,c++ 位是否以原子方式切换?
- 将 3D 矢量浮点打包到无符号 int 中并将其解压缩
- 如何以优雅高效的方式将无符号/有符号整数/长整型转换为 C 字符串?
- 矩阵类编写构造函数,解构器和复制构造函数的方式
- 消除有符号和无符号整数表达式之间比较的优雅方式
- GCC 以错误的方式解包(我<...)折叠表达式
- 如何以最佳方式将高分辨率图像数据存储在无符号字符*中C++
- 将无符号int地址视为指针,并将其解引用为字节数组
- 为什么 GNU ld 在链接可执行文件和共享对象时以不同的方式解析符号
- 如何将无符号的 int 放入 char 数组并将其解压缩回来
- 以编程方式下载Windows符号
- 为什么 C 编译器不能以直观的方式进行有符号/无符号比较
- 我可以将数据分配给从OpenCV对象解引用中检索的双函数返回以任何方式