我使用 cmake 编写了一个简单的程序/库组合,名为“PrintFive”。
从 CLI 运行:
readelf -d PrintFive
Dynamic section at offset 0x2d60 contains 30 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libUsesSharedLib.so]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [/home/xxx/Projects/PrintFive/UsesSharedLib/sharedLib/lib:/home/xxx/Projects/PrintFive/build/UsesSharedLib]
...
奇怪。我的理解是 CMake 会写入 RPATH。它没有出现,但“RUNPATH”出现了。
如果我从 CLI 运行该应用程序,则可以轻松找到该库。
如果我删除 RUNPATH 属性:
chrpath -d PrintFive
然后应用程序不再运行。没有意外。如果我设置LD_LIBRARY_PATH
为指向图书馆的位置,那么一切都会恢复正常。
(此时我重建了我的程序)
如果这个“RUNPATH”是真的,RUNPATH
那么我应该能够使用覆盖它LD_LIBRARY_PATH
。或者本文索偿。
所以我从应用程序的构建目录运行:
export LD_LIBRARY_PATH=`pwd`
(请注意,使用 cmake 构建时,库不会与应用程序放在同一目录中)
按照理论,应用程序现在不应该运行,因为 LD_LIBRARY_PATH 应该覆盖二进制文件中嵌入的任何真正的 RUNPATH。
但它运行了。对我来说,这表明二进制文件确实有 RPATH。
我有两种理论。
- readelf 返回 RPATH 作为 RUNPATH
- 尽管二进制文件中已经嵌入了 RPATH,但 readelf 不会打印 RPATH。
附加信息:
readelf -v
GNU readelf (GNU Binutils for Ubuntu) 2.34
Copyright (C) 2020 Free Software Foundation, Inc.
不过,我已经看到很多互联网文章显示 readelf 打印 RPATH。有人能告诉我吗?
答案1
我怀疑你的推理LD_LIBRARY_PATH
是错误的。在寻找库时,动态链接器会按照一定的顺序搜索各个位置:
- 路径
- LD_LIBRARY_PATH
- 运行路径
- 缓存文件
- 在默认路径 /lib 和 /usr/lib (或 lib64,取决于 glibc 的一些编译设置)中
这并不意味着如果设置了,搜索将在步骤 2 之后无条件停止LD_LIBRARY_PATH
。它只是意味着如果在步骤 2 中找到合适的库,则跳过步骤 3 及后续步骤。