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

打印 上一主题 下一主题

主题 987|帖子 987|积分 2961

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
一、参考资料

链接选项 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 动态库查找路径

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

  • rpath 指定的目录;
  • 情况变量 LD_LIBRARY_PATH 指定的目录;
  • runpath 指定的目录;
  • /etc/ld.so.cache 缓存文件,通常包罗 /etc/ld.so.conf 文件编译出的二进制俩别哦(比如 CentOS 上,该文件会使用 include 从而使用 ld.so.conf.d 目录下面全部的 *.conf 文件,这些都会缓存在 ld.so.cache 中)
  • 系统默认路径,比如 /lib,/usr/lib。
在编译时若使用 -z nodefaultlib 选项编译,则会跳过 4 和 5。至于 runpath,和 rpath 类似,都是二进制(ELF)文件的动态 section 属性(分别为 DT_RUNPATH 和 DT_RPATH),唯一区别就是是否优先于 LD_LIBRARY_PATH 来查找。
   rpath vs. runpath:rpathrunpath 是嵌入在可实验文件或共享库中的路径列表,用于指定运行时查找共享库的位置。rpath 是旧尺度,runpath 是新尺度,功能类似但优先级不同。
  -Wl参数

gcc的-Wl,xxx选项将逗号分隔的标志列表(flags)作为空格分隔的参数列表传递给链接器,即:
  1. gcc -Wl,aaa,bbb,ccc
复制代码
终极变成了linker的用法:
  1. ld aaa bbb ccc
复制代码
如果是想把ld -rpath通过-Wl传递给gcc,可以是-Wl,-rpath,xxx,也可以指定-Wl的重复实例:
  1. gcc -Wl,aaa -Wl,bbb -Wl,ccc
复制代码
类似的参数还有:
  1. -Wa,<options>   Pass comma-separated <options> on to the assembler
  2. -Wp,<options>   Pass comma-separated <options> on to the preprocessor
  3. -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 路径。
  1. # 设置交叉编译工具链的环境变量
  2. export PATH=/home/yoyo/360Downloads/toolchains/arm-linux-gnueabihf/bin:$PATH
  3. # 查看交叉编译工具链的 sysroot 路径
  4. arm-linux-gnueabihf-gcc -print-sysroot
复制代码
输出示例:
  1. yoyo@yoyo:~$ arm-linux-gnueabihf-gcc -print-sysroot
  2. /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 中。可以在编译时设置 RPATH 或 RUNPATH 为 $ORIGIN/../lib,这样程序运行时会在 /app/lib 中查找依赖库。
  1. /app/
  2.     myprogram.c
  3.     bin/
  4.             app
  5.     lib/
  6.         libdependency.so
复制代码
在链接 app 时,可以使用:
  1. gcc -Wl,-rpath,'$ORIGIN/../x264/lib' -Wl,rpath,'$ORIGIN/../x265/lib' -o app myprogram.c
  2. -Wl,-rpath,'$ORIGIN'
复制代码
如果须要设置多个路径,可以将它们用空格分隔,并确保每个路径前都有 -Wl,-rpath,。
  1. -Wl,-rpath,'$ORIGIN/../third_party/arm_opencv/3rdparty/zlib/lib' \
  2. -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

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

现代毗连器在处置惩罚动态库时将链接时路径(Link-time path) 和 运行时路径(Run-time path) 分开,用户可以通过 -L指定毗连时库的路径,通过-R(或-rpath)指定程序运行时库的路径,大大进步了库应用的机动性。
-rpath和-rpath-link之间的区别:-rpath选项指定的目录被包罗在可实验文件中并在运行时使用,而-rpath-link选项仅在链接时有效。
通过测试发现,-Wl,-rpath下面这三种写法都是可以的:
  1. -Wl,-rpath -Wl,/usr/lib/gstreamer-1.0
  2. -Wl,-rpath,/usr/lib/gstreamer-1.0
  3. -Wl,-rpath=/usr/lib/gstreamer-1.0
