即使设置了 RPATH,为什么此可执行文件不加载相对路径模块库?

即使设置了 RPATH,为什么此可执行文件不加载相对路径模块库?

我从 Stack Overflow 迁移了这个问题;虽然它涉及到编程方面的内容,但我越是尝试了解发生的情况,我就越认为这可能与RPATH和相关$ORIGIN,我认为这与 Unix/Linux 相关。 (我的问题在 Stack Overflow 上也没有得到太多关注)我将尽可能多地删除问题中与编程相关的方面(例如 CMakeLists.txt),但如果回复者说它们是相关的。

我创建了一个可执行文件,它从可执行文件所在的子目录加载模块库(或“共享库”或“插件库”,因为它有不同的称呼)。目录结构为:

build/
├── main  # the executable
└── plugins
    └── libmy-plugin.so

为了与这个问题的编程方面保持一定的距离,我不会显示完整的 C 代码(除非有人说它不会使这个问题偏离本网站的主题)。但它实际上相当于加载模块库的“hello-world”,只不过有一点不同:它从相对路径加载插件库。具体来说,它加载plugins/libmy-plugin.so.最低限度的代码片段是:

const char* plugin = "plugins/libmy-plugin.so";
void* handle = dlopen(plugin, RTLD_NOW);

手册页dlopen说:

函数 dlopen() 加载以 null 结尾的字符串文件名命名的动态共享对象(共享库)文件,并返回加载对象的不透明“句柄”...如果文件名为 NULL,则返回的句柄用于主文件程序。如果文件名包含斜杠(“/”),则将其解释为(相对或绝对)路径名。

手册页ld-linux.so说:

$ORIGIN(或等效的 ${ORIGIN})
这扩展到包含程序或共享对象的目录。因此,位于 somedir/app 中的应用程序可以进行编译,
gcc -Wl,-rpath,'$ORIGIN/../lib'
以便无论 somedir 位于目录层次结构中的哪个位置,它都能在 somedir/lib 中找到关联的共享对象。这有助于创建“交钥匙”应用程序,这些应用程序不需要安装到特殊目录中,而是可以解压缩到任何目录中,并且仍然可以找到它们自己的共享对象。

据我所知如何检查,我编译的二进制文件确实将其RPATH设置为$ORIGIN

$ objdump -x ./build/main | grep PATH
  RUNPATH              $ORIGIN
$
$ readelf -d ./build/main

Dynamic section at offset 0x2d98 contains 28 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000001d (RUNPATH)            Library runpath: [$ORIGIN]
...

根据我的阅读,由于$ORIGIN“扩展到包含程序的目录”和“[i]f文件名包含斜杠(“/”),那么它被解释为(相对或绝对)路径名”,这应该意味着程序如果将其RPATH设置为使用包含斜杠(并且是相对路径)的文件名$ORIGIN进行调用dlopen(),则该模块库的搜索路径应该相对于包含程序的目录。

但这不是我观察到的。我实际观察到的是,当我的 CWD 是包含可执行文件的目录时,可执行文件仅找到模块库。如果我在任何其他目录中,并指定可执行文件的完整相对/绝对路径,它不会找到模块库(并且似乎不受设置影响LD_LIBRARY_PATH):

$ ./build/main
failed loading plugins/libmy-plugin.so: plugins/libmy-plugin.so: cannot open shared object file: No such file or directory
$
$ LD_LIBRARY_PATH=./build ./build/main
failed loading plugins/libmy-plugin.so: plugins/libmy-plugin.so: cannot open shared object file: No such file or directory
$
$ LD_LIBRARY_PATH=/home/user/dev/cmake-learn/rpath/build/ ./build/main
failed loading plugins/libmy-plugin.so: plugins/libmy-plugin.so: cannot open shared object file: No such file or directory
$
$ cd build/
$ ./main
all good
$

我在脑海中反复思考这是一个编程问题还是一个 Unix/Linux 问题,正如我提到的,我有一种非特定的感觉,这与 Unix/Linux 模块搜索路径有关,但如果社区认为这真的是一个编程问题,我会再次在 Stack Overflow 上碰碰运气。
(我在 Stack Overflow 上的原始问题的评论者说搜索路径始终与 CWD 相关,但这不是一个完全解释性的答案,因此我无法将该声明与我对注释手册页部分的阅读相一致)

答案1

对我来说,man dlopen可以理解为:要么文件名有/所以不被搜索(它相对于“.”或来自“/”),要么没有,并且在所有路径机制中搜索它。

您可能应该期望必须使用dlopen("libmy-plugin.so",)并提供-Wl,-rpath,'$ORIGIN/plugins'

相关内容