当前位置: 首页 > news >正文

Qt .pro配置gcc相关命令(三):-W1、-L、-rpath和-rpath-link

目录

1.Linux 动态库相关知识

1.1.动态库查找路径

1.2.查看程序依赖的动态库

1.3.修改动态库查找路径的方法

1.4.动态链接器缓存管理

2.-Wl参数

3.-L选项(编译时路径)

4.-rpath参数(运行时路径)

5.-rpath-link 参数

6.常见问题与解决方案

7.总结


        在 Linux 系统中编译和链接动态库时,-L-rpath-rpath-link是三个非常重要的参数,它们分别解决了动态库编译、链接和运行时的不同问题。

1.Linux 动态库相关知识

1.1.动态库查找路径

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

  1.程序本身指定的路径, 即是rpath或 runpath指定的目录;

  • RPATH:硬编码在 ELF 文件中,优先级最高。
  • RUNPATH:与 RPATH 类似,但优先级低于 LD_LIBRARY_PATH

     2.环境变量 LD_LIBRARY_PATH 指定的目录;

  • 用户自定义的临时路径,多个路径用冒号 : 分隔。
  • 例如:export LD_LIBRARY_PATH=/path/to/lib:$LD_LIBRARY_PATH

     3.runpath 指定的目录;

  4./etc/ld.so.cache缓存文件,通常包含 /etc/ld.so.conf 文件编译出的二进制(比如 CentOS 上,该文件会使用 include 从而使用 ld.so.conf.d 目录下面所有的 *.conf 文件,这些都会缓存在 ld.so.cache 中)

  • 这些文件中指定的路径会被动态链接器缓存(通过 ldconfig 命令更新)。

     5.系统默认路径,比如 /lib/usr/lib

  • /lib:系统核心库(如 libc.so)。
  • /usr/lib:用户级库。
  • /usr/local/lib:本地安装的库(如自行编译的软件)。

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

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

1.2.查看程序依赖的动态库

1.ldd 命令

ldd /path/to/program  # 显示程序依赖的所有动态库及其路径
  • 若某库显示为 not found,表示系统未找到该库。

2.readelf 命令

readelf -d /path/to/program | grep -E '(RPATH|RUNPATH|NEEDED)'

输出示例:

0x000000000000000f (RPATH)              Library rpath: [/path/to/lib]
0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

1.3.修改动态库查找路径的方法

1.临时修改:通过 LD_LIBRARY_PATH 环境变量

export LD_LIBRARY_PATH=/path/to/lib:$LD_LIBRARY_PATH  # 当前终端生效
# 或添加到 ~/.bashrc 中使其永久生效
echo 'export LD_LIBRARY_PATH=/path/to/lib:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

2.永久修改:编辑 /etc/ld.so.conf 或添加新配置

# 方法1:直接编辑主配置文件
sudo vim /etc/ld.so.conf
# 添加一行:/path/to/lib
# 保存后更新缓存
sudo ldconfig# 方法2:在 /etc/ld.so.conf.d/ 目录下创建新配置文件
sudo touch /etc/ld.so.conf.d/myapp.conf
sudo echo '/path/to/lib' > /etc/ld.so.conf.d/myapp.conf
sudo ldconfig  # 更新缓存

3.编译时指定:通过 -Wl,-rpath 选项

在编译程序时,使用 -Wl,-rpath 将路径硬编码到程序中:

gcc -o myapp myapp.c -L/path/to/lib -lmylib -Wl,-rpath,/path/to/lib
  • 优点:无需修改系统配置或环境变量。
  • 缺点:路径被固定,若库位置改变需重新编译。

1.4.动态链接器缓存管理

1.更新缓存

当添加新库或修改 /etc/ld.so.conf 后,需执行:

sudo ldconfig  # 重建动态链接器缓存

2.查看缓存内容

ldconfig -p  # 显示当前缓存的所有库及其路径

2.-Wl参数

        在 Linux 系统中,-Wl 是 GCC 编译器的一个重要参数,用于向链接器(如 ld)传递额外选项。由于 GCC 是编译和链接的前端工具,真正处理链接过程的是链接器,因此需要通过 -Wl 将参数传递给链接器。

        基本语法

gcc [编译选项] -Wl,链接器选项1[,链接器选项2,...] [源文件]

将逗号分隔的选项传递给链接器。如:

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 

3.-L选项(编译时路径)

  • 编译时:指定链接器搜索库文件的路径。
  • 仅影响链接过程,不影响程序运行时的库查找。

假设你有一个自定义库 libmath.so 位于 /opt/mylibs 目录下:

g++ main.cpp -L/opt/mylibs -lmath -o myapp
  • -L/opt/mylibs:告诉链接器在 /opt/mylibs 目录下搜索 libmath.so
  • -lmath:链接名为 libmath.so 的库。

-L一般用于链接非标准位置的第三方库(如 /usr/local/lib 以外的路径)。

4.-rpath参数(运行时路径)

        运行时搜索路径,将动态库搜索路径硬编码到可执行文件中(运行时生效)。通过修改可执行文件的 .dynamic 段,将路径硬编码到二进制文件中。

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

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

        示例:

g++ main.cpp -L/opt/mylibs -lmath -Wl,-rpath=/opt/mylibs -o myapp
  • -Wl,-rpath=/opt/mylibs:将 /opt/mylibs 添加到程序运行时的库搜索路径。

等价写法

# 直接使用链接器参数
g++ main.cpp -L/opt/mylibs -lmath -Wl,-rpath=/opt/mylibs -o myapp# 或使用环境变量
export LDFLAGS="-Wl,-rpath=/opt/mylibs"
g++ main.cpp -L/opt/mylibs -lmath $LDFLAGS -o myapp

