RPATH与RUNPATH
Posted LiuYanYGZ
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RPATH与RUNPATH相关的知识,希望对你有一定的参考价值。
RPATH与RUNPATH
原文链接: ckamm - RPATH and RUNPATH
DT_RPATH通常设置在这样一种可执行程序中,它依赖的库无法在默认位置中被找到。举例来说,Qt Creator自带一个Qt库的副本,而且有一个指向库文件所在目录的rpath。当你构建自己的Qt库而不将其安装到全局位置时,这也是很有用的:qmlviewer之类的二进制文件之所以能够工作,是因为它们包含了一个指向了编译时所用Qt库的rpath。
如果这些文件没有设置rpath,在启动它们之前你需要显式地设置LD_LIBRARY_PATH,或写一个替你做这些事情的脚本。由于LD_LIBRARY_PATH是一个环境变量,它也有自身的一些问题。
很不幸的是:在基于glibc的系统中,动态加载器的搜索路径有些混乱。尤其是在RPATH和RUNPATH二者的区别上。这方面的文档非常匮乏: Google给出的第一个结果 是不正确的,可能只是过时了。ld和ld.so的man页面是不完整的,而且dlopen中对 RUNPATH如何起作用的描述是错的 。 Debain Wiki 一开始说得不错,但是和dlopen页面有同样的错误,而且后面有些自相矛盾。
另一个混乱的来源是:根据你的发行版的不同,“ld”的-rpath参数表现出不同的行为。在一些发行版中生成DT_RPATH,而在另外一些发行版中却同时生成DT_RPATH和DT_RUNPATH。
好的,这并不严重,但问题是什么呢?
简单地说:在你的应用程序中设置DT_RUNPATH(或者DT_RUNPATH和DT_RPATH)并不足以保证它链接到你所指定目录中的库。
一个导致问题的具体例子:
- Qt Creator链接到它自带的QtGui
- 它通过dlopen加载了系统提供的KDE插件,该插件(间接)依赖QtDBus
- 如果Qt Creator的二进制程序设置了RPATH而没有RUNPATH:Qt Creator自带QtDBus被加载
- 如果Qt Creator的二进制程序设置了RUNPATH:系统提供的QtDBus被加载且导致Qt Creator终止。
该错误将会类似这样“Cannot mix incompatible Qt library (version 473) with this library (version 474)”[不能将当前库(版本474)与不兼容的Qt库(版本473)混用]。因为即使版本间是二进制兼容的,你也不能混用它们。QtDBus可能会依赖QtCore中已经发生变化或者在4.7.4中新增的私有API。
对于所有的链接到自有QtGui库且运行在带有KDE的系统上的应用程序,都可能发生这种问题。但是该问题也并不局限于KDE:任何使用了先前未加载的Qt库的插件,都可能查找到错误的库。
为什么会这种情况?
实验以及对glibc源码(elf/dl-load.c中的_dl_map_object)阅读表明,库的搜索顺序如下:
除非正被加载的对象(object)拥有RUNPATH: 正被加载对象的RPATH, 然后是其加载者(loader)的RPATH(除非它有RUNPATH),..., 直到搜索链的结束,它要么是可执行程序, 要么是通过dlopen加载的对象 除非可执行程序拥有RUNPATH: 该可执行程序的RPATH LD_LIBRARY_PATH 正被加载对象的RUNPATH ld.so.cache 默认路径
该过程解释了这种行为:我们依赖于插件加载时检查可执行程序的RPATH。可执行程序的RUNPATH并不被用来查找间接依赖的库。
我们该如何做?
当你发布二进制(程序)时,要么使用RPATH且不使用RUNPATH,要么确保LD_LIBRARY_PATH在运行前被设置。当你在“ld”默认是–enable-new-dtags(因此-rpath会添加RUNPATH)的系统中构建Qt时,要明白一点:在启动使用该版本Qt构建的程序时,你可能必须要先设置LD_LIBRARY_PATH。
以上是关于RPATH与RUNPATH的主要内容,如果未能解决你的问题,请参考以下文章
dyld:库未加载:@rpath/XCTest.framework/XCTest 原因:找不到图像