通俗理解-L、-rpath和-rpath-link编译链接动态库

embedded/2025/2/22 5:50:04/

一、参考资料

链接选项 rpath 的应用和原理 | BewareMyPower的博客

使用 rpath 和 rpath-link 确保 samba-util 库正确链接-CSDN博客

编译参数-Wl和rpath的理解_-wl,-rpath-CSDN博客

Using LD, the GNU linker - Options

Directory Options (Using the GNU Compiler Collection (GCC))

交叉编译时–sysroot,-rpath,-rpath-link,-L之间的关系与注意点_交叉编译 sysroot-CSDN博客

二、相关介绍

Linux__16">Linux 动态库查找路径

一个典型的 C/C++ 程序的构建流程是:预处理,汇编,编译,链接。而执行链接的程序其实是 ld,通常编译器比如 GCC 都会自动调用 ld 去进行链接,用户不必关注其中的细节。而 ld 查找动态库的顺序是:

  1. rpath 指定的目录;
  2. 环境变量 LD_LIBRARY_PATH 指定的目录;
  3. runpath 指定的目录;
  4. /etc/ld.so.cache 缓存文件,通常包含 /etc/ld.so.conf 文件编译出的二进制俩别哦(比如 CentOS 上,该文件会使用 include 从而使用 ld.so.conf.d 目录下面所有的 *.conf 文件,这些都会缓存在 ld.so.cache 中)
  5. 系统默认路径,比如 /lib/usr/lib

在编译时若使用 -z nodefaultlib 选项编译,则会跳过 4 和 5。至于 runpath,和 rpath 类似,都是二进制(ELF)文件的动态 section 属性(分别为 DT_RUNPATHDT_RPATH),唯一区别就是是否优先于 LD_LIBRARY_PATH 来查找。

rpath vs. runpathrpathrunpath 是嵌入在可执行文件或共享库中的路径列表,用于指定运行时查找共享库的位置。rpath 是旧标准,runpath 是新标准,功能类似但优先级不同。

-Wl参数

gcc的-Wl,xxx选项将逗号分隔的标记列表(flags)作为空格分隔的参数列表传递给链接器,即:

gcc -Wl,aaa,bbb,ccc

最终变成了linker的用法:

ld aaa bbb ccc

如果是想把ld -rpath通过-Wl传递给gcc,可以是-Wl,-rpath,xxx,也可以指定-Wl的重复实例:

gcc -Wl,aaa -Wl,bbb -Wl,ccc

类似的参数还有:

-Wa,<options>   Pass comma-separated <options> on to the assembler
-Wp,<options>   Pass comma-separated <options> on to the preprocessor
-Wl,<options>   Pass comma-separated <options> on to the linker 

--sysroot 选项

--sysroot = dir 将dir作为逻辑root目录,用于搜索头文件和依赖库文件,例如 --sysroot=/home/build,那么如果之前默认去 /usr/lib下面去搜索依赖库,则在sysroot的作用下会定位到 /home/build/usr/lib 目录下进行搜索。这个参数在交叉编译的时候会影响到rpath,如果没有设置这个sysroot,则rpath在编译阶段是不起作用的。

在交叉编译工具中,有默认的 sysroot 路径。

# 设置交叉编译工具链的环境变量
export PATH=/home/yoyo/360Downloads/toolchains/arm-linux-gnueabihf/bin:$PATH# 查看交叉编译工具链的 sysroot 路径
arm-linux-gnueabihf-gcc -print-sysroot

输出示例:

yoyo@yoyo:~$ arm-linux-gnueabihf-gcc -print-sysroot
/home/yoyo/360Downloads/toolchains/arm-linux-gnueabihf/bin/../arm-linux-gnueabihf/libc

$ORIGIN 变量

关于Linux上的$ORIGIN解说

关于Linux上的$ORIGIN解说

许多现代C / C ++项目都利用 Autotools 创建GNU构建系统,例如根据平台生成make文件。 可执行文件(二进制文件)在生成/编译过程中生成,并且可以在执行编译的计算机上本地执行。 但是,如果将同一可执行文件移动到另一台计算机上,或者只是移到同一台计算机上的其他文件夹,则在运行该可执行文件时可能会遇到“找不到库”错误。因此,引入一个特殊的环境变量 $ORIGIN

Linux系统中,$ORIGIN 是一个特殊的环境变量,表示可执行文件或共享库所在的目录。使用 $ORIGIN 可以指定相对于可执行文件或共享库的路径,确保程序在不同目录中运行时能正确找到依赖库。