特殊变量

$ORIGIN:表示可执行文件所在目录,常用于相对路径。

# 搜索与可执行文件同级的 lib 目录
-Wl,-rpath='$ORIGIN/../lib'

注意:在 Makefile 或 shell 脚本中使用时,需用双引号防止变量提前展开:

-Wl,-rpath="\$$ORIGIN/../lib"

在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'")

5.-rpath-link 参数

        用于指定动态库的搜索路径(在链接阶段),该选项只在链接阶段起作用,不会被写入elf文件中。辅助链接器解析库之间的依赖关系,但不影响程序运行时的库搜索路径。适用于复杂的库依赖链(如 A 依赖 B,B 依赖 C)。

        示例:假设:

  • libapp.so 依赖 libmath.so
  • libmath.so 依赖 libutils.so(位于 /opt/thirdparty)。
# 链接 libapp.so 时指定 libmath.so 的依赖路径
g++ -shared -fPIC app.cpp -L/opt/mylibs -lmath -Wl,-rpath-link=/opt/thirdparty -o libapp.so
  • -Wl,-rpath-link=/opt/thirdparty:告诉链接器,libmath.so 依赖的 libutils.so 在 /opt/thirdparty 目录下。
  • 但程序运行时,仍需通过 -rpath 或环境变量指定 /opt/thirdparty

在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 的区别

  • -rpath:同时影响链接和运行时的库搜索。
  • -rpath-link:仅在链接时生效,不修改可执行文件的运行时路径。

三者对比

参数生效阶段是否影响运行时作用
-L链接时指定链接器搜索库的路径
-rpath运行时修改程序运行时的库搜索路径(硬编码到二进制文件)
-rpath-link链接时辅助链接器解析库依赖关系,但不影响程序运行时的搜索路径

6.常见问题与解决方案

1.错误:libxxx.so: cannot open shared object file: No such file or directory

  • 可能原因
    • 库未安装。
    • 库路径未包含在查找路径中。
  • 解决方案
# 1. 确认库是否存在
find / -name "libxxx.so*" 2>/dev/null# 2. 若存在,将路径添加到 LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/path/to/lib:$LD_LIBRARY_PATH# 3. 或添加到系统配置
echo '/path/to/lib' | sudo tee -a /etc/ld.so.conf
sudo ldconfig

2.区分 RPATH 和 RUNPATH

  • RPATH:在 RUNPATH 和 LD_LIBRARY_PATH 之前被搜索。
  • RUNPATH:在 LD_LIBRARY_PATH 之后被搜索。

修改方法

# 编译时指定 RPATH
gcc -Wl,-rpath,/path/to/lib ...# 编译时指定 RUNPATH(需显式使用 -rpath-link)
gcc -Wl,-rpath-link,/path/to/lib -Wl,-rpath,'$ORIGIN/../lib' ...
  • $ORIGIN 表示程序所在目录,用于相对路径。

3.链接时提示找不到库的依赖

/usr/bin/ld: libmath.so: undefined reference to `function_in_libutils'

原因

  • libmath.so 依赖 libutils.so,但链接器找不到 libutils.so

解决方案

# 临时指定依赖路径
g++ -shared -fPIC app.cpp -L/opt/mylibs -lmath -Wl,-rpath-link=/opt/thirdparty -o libapp.so

7.总结

  1. 优先使用 -rpath:减少对环境变量的依赖,提高程序可移植性。
  2. 使用 $ORIGIN:让库路径相对于可执行文件,避免硬编码绝对路径。
  3. 谨慎使用 -rpath-link:仅在链接复杂依赖的库时使用,避免污染运行时路径。
  4. 测试部署:确保程序在目标环境中能正常找到库(如使用 ldd myapp 检查)。

通过合理组合 -L-rpath 和 -rpath-link,可以灵活控制动态库的编译、链接和运行时行为,解决复杂的依赖问题。

相关文章:

  • std::shared_ptr引起内存泄漏的例子
  • [CVPR 2025] DeformCL:基于可变形中心线的3D血管提取新范式
  • AI应用:计算机视觉相关技术总结
  • 蓝桥杯国赛前一晚知识点准备(十六届python)
  • 灵敏度分析
  • Codeforces Round 1030 (Div. 2)
  • STM32项目---汽车氛围灯
  • Flutter JSON解析全攻略:使用json_serializable实现高效序列化
  • MySQL 调优笔记
  • 项目拓展-简易SQL监控,P6SPY拦截所有jdbc连接并打印执行SQL
  • 第1章 C# 和 .NET 框架 笔记
  • 【知识图谱构建系列3】zero-shot的理念介绍
  • Android xml的Preference设置visibility=“gone“ 无效分析解决
  • 【无标题】【2025年软考中级】第三章数据结构3.2 栈与队列
  • LeetCode - 69. x 的平方根
  • 数据结构 学习 链表 2025年6月14日08点01分
  • 力扣Hot100每日N题(15~16)
  • sqli-labs靶场46-53关(综合)
  • 拆解 CMS/G1/ZGC 三种垃圾回收器算法过程
  • Python实战应用-Python操作MySQL数据库
  • 不懂代码如何做网站/网络营销推广实训报告
  • 嘉兴网站制作公司/网站建设公司网站
  • 公司找人做网站/竞价网络推广培训
  • 常平网站开发/赣州seo
  • 长沙好的做网站品牌/广东seo网站推广代运营
  • wordpress 主题 设置/seo概念