本文为原创文章,转载注明出处,欢迎关注网站https://hkvision.cn

缘由

最近在弄Linux上的程序,然后由于涉及到要调用mkl的包(armadillo中用mkl+openblas要快很多),而mkl安装的时候库是不会进入/usr/lib这样的系统路径下的,然后引发了一些问题。

链接

稍微对程序的加载等方面熟悉一点的童鞋会知道,C++分为编译链接和运行两个部分,对于g++这样的编译器来说,需要链接器知道要加载的动态链接库(共享对象)的位置,对于一个二进制文件来说,在运行的时候也需要知道动态链接库的位置,这就涉及到两个链接,一个是编译时链接,一个是运行时链接。

在g++中,这两个链接是由两个参数来控制的,一个是-L,一个是-Wl,-rpath,由于之前弄明白链接的过程之后使用了这两个参数,程序没有出问题。但是这次我发现即使配置了这两个参数仍然有问题,上网查了一下,又深入了一点点。

rpath和runpath

这涉及到另外一个小知识,大家应该知道Linux中的可执行文件是elf格式的文件,这种文件以段来进行区域划分,在可执行文件的elf中,就存在一个section,名字叫做rpath,这里面存储了执行这个文件的时候搜索库的位置,因此在加载可执行文件的时候就会在这个位置搜索库。

本来这一切好好的,但是存在另外一种段,名字叫做runpath,乍一眼看这个应该行使和rpath类似的功能,但是不是的,具体的一些内容大家可以参考这个文章RPATH与RUNPATH - LiuYanYGZ - 博客园 (cnblogs.com),估计是机器翻译的。其实runpath就是一个控制搜索逻辑的一个段,并不是会在这个路径下面搜索(可能我的理解也不太对,毕竟文章写的太抽象了)。

g++的神奇操作

本来我不应该纠结这两个段的区别的,但是,新版本的g++(9.3.0),glibc版本2.31,在指定-Wl,-rpath的时候,默认只会增加上runpath,而没有rpath。这就导致这个参数失效了。于是出现了诡异的一幕,明明指定了运行时链接的路径但是还是提示没有找到库。

罪魁祸首就是一个新的链接器参数,叫做--enable-new-dtags,man手册里面说这个默认关着的,但是实际上我使用的时候发现这玩意是开着的,设置了这个参数就会导致只有runpath而没有rpath,因此如果想要回到原来的状态,就得手动关掉这个参数--disable-new-dtags,这样编译出来的文件就会只有rpath而没有runpath,之后就又能愉快的玩耍了