在我的目录中,我有两个文件。一个是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
快速浏览Google之后,我认为这可能是由于我安装了Ubuntu。我实际上使用的是MacBook,并且已经安装了Ubuntu的本机副本(不是虚拟机)。看来这是造成问题的原因,但我不知道如何解决。也许该库文件仅在MacBook Ubuntu上不起作用。
答案 0 :(得分:4)
当库文件与CPP文件位于同一目录时,为什么为什么返回NULL?
.cpp
文件的位置与此处无关。
可执行文件的位置或LD_LIBRRY_PATH
的设置是在运行时用来解析的。
无论如何,不建议使用LD_LIBRRY_PATH
长期解决方案。最简单的方法是使用"./bar.so"
而不是"bar.so"
,以便dlopen()
首先在当前目录中查找。但是当前目录可能与可执行文件的存储目录不同。在这种情况下,dlopen()
仍然会失败。
另一种解决方案是在编译可执行文件(在这种情况下为-Wl,-rpath='$ORIGIN'
时,将foo.cpp
添加到编译标志中,并像以前一样传递"bar.so"
。使用$ORIGIN
作为rpath时,当前目录是什么都没有关系。 dlopen()将始终始终在可执行文件的目录中查找。但是请注意,这将导致首先在当前目录中查找所有库,而不仅仅是您尝试dlopen()的库。可能是您想要的,也可能不是。
所以最好的解决方案是在运行时获取可执行文件所在目录的路径,并将其用作bar.so
的路径。这是系统特定的。在Linux上,请参见:Get path of executable