使用 $ORIGIN 的好处在于,它允许可移植性更高的应用程序部署,因为这意味着应用程序和它的依赖库可以被放置在文件系统中的任意位置,并且在运行时动态链接器仍然能正确找到它们,只要维持相对结构不变即可。

简单示例:假设有一个可执行文件 /app/bin/myprogram,依赖库在 /app/lib 中。可以在编译时设置 RPATHRUNPATH$ORIGIN/../lib,这样程序运行时会在 /app/lib 中查找依赖库。

/app/myprogram.cbin/applib/libdependency.so

在链接 app 时,可以使用:

gcc -Wl,-rpath,'$ORIGIN/../x264/lib' -Wl,rpath,'$ORIGIN/../x265/lib' -o app myprogram.c
-Wl,-rpath,'$ORIGIN'

如果需要设置多个路径,可以将它们用空格分隔,并确保每个路径前都有 -Wl,-rpath,

-Wl,-rpath,'$ORIGIN/../third_party/arm_opencv/3rdparty/zlib/lib' \
-Wl,-rpath,'$ORIGIN/../third_party/arm_opencv/3rdparty/szlib/lib'

这样,不管 /usr/appdir/ 复制到文件系统的哪个地方,执行 app 时,libdependency.so 都会从执行文件所在目录下的 lib 目录中被找到和加载。

在处理诸如需要将应用打包到一个单一文件夹以实现便携式部署的情况下,$ORIGIN 变量异常有用。使用 $ORIGIN ,开发者便无需担心程序部署后动态链接库的路径问题,从而大大提高了软件的移植性和灵活性。

注意事项

  • $ORIGIN 必须用引号括起来,防止被 shell 解释。
  • 使用 $ORIGIN 时,确保路径设置正确,避免运行时找不到库。
  • Makefile 或其他文件中直接使用时,只用一个 $ 会展开成变量值,通常需要写作 $$ORIGIN来避免变量扩展。

三、-L、-rpath-link和-rpath

通过使用 rpathrpath-link,可以确保程序在运行时正确找到依赖的库。这对于处理不在系统默认路径下的库非常有用。在编译和链接时正确使用这两个选项可以确保你的程序在不同环境中都能正常运行。

引言

现代连接器在处理动态库时将链接时路径(Link-time path)运行时路径(Run-time path) 分开,用户可以通过 -L指定连接时库的路径,通过-R(或-rpath)指定程序运行时库的路径,大大提高了库应用的灵活性。

-rpath-rpath-link之间的区别:-rpath选项指定的目录被包含在可执行文件中并在运行时使用,而-rpath-link选项仅在链接时有效。

通过测试发现,-Wl,-rpath下面这三种写法都是可以的:

-Wl,-rpath -Wl,/usr/lib/gstreamer-1.0
-Wl,-rpath,/usr/lib/gstreamer-1.0
-Wl,-rpath=/usr/lib/gstreamer-1.0

-l 选项

功能:添加需要链接的库文件,如果没有后缀指明动态库还是静态库,则优先使用动态库

-L选项(编译时路径)

功能:-L 指定的是编译时链接动态库搜索路径。

编译时-L选项并不影响环境变量 LD_LIBRARY_PATH,只是指定了程序编译连接时库的路径,并不影响程序执行时库的路径。当程序运行时,系统还是会到默认路径下查找该程序所需要的库,如果找不到,会出现类似 cannot open shared object file 的错误。

-L/mylib -lmylib

-Wl,-rpath选项(运行时路径)

功能:-Wl,-rpath 用于指定动态库的搜索路径(在运行阶段),该路径会被记录在elf可执行文件中。

-rpath 的作用相当于在程序运行时设置了 LD_LIBRARY_PATH 环境变量,因为 -rpath指定的路径会被记录在生成的可执行程序中,用于运行时查找需要加载的动态库 。因此,在开发板中无需设置环境变量即可找到相关的动态库。通常情况下,推荐使用 -Wl,-rpath 选项。

# 单个路径
-L/mylib -lmylib -Wl,-rpath=dir# 多个路径
-L/mylib -lmylib -Wl,-rpath,dir1:dir2:...:dirN

在cmake中使用:

# 设置第三方库路径
set(3RDPARTY_DIR "${PARENT_DIR}/third_party")# 设置目标属性,将运行时库搜索路径添加到目标
set_target_properties(dla_detectPROPERTIESLINK_FLAGS"-L${3RDPARTY_DIR}/zlib/lib -Wl,-rpath,'$ORIGIN/../../third_party/zlib/lib' \-L${3RDPARTY_DIR}/szlib/lib -Wl,-rpath,'$ORIGIN/../../third_party/szlib/lib' \-L${3RDPARTY_DIR}/hdf5/lib -Wl,-rpath,'$ORIGIN/../../third_party/hdf5/lib' \-L${3RDPARTY_DIR}/x264/lib -Wl,-rpath,'$ORIGIN/../../third_party/x264/lib' \-L${3RDPARTY_DIR}/x265/lib -Wl,-rpath,'$ORIGIN/../../third_party/x265/lib' \-L${3RDPARTY_DIR}/ffmpeg/lib -Wl,-rpath,'$ORIGIN/../../third_party/ffmpeg/lib' \-L${3RDPARTY_DIR}/sigmastar/lib -Wl,-rpath,'$ORIGIN}/../../third_party/sigmastar/lib' \-L${3RDPARTY_DIR}/arm_opencv/lib -Wl,-rpath,'$ORIGIN/../../third_party/arm_opencv/lib' \-L${PARENT_DIR}/build -Wl,-rpath,'$ORIGIN/../../build'"
)

或者:

# 设置第三方库路径
set(3RDPARTY_DIR "${PARENT_DIR}/third_party")# 设置rpath
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} \
-L${3RDPARTY_DIR}/zlib/lib -Wl,-rpath,'$ORIGIN/../../third_party/zlib/lib' \
-L${3RDPARTY_DIR}/szlib/lib -Wl,-rpath,'$ORIGIN/../../third_party/szlib/lib' \
-L${3RDPARTY_DIR}/hdf5/lib -Wl,-rpath,'$ORIGIN/../../third_party/hdf5/lib' \
-L${3RDPARTY_DIR}/x264/lib -Wl,-rpath,'$ORIGIN/../../third_party/x264/lib' \
-L${3RDPARTY_DIR}/x265/lib -Wl,-rpath,'$ORIGIN/../../third_party/x265/lib' \
-L${3RDPARTY_DIR}/ffmpeg/lib -Wl,-rpath,'$ORIGIN/../../third_party/ffmpeg/lib' \
-L${3RDPARTY_DIR}/sigmastar/lib -Wl,-rpath,'$ORIGIN/../../third_party/sigmastar/lib' \
-L${3RDPARTY_DIR}/arm_opencv/lib -Wl,-rpath,'$ORIGIN/../../third_party/arm_opencv/lib' \
-L${PARENT_DIR}/build -lsigmastar_vVehicle_det -Wl,-rpath,'$ORIGIN/../../build'")

编译之后,查看rpath:

yoyo@yoyo:~/share/driver/dla_detect$ readelf -d test/build/dla_detect
...
0x0000000f (RPATH)                      Library rpath: [$ORIGIN/../../third_party/zlib/lib:$ORIGIN/../../third_party/szlib/lib:$ORIGIN/../../third_party/hdf5/lib:$ORIGIN/../../third_party/x264/lib:$ORIGIN/../../third_party/x265/lib:$ORIGIN/../../third_party/ffmpeg/lib:$ORIGIN/../../third_party/sigmastar/lib:$ORIGIN/../../third_party/arm_opencv/lib:$ORIGIN/../../build:/home/yoyo/share/driver/dla_detect/third_party/arm_opencv/share/opencv4/../../lib]
...

-Wl,-rpath-link选项(运行时路径)

功能:-Wl,-rpath-link 用于指定动态库的搜索路径(在链接阶段),该选项只在链接阶段起作用,不会被写入elf文件中。

-L/mylib -lmylib -Wl,-rpath-link=<library_path>

在cmake中使用:

# 设置第三方库路径
set(3RDPARTY_DIR "${PARENT_DIR}/third_party")# 设置目标属性,将运行时库搜索路径添加到目标
set_target_properties(dla_detectPROPERTIESLINK_FLAGS"-L${3RDPARTY_DIR}/zlib/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/zlib/lib' \-L${3RDPARTY_DIR}/szlib/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/szlib/lib' \-L${3RDPARTY_DIR}/hdf5/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/hdf5/lib' \-L${3RDPARTY_DIR}/x264/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/x264/lib' \-L${3RDPARTY_DIR}/x265/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/x265/lib' \-L${3RDPARTY_DIR}/ffmpeg/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/ffmpeg/lib' \-L${3RDPARTY_DIR}/sigmastar/lib -Wl,-rpath-link,'$ORIGIN}/../../third_party/sigmastar/lib' \-L${3RDPARTY_DIR}/arm_opencv/lib -Wl,-rpath,'$ORIGIN/../../third_party/arm_opencv/lib' \-L${PARENT_DIR}/build -Wl,-rpath-link,'$ORIGIN/../../build'"
)

或者:

# 设置第三方库路径
set(3RDPARTY_DIR "${PARENT_DIR}/third_party")# 设置rpath
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} \
-L${3RDPARTY_DIR}/zlib/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/zlib/lib' \
-L${3RDPARTY_DIR}/szlib/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/szlib/lib' \
-L${3RDPARTY_DIR}/hdf5/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/hdf5/lib' \
-L${3RDPARTY_DIR}/x264/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/x264/lib' \
-L${3RDPARTY_DIR}/x265/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/x265/lib' \
-L${3RDPARTY_DIR}/ffmpeg/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/ffmpeg/lib' \
-L${3RDPARTY_DIR}/sigmastar/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/sigmastar/lib' \
-L${3RDPARTY_DIR}/arm_opencv/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/arm_opencv/lib' \
-L${PARENT_DIR}/build -lsigmastar_vVehicle_det -Wl,-rpath-link,'$ORIGIN/../../build'")

编译之后,查看二进制的 rpath

yoyo@yoyo:~/share/driver/dla_detect$ readelf -d test/build/dla_detect
...
0x0000000f (RPATH)                      Library rpath: [/home/yoyo/share/driver/dla_detect/third_party/arm_opencv/share/opencv4/../../lib]
...

查看 rpath

objdump -x path/to/executable | grep RPATH
readelf -d path/to/executable | head -20
chrpath -l path/to/executable

http://www.ppmy.cn/embedded/162365.html

相关文章

【Java】 String 类中常用方法的详细说明

目录 1.char charAt(int index) 2. int length() 3. boolean isEmpty() 4. boolean equals(Object anObject) 5. boolean equalsIgnoreCase(String anotherString) 6. boolean contains(CharSequence s) 7. boolean startsWith(String prefix) 8. boolean endsWith(Str…

自学网络安全(黑客技术)2024年 —100天学习计划

&#x1f91f; 基于入门网络安全/黑客打造的&#xff1a;&#x1f449;黑客&网络安全入门&进阶学习资源包 前言 什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、…

STM32HAL库快速入门教程——常用外设学习(2)

目录 一、STM32HAL库开发&#xff08;8&#xff09;——CubeMX配置DMA 1.1、什么是DMA&#xff1f; 1.2、内存内存之间的传输&#xff08;单次&#xff09; ​编辑 1.3、内存外设之间的传输&#xff08;ADC&#xff09; 二、STM32HAL库开发&#xff08;9&#xff09;——…

Vue的简单入门 一

声明&#xff1a;本版块根据B站学习&#xff0c;创建的是vue3项目&#xff0c;用的是vue2语法风格&#xff0c;仅供初学者学习。 目录 一、Vue项目的创建 1.已安装15.0或更高版本的Node.js 2.创建项目 二、 简单认识目录结构 三、模块语法中的指令 1.v-html 1.文本插值…

【C++】C++ 旅馆管理系统(含 源码+报告)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;专__注&#x1f448;&#xff1a;专注主流机器人、人工智能等相关领域的开发、测试技术。 系列文章目录 目录 系列文章目录一、设计要求二、设…

P1226 【模板】快速幂

P1226 【模板】快速幂 题目描述 给你三个整数 a , b , p a,b,p a,b,p&#xff0c;求 a b m o d p a^b \bmod p abmodp。 输入格式 输入只有一行三个整数&#xff0c;分别代表 a , b , p a,b,p a,b,p。 输出格式 输出一行一个字符串 a^b mod ps&#xff0c;其中 a , b…

MacOS使用PhpWebStudy搭建PHP开发环境

mac上的PHP开发环境搭建方式有很多, brew, docker, mamp等, 这里使用最近新出的工具PhpWebStudy来搭建mac上的php开发环境 安装 使用brew安装 brew install phpwebstudy 无法使用brew的话, 可以去官网下载最新版本安装 FlyEnv | Powerful Web Server and Environment Mana…

Windows 11 卸载 Edge

前言 咋说呢&#xff0c;Edge 确实有它好的一面&#xff0c;自带微软翻译速度可观&#xff0c;确实是 Chrome 自带翻译不可用现状下的首选 &#xff08;李玲玲你好啊&#xff09;&#xff0c;但是深度绑定微软生态&#xff0c;而且还挺重&#xff0c;使我最终放弃了使用 Edge&…