RPATH与RUNPATH

时间 2011-11-01 21:46:44 Qt Labs China
主题 Qt

原文链接: ckammRPATH 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的更多相关文章

  1. rpath 与runpath

  2. linux动态库加载RPATH, RUNPATH

    摘自http://gotowqj.iteye.com/blog/1926771 linux动态库加载RPATH, RUNPATH 链接动态库 如何程序在连接时使用了共享库,就必须在运行的时候能够找到共 ...

  3. 探讨CMake中关于RPATH的使用

    最近研究CMake,发现CMake对于RPATH的管理也非常人性化.官方说法是当动态库的编译也和执行档在同级目录下的时候,CMake会自动给执行档加入适当的RPATH.具体可以通过readelf -d ...

  4. linux动态库加载的秘密

    摘自http://gotowqj.iteye.com/blog/1926734 摘自http://www.360doc.com/content/14/0313/13/12747488_36024641 ...

  5. 高级C/C++编译技术之读书笔记(四)之定位库文件

    最近有幸阅读了<高级C/C++编译技术>深受启发,该书深入浅出地讲解了构建过程(编译.链接)中的各种细节,从多个角度展示了程序与库文件或代码的集成方法,提出了面向代码复用和系统集成的软件架 ...

  6. 通过一道简单的例题了解Linux内核PWN

    写在前面 这篇文章目的在于简单介绍内核PWN题,揭开内核的神秘面纱.背后的知识点包含Linux驱动和内核源码,学习路线非常陡峭.也就是说,会一道Linux内核PWN需要非常多的铺垫知识,如果要学习可以 ...

  7. MacOS平台下@rpath在动态链接库中的应用

    一.背景介绍 公司开发的一个底层库被用在了Mac平台的多个产品中.在开发这个底层库的初期,对于Mac OSX下的Install name 并没有过多的了解.对于XCode中的install name项 ...

  8. @rpath/libswiftCore.dylib问题

    dyld: Library not loaded: @rpath/libswiftCore.dylib  Referenced from: /private/var/containers/Bundle ...

  9. Objective-C @executable_path、@loader_path和@rpath

    工程配置中,有三个路径和库的加载息息相关: 1.@executable_path 可执行文件的路径,例如/Applications/WeChat.app/Contents/MacOS. 2.@load ...

随机推荐

  1. JAVA I/O流 之入门

    I/O流分类: 根据处理的数据类型不同 字节流 字符流 根据流向不同 输入流 输出流 根据功能不同 节点流:直接与数据源相连,读入或读出. 处理流:直接使用节点流,读写不方便,为了更快的读写文件,才有 ...

  2. Unity 飞机的子弹轨迹

    最近公司在开发一款儿童打飞机游戏.  策划跟我说能在子弹上加上一些轨迹就好了.  比如 旋转 左右移动呀.然后它就很愉快的跑去截其他游戏的图啦... 我看见图的时候, 解决方案: 1.   使用牛逼的 ...

  3. JavaScript 轮播图

    这是我自己做的一个轮播图,大家可以看看 ,我还没进行优化.有改进的地方可以私聊 布局什么的你们自己搞定吧 <div class="slider" id="circl ...

  4. [转]Traceroute网络排障实用指南(1)

    注:本文是同事的大作,虽是翻译的一篇英文PPT,但内容实在精彩,小小的Traceroute竟包含如此大的信息量,真是让人感慨!内容不涉及公司机密,所以一直想转到自己的Blog上来,自己需要时可以再翻阅 ...

  5. char与byte的差别

    非常多刚開始学习的人(包含我,已经学了一年多java了)肯会对char和byte这两种数据类型有所疑惑,相互混淆,今天特地查了好多资料,对byte和char两种数据类型进行了总结和比較,先将结果与大家 ...

  6. 【巧妙预处理系列+离散化处理】【uva1382】Distant Galaxy

    给出平面上的n个点,找一个矩形,使得边界上包含尽量多的点. [输入格式] 输入的第一行为数据组数T.每组数据的第一行为整数n(1≤n≤100):以下n行每行两个整数,即各个点的坐标(坐标均为绝对值不超 ...

  7. 【set&&sstream||floyed判环算法】【UVa 11549】Calculator Conundrum

    CALCULATOR CONUNDRUM Alice got a hold of an old calculator that can display n digits. She was bored ...

  8. 利用iptables将本地的80端口请求转发到8080,当前主机ip为192.168.1.1,命令怎么写?

    iptables -t nat -A PREROUTING -d 192.168.1.1 -p tcp --dport 80 -j REDIRECT --to-port 8080 内网上外网: ipt ...

  9. SQLServer游标详解

    一.游标概念 我们知道,关系数据库所有的关系运算其实是集合与集合的运算,它的输入是集合输出同样是集合,有时需要对结果集逐行进行处理,这时就需要用到游标.我们对游标的使用一本遵循“五步法”:声明游标—& ...

  10. 单链表(Single Linked List)

    链表的结点结构  ┌───┬───┐  │data|next│  └───┴───┘ data域--存放结点值的数据域 next域--存放结点的直接后继的地址(位置)的指针域(链域) 实例:从终端输入 ...