复制代码
-l 选项

   功能:添加须要链接的库文件,如果没有后缀指明动态库还是静态库,则优先使用动态库。
  -L选项(编译时路径)

   功能:-L 指定的是编译时链接的动态库搜索路径。
  编译时-L选项并不影响情况变量 LD_LIBRARY_PATH,只是指定了程序编译毗连时库的路径,并不影响程序实验时库的路径。当程序运行时,系统还是会到默认路径下查找该程序所须要的库,如果找不到,会出现类似 cannot open shared object file 的错误。
  1. -L/mylib -lmylib
复制代码
-Wl,-rpath选项(运行时路径)

   功能:-Wl,-rpath 用于指定动态库的搜索路径(在运行阶段),该路径会被记载在elf可实验文件中。
  -rpath 的作用相称于在程序运行时设置了 LD_LIBRARY_PATH 情况变量,因为 -rpath指定的路径会被记载在生成的可实验程序中,用于运行时查找须要加载的动态库 。因此,在开辟板中无需设置情况变量即可找到相干的动态库。通常情况下,保举使用 -Wl,-rpath 选项。
  1. # 单个路径-L/mylib -lmylib
  2. -Wl,-rpath=dir# 多个路径-L/mylib -lmylib
  3. -Wl,-rpath,dir1:dir2:...:dirN
复制代码
在cmake中使用:
  1. # 设置第三方库路径
  2. set(3RDPARTY_DIR "${PARENT_DIR}/third_party")
  3. # 设置目标属性,将运行时库搜索路径添加到目标
  4. set_target_properties(
  5.     dla_detect
  6.     PROPERTIES
  7.     LINK_FLAGS
  8.     "-L${3RDPARTY_DIR}/zlib/lib -Wl,-rpath,'$ORIGIN/../../third_party/zlib/lib' \
  9.     -L${3RDPARTY_DIR}/szlib/lib -Wl,-rpath,'$ORIGIN/../../third_party/szlib/lib' \
  10.     -L${3RDPARTY_DIR}/hdf5/lib -Wl,-rpath,'$ORIGIN/../../third_party/hdf5/lib' \
  11.     -L${3RDPARTY_DIR}/x264/lib -Wl,-rpath,'$ORIGIN/../../third_party/x264/lib' \
  12.     -L${3RDPARTY_DIR}/x265/lib -Wl,-rpath,'$ORIGIN/../../third_party/x265/lib' \
  13.     -L${3RDPARTY_DIR}/ffmpeg/lib -Wl,-rpath,'$ORIGIN/../../third_party/ffmpeg/lib' \
  14.     -L${3RDPARTY_DIR}/sigmastar/lib -Wl,-rpath,'$ORIGIN}/../../third_party/sigmastar/lib' \
  15.     -L${3RDPARTY_DIR}/arm_opencv/lib -Wl,-rpath,'$ORIGIN/../../third_party/arm_opencv/lib' \
  16.     -L${PARENT_DIR}/build -Wl,-rpath,'$ORIGIN/../../build'"
  17. )
复制代码
大概:
  1. # 设置第三方库路径
  2. set(3RDPARTY_DIR "${PARENT_DIR}/third_party")
  3. # 设置rpath
  4. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} \
  5. -L${3RDPARTY_DIR}/zlib/lib -Wl,-rpath,'$ORIGIN/../../third_party/zlib/lib' \
  6. -L${3RDPARTY_DIR}/szlib/lib -Wl,-rpath,'$ORIGIN/../../third_party/szlib/lib' \
  7. -L${3RDPARTY_DIR}/hdf5/lib -Wl,-rpath,'$ORIGIN/../../third_party/hdf5/lib' \
  8. -L${3RDPARTY_DIR}/x264/lib -Wl,-rpath,'$ORIGIN/../../third_party/x264/lib' \
  9. -L${3RDPARTY_DIR}/x265/lib -Wl,-rpath,'$ORIGIN/../../third_party/x265/lib' \
  10. -L${3RDPARTY_DIR}/ffmpeg/lib -Wl,-rpath,'$ORIGIN/../../third_party/ffmpeg/lib' \
  11. -L${3RDPARTY_DIR}/sigmastar/lib -Wl,-rpath,'$ORIGIN/../../third_party/sigmastar/lib' \
  12. -L${3RDPARTY_DIR}/arm_opencv/lib -Wl,-rpath,'$ORIGIN/../../third_party/arm_opencv/lib' \
  13. -L${PARENT_DIR}/build -lsigmastar_vVehicle_det -Wl,-rpath,'$ORIGIN/../../build'")
