C++ 的链接问题

作者: , 共 1411 字 , 共阅读 0

C++的链接分为两部分,一个是编译时,一个是运行时。但运行时的行为也收到编译参数的影响。

1. 编译时链接

基本就两个参数,-l-L

  • -l 编译时要链接的库(包括动态链接库.so和静态链接库.a),注意库的顺序,被依赖的放在后面。
  • -L查询链接库的位置,编译器将依次查找。(/usr/lib之类的系统位置不用写)。

一个例子:

g++ ... -l folly -l boost_system -L /opt/lib

2. 运行时链接

编译时,静态链接库.a文件将直接被合并,因此运行时链接只涉及动态链接库.so文件。

执行ldd your_file可以查看指定文件运行时所需要链接的文件以及是否链接到指定位置。如果出现Not found或者链接到不正确位置,需要考察以下两个设置对象。

2.1. 系统环境变量LD_LIBRARY_PATH

链接程序首先考虑系统的环境变量LD_LIBRARY_PATH,从这里面设置的目录列表依次查找所需要的库文件。

下面命令可以查看当前设置的(用:隔开的)目录列表:

echo $LD_LIBRARY_PATH

下面命令可以设置该列表:

export LD_LIBRARY_PATH=~/lib:$LD_LIBRARY_PATH

注意将自己的目录放在最前面,多个目录用:隔开,并且包含原有的$LD_LIBRARY_PATH,以免破坏其它程序的设置。

该命令设置只会对当前窗口有效,新开窗口需要重新设置。如果需要总是有效,可考虑下面方法:

  • 如果想对所有用户生效,可放在/etc/environment文件里(需 ROOT 权限)。
  • 如果想对当前用户生效,可放在~/.bashrc或者~/.zshrc等启动配置文件。

2.2. 程序内置参数RUNPATH

如果链接程序在系统环境变量LD_LIBRARY_PATH找不到指令的库,此时会参考程序内置参数RUNPATH。下面命令可以查看该设置:

readelf -d your_file | grep RUNPATH

这个参数的设置在编译环节,即常见的-Wl,rpath

g++ ... -Wl,rpath=dir1 -Wl,rpath=dir2

2.3. 程序内置参数DT_RPATH

内置参数DT_RPATH是很老的-Wl,rpath行为,现在已经改成了RUNPATHDT_RPATH的区别在于它的优先级还在系统设置LD_LIBRARY_PATH之前。下面命令可查看该设置

readelf -d your_file | grep DT_RPATH

设置方法为-Wl,rpath配上-Wl,disable-new-dtags选项:

g++ ... -Wl,rpath=dir1 -Wl,rpath=dir2 -Wl,disable-new-tags

2.4. 还是找不到库?

有时候,通过上面方法设置了合适的路径和参数,查看路径和参数也都正常,但还是提示找不到,比如报「libboost_thread.so.xxx.xxx.xxx: cannot open shared object file: No such file or directory」错误。

我碰到的一次,解决方法是执行:

sudo ldconfig /opt/lib/ 

其中/opt/lib换成你的 boost 的安装路径。本质是通过ldconfig刷新缓存。

Q. E. D.

类似文章:
编程 »
一个典型的 GCC C++编译过程为:
编程 » C++, GCC, 编译链接
LD 在链接生成目标文件时,会从左到有扫描输入的依赖库,当依赖库之间也有依赖关系时,必须将「依赖别人的库」放在「被别人依赖的库」的前面。否则会链接失败!失败的症状有:
相似度: 0.146
boost是除std外最常用的 C++库,覆盖很多常用操作。目前最新的版本是1.59.0
相似度: 0.102
编程 » Python
Python 在搜索模块时,依次搜索sys.path里的位置,直到找到模块为止。下面命令可以查看当前的搜索路径:
相似度: 0.096
armadillo是一个线性代数 C++库,封装了blaslapack,提供更直观的接口。
编程 » C++, assert, 异常处理
1)在函数开始处检验传入参数的合法性
编程 » C++
要在C++中运行系统命令,可以直接使用std::system函数:
std::thread是 C++ 11 新引入的标准线程库。在同样是 C++ 11 新引入的 lambda 函数的辅助下,std::thread用起来特别方便:
编程 » Matlab
第一步,which函数可用来获取 Matlab 函数的全路径(包含路径和文件名)。
编程 » C++, assert, 异常处理
1)在函数开始处检验传入参数的合法性
编程 »
一个典型的 GCC C++编译过程为: