首页 > 解决方案 > dlopen() 返回 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

如果 dlopen() 因任何原因失败,则返回 NULL

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


更新:

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

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

但我不明白......bar.so并且foo.cpp在同一个目录中,可执行文件是在同一个目录中构建的,当我运行可执行文件时我在同一个目录中。

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

invalid ELF header

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

标签: c++linuxg++dlopen

解决方案


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

文件的位置在.cpp这里无关紧要。

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

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

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

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


推荐阅读