cmake rpath, rpath-link, RUNPATH

Posted by Leo on September 24, 2023

一、Abstract

  • LD_LIBRARY_PATH & rpath & runpath 我们复制了目标程序所需的动态链接库,但是我们如何确定程序启动时,真的能够顺利找到这些动态链接库呢?

    在 Linux 中,主要有三个因素可以决定特定可执行文件的动态链接库的搜索路径:环境变量 LD_LIBRARY_PATH 、rpath 和 runpath。

    绝大部分动态链接库会从环境变量 LD_LIBRARY_PATH 中查找加载。要指定运行 python3 时这些库的查找路径,可以这样做:

    LD_LIBRARY_PATH=/new/path:$LD_LIBRARY_PATH /usr/bin/python3 这样在复制 Python 3 时,连带复制所需的动态运行库至单独的目录,然后重新指定 LD_LIBRARY_PATH 即可。

    rpath 和 runpath 是 ELF 文件的可选内容。如果一个 ELF 文件含有 rpath ,那么系统会优先在 rpath 所指向的路径搜索,然后再搜索 LD_LIBRARY_PATH ;而 runpath 则是在 LD_LIBRARY_PATH 之后搜索。

    这样看来 runpath 对我们没有什么帮助,LD_LIBRARY_PATH 可以帮助我们引导系统搜索动态链接库的路径。而 rpath,因为是内嵌在 ELF 当中的,一旦程序中有这个内容会影响我们使用 LD_LIBRARY_PATH 的效果。

  • 概念

    -L 用于链接时指定显示链接的库的搜索路径(优先级高) -rpath 用于在链接时指定直接或间接链接的库搜索路径(最高优先级),并且(写入二进制文件中RPATH)指定运行时的本二进制文件的直接或间接依赖的动态加载库搜索路径(最高优先级)。注:有些系统默认开启链接选项-enable-new-dtags,导致-rpath生成RUNPATH。通过指定链接选项-disable-new-dtags来使其生成RPATH。 -rpath-link 用于在链接时指定直接或间接链接的库搜索路径(优先级高)。 LD_LIBRARY_PATH 在运行时搜索直接或间接依赖。优先级低于RPATH为第二优先级 RUNPATH写入在二进制文件中,用于指定运行时本二进制文件的直接依赖动态加载库搜索路径(优先级低于LD_LIBRARY_PATH)。存在时覆盖二进制文件中RPATH。

  • 工具:

    ldd -s lib_path LD_DEBUG=libs lib_path readelf -d lib_path cmake 设置rpath指令 chrpath -r [new_rpath] [lib_name] 注:只能改路径比原来短的. patchelf –set-rpath [new_rpath] [lib_name] 注:没有限制路径长度,但是修改的是RUNPATH

    还有就是回到开头的案例上,解决方法大概有:

    将lib中的库文件装到目标机器的lib,/usr/lib,/usr/local/lib. 将lib装到目标机器任意位置,通过添加目标机器lib的路径到LD_LIBRARY_PATH或到ld.so.confg来运行时加载. 要么在目标机器中额外运行脚本进行rpath修改.要么cmake写好install_rpath通过安装到源码机器来修改rpath,然后拷贝给目标用户.

Refence

一文搞懂动态链接库的各种路径的意义与设置 理解 Linux 动态链接库依赖