dlopen() 返回 0

dlopen() is returning 0

在我的目录中,我有两个文件。一个是foo.cpp,另一个是bar.so。在 foo.cpp 中,我正在尝试加载库 bar.so:

#include <dlfcn.h>
#include <iostream>

int main()
{
    void* handle = dlopen("bar.so", RTLD_NOW | RTLD_GLOBAL);
    std::cout << handle << std::endl;
    return 0;
}

在同一个目录中,然后我从命令行编译代码:

g++ foo.cpp -ldl -o test

然而,当执行 test 时,这会打印出 0,并且根据 dlopen 的文档:

If dlopen() fails for any reason, it returns NULL

当库文件与 CPP 文件位于同一目录时,为什么返回 NULL?


更新:

我现在已经将 dlopen() 添加到我的 CPP 文件中,并且输出:

bar.so: cannot open shared object file: No such file or directory

但我不明白... bar.sofoo.cpp 在同一目录中,可执行文件是在同一目录中构建的,而我在同一目录中 运行 可执行文件。

然后,我尝试使用 bar.so 的绝对路径,但随后收到一个新错误:

invalid ELF header

快速 google 之后,我认为这可能是由于我的 Ubuntu 安装所致。我实际上使用的是 MacBook,并且安装了 Ubuntu 的本机副本(不是虚拟机)。看来这是导致问题的原因,但我不知道如何解决。也许这个库文件不能在 MacBook 上运行 Ubuntu.

So why is this returning NULL, when the library file is in the same directory as the CPP file?

.cpp 文件的位置与此处无关。

可执行文件的位置,分别是 LD_LIBRRY_PATH 的设置,用于在运行时解析。

无论如何,LD_LIBRRY_PATH 不是推荐的 long-term 解决方案。最简单的方法是使用 "./bar.so" 而不是 "bar.so",这样 dlopen() 首先在当前目录中查找。但是当前目录可能与可执行文件所在的目录不同。在这种情况下,dlopen() 仍然会失败。

另一种解决方案是在编译可执行文件时将 -Wl,-rpath='$ORIGIN' 添加到编译标志(在本例中为 foo.cpp )并像您已经传递的那样传递 "bar.so" 。当使用 $ORIGIN 作为 rpath 时,当前目录是什么并不重要。 dlopen() 将始终首先查找可执行文件的目录。但请注意,这将导致首先在当前目录中查找所有库,而不仅仅是那些您尝试 dlopen() 的库。它可能是也可能不是你想要的。

所以最好的解决方案是在运行时获取可执行文件所在目录的路径,并将其用作 bar.so 的路径。这是系统特定的。在 Linux 上,请参阅:Get path of executable