LD_LIBRARY_PATH临时生效且优先级最高,用于调试时强制加载指定库;rpath编译期固化路径,更可靠但需显式配置(如CMake设BUILD_RPATH);$ORIGIN仅在rpath中有效,代表可执行文件目录。

LD_LIBRARY_PATH 临时生效但优先级高,适合调试
运行时动态链接器会按顺序查找库:先查 LD_LIBRARY_PATH 中的路径(以冒号分隔),再查 /etc/ld.so.cache,最后是默认路径如 /lib 和 /usr/lib。这意味着即使系统里有同名旧版库,只要 LD_LIBRARY_PATH 指向你自己的新版库目录,它就会被优先加载。
常见错误是漏掉 export 或拼错变量名,比如写成 LD_LIBARY_PATH(少一个 R)——这时变量根本不会生效,程序仍报 libxxx.so: cannot open shared object file。
- 临时设置(仅当前 shell 有效):
export LD_LIBRARY_PATH="/path/to/my/libs:$LD_LIBRARY_PATH" - 验证是否生效:
echo $LD_LIBRARY_PATH,再用ldd ./myapp | grep xxx看是否指向预期路径 - 不建议在生产环境长期依赖它:它绕过系统包管理,容易因环境变量污染导致行为不一致
rpath 编译期固化路径,更可靠但需显式配置
rpath 是嵌入在可执行文件或共享库内部的搜索路径,由链接器(ld)在构建时写入,运行时不依赖环境变量。它的优先级高于 /etc/ld.so.cache,但低于 LD_LIBRARY_PATH(除非用 patchelf --no-default-lib 或禁用该变量)。
关键点在于:CMake 默认不启用 rpath,而 Makefile 直接调用 g++ 时也必须显式传参,否则生成的二进制里 DT_RUNPATH 或 DT_RPATH 字段为空。
立即学习“C++免费学习笔记(深入)”;
- CMake 中启用并设置:
set(CMAKE_BUILD_RPATH "$ORIGIN/../lib"),再加set(CMAKE_BUILD_RPATH_USE_ORIGIN ON)支持$ORIGIN(表示可执行文件所在目录) - 手动链接时:
g++ -o app main.o -L./lib -lmylib -Wl,-rpath,'$ORIGIN/lib'—— 注意单引号防止 shell 提前展开$ORIGIN - 检查是否写入成功:
readelf -d ./app | grep rpath,输出应含Library rpath: [$ORIGIN/lib]
$ORIGIN 是相对路径的关键,但不能用在 LD_LIBRARY_PATH 里
$ORIGIN 是动态链接器识别的特殊 token,只在 rpath 或 runpath 中有效,代表可执行文件自身的目录。它让部署更灵活:比如把整个 bin/ 和 lib/ 打包移动,只要相对结构不变,库就能自动找到。
有人误以为在 LD_LIBRARY_PATH 里写 $ORIGIN/lib 也能起作用,实际不会——shell 展开后变成空字符串或字面量 $ORIGIN/lib,链接器根本不认识这个路径。
- 正确用法仅限
-rpath或-R参数:-Wl,-rpath,'$ORIGIN/../libs' - 多个路径用冒号连接:
-Wl,-rpath,'$ORIGIN/lib:$ORIGIN/../third_party/lib' - 避免硬编码绝对路径(如
/home/user/project/lib),否则换机器就失效
运行时排查:ldd 和 readelf 比 error message 更准
当程序启动报 error while loading shared libraries,别急着改环境变量。先用 ldd 看链接状态——它模拟链接器行为,但不实际加载,结果更稳定;而 strace ./app 2>&1 | grep openat 虽能看真实 open 尝试,但输出太杂。
-
ldd ./app显示“not found”不等于真没找到:可能权限不足、架构不匹配(如 aarch64 库跑在 x86_64)、或符号版本不兼容 -
readelf -d ./app | grep -E "(RUNPATH|RPATH)"确认 rpath 是否存在且格式正确(注意有些老系统只认RPATH,新链接器默认写RUNPATH) - 如果
ldd显示库路径却仍失败,用objdump -p ./app | grep NEEDED核对所需库名,再确认对应.so文件是否存在且可读
$ORIGIN/lib,又 export 了 LD_LIBRARY_PATH=/tmp/hack,而 /tmp/hack 里恰好有个 ABI 不兼容的同名库——这时候程序会静默加载错的版本,崩溃时堆栈还看不出根源。


