复制代码
编译之后,检察rpath:
  1. yoyo@yoyo:~/share/driver/dla_detect$ readelf -d test/build/dla_detect
  2. ...
  3. 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]
  4. ...
复制代码
-Wl,-rpath-link选项(运行时路径)

   功能:-Wl,-rpath-link 用于指定动态库的搜索路径(在链接阶段),该选项只在链接阶段起作用,不会被写入elf文件中。
  1. -L/mylib -lmylib
  2. -Wl,-rpath-link=<library_path>
复制代码
在cmake中使用:
  1. # 设置第三方库路径
  2. set(3RDPARTY_DIR "${PARENT_DIR}/third_party")
  3. # 设置目标属性,将运行时库搜索路径添加到目标
  4. set_target_properties(
  5.     dla_detect
  6.     PROPERTIES
  7.     LINK_FLAGS
  8.     "-L${3RDPARTY_DIR}/zlib/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/zlib/lib' \
  9.     -L${3RDPARTY_DIR}/szlib/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/szlib/lib' \
  10.     -L${3RDPARTY_DIR}/hdf5/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/hdf5/lib' \
  11.     -L${3RDPARTY_DIR}/x264/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/x264/lib' \
  12.     -L${3RDPARTY_DIR}/x265/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/x265/lib' \
  13.     -L${3RDPARTY_DIR}/ffmpeg/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/ffmpeg/lib' \
  14.     -L${3RDPARTY_DIR}/sigmastar/lib -Wl,-rpath-link,'$ORIGIN}/../../third_party/sigmastar/lib' \
  15.     -L${3RDPARTY_DIR}/arm_opencv/lib -Wl,-rpath,'$ORIGIN/../../third_party/arm_opencv/lib' \
  16.     -L${PARENT_DIR}/build -Wl,-rpath-link,'$ORIGIN/../../build'"
  17. )
复制代码
大概:
  1. # 设置第三方库路径
  2. set(3RDPARTY_DIR "${PARENT_DIR}/third_party")
  3. # 设置rpath
  4. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} \
  5. -L${3RDPARTY_DIR}/zlib/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/zlib/lib' \
  6. -L${3RDPARTY_DIR}/szlib/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/szlib/lib' \
  7. -L${3RDPARTY_DIR}/hdf5/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/hdf5/lib' \
  8. -L${3RDPARTY_DIR}/x264/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/x264/lib' \
  9. -L${3RDPARTY_DIR}/x265/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/x265/lib' \
  10. -L${3RDPARTY_DIR}/ffmpeg/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/ffmpeg/lib' \
  11. -L${3RDPARTY_DIR}/sigmastar/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/sigmastar/lib' \
  12. -L${3RDPARTY_DIR}/arm_opencv/lib -Wl,-rpath-link,'$ORIGIN/../../third_party/arm_opencv/lib' \
  13. -L${PARENT_DIR}/build -lsigmastar_vVehicle_det -Wl,-rpath-link,'$ORIGIN/../../build'")
复制代码
编译之后,检察二进制的 rpath:
  1. yoyo@yoyo:~/share/driver/dla_detect$ readelf -d test/build/dla_detect
  2. ...
  3. 0x0000000f (RPATH)                      Library rpath: [/home/yoyo/share/driver/dla_detect/third_party/arm_opencv/share/opencv4/../../lib]
  4. ...
复制代码
检察 rpath:
  1. objdump -x path/to/executable | grep RPATH
  2. readelf -d path/to/executable | head -20
  3. chrpath -l path/to/executable
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用户国营

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表