dlopen失败:无法打开共享对象文件:没有那个文件或目录。

11

问题是我使用dlopen加载一个库(.so是由我编写的,不是系统库),但我得到了标题中显示的错误。

  1. 我已经包含了dlfcn.h
  2. 在编译器中,我使用了-ldl命令
  3. 我想要加载的只是源代码文件夹,我尝试添加-L.,但它没有起作用。
5个回答

15

找出代码错误最残酷而有效的方法是使用以下命令, 它将为共享库激活调试模式,文档在此处here:

export LD_DEBUG=libs
然后,您会惊讶地发现有这么多信息弹出来。不要担心,这些信息告诉您刚才输入的命令需要哪些共享库以及定位这些所需库的位置。例如,如果您键入 reset ,则屏幕将被重置,然后将打印有关 reset 命令所需的共享库的信息。
然后,执行您的“有问题”的可执行文件以查看出了什么问题。

PS.1:根据您接受的mythagal的解决方案:

  

在dlopen中指定文件的完整路径

     

dlopen(“ / full / path / to / libfile.so”);

似乎即使在 dlopen 函数中使用绝对或相对路径,目录未找到错误仍然会显示出来。我正在使用CentOS,我的Debian也遇到了这个问题。因此,我认为mythagal提供的第一个解决方案是错误的。您可以在上面提到的“调试”模式中验证。


PS.2:如果您“安装”或“编译”一个共享库而不是通过软件包管理器安装它,则必须运行 sudo ldconfig /path/where/not/found/shared/library/reside 来通知系统新添加的共享库。例如:

cp /etc/ld.so.cache ~/ld.so.cache.backup    
#cp -r /etc/ld.so.conf.d ~/ld.so.conf.d.backup #sometimes this backup is unnecessary.
#cp /etc/ld.so.conf ~/ld.so.conf.backup #sometimes this backup is unnecessary.
sudo ldconfig /PATH/WHERE/NOT/FOUND/SHARED/LIBRARY/RESIDE
###I am omitting the cp commands to roll back.
###For example, sudo cp -f ld.so.cache /etc/ld.so.cache
为了理解这里正在发生的事情,请仔细阅读上面链接中的所有内容。

PS.3:您可以随时使用命令export LD_DEBUG=helpexport LD_DEBUG=libs来查明-rpathLD_LIBRARY_PATH如何解决您的问题。您会喜欢这种调试模式。


PS.4:找出问题的一种不那么残酷的方法:

ldd ./YOURproblematicEXECUTABLE

这个命令可以告诉你要打开的共享库是否存在。此外,有很多方法可以解决你的问题,每种方法都有其局限性和应用场景。因此,我强烈建议你阅读我上面提供的链接,并了解如何选择解决问题的方法。在阅读完之后,如果你真的感觉非常“好”,你也可以阅读这篇文章《通过示例更好地理解 Linux 二级依赖项解决方案》以深入了解。


这其实是一个非常好的解释,点赞。 - Dmitry Mikushin

9
如果您想要dlopen的库不在标准搜索路径中,您有多种选择:
  1. 在dlopen中指定文件的完整路径:

    dlopen("/full/path/to/libfile.so");

  2. 通过LD_LIBRARY_PATH添加库的路径:

    LD_LIBRARY_PATH=/path/to/library/ ./executable

  3. 使用ld -rpath选项将库路径添加到应用程序中:

    g++ -link stuff- -Wl,-rpath=/path/to/library/

请注意,选项1和3会将库路径硬编码到您的应用程序中。-rpath有一个选项可以指定相对路径,即:
-Wl,-rpath=$ORIGIN/../lib/

将相对路径嵌入应用程序。


它不工作了,我看文件类型:它是ELF 32位LSB共享对象,ARM,但可执行文件是ELF 32位LSB可执行文件,Intel 80386,这是平台问题吗? - user1534282
可执行文件和库必须编译为相同的平台,是的。 - mythagel

2
我建议使用dlerror来获取原因。
void* handle = dlopen(SO_FILE, RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
if(handle == NULL)
{
    printf(LOG_ERROR, "Error: %s\n",  dlerror());
    assert(0);
}

这将报告错误的详细原因


2

dlopen的声明如下:

void *dlopen(const char *filename, int flag);

如果你将参数'filename'设置为共享库的名称,则应该将当前路径添加到'LD_LIBRARY_PATH'中。例如:

1. dlopen("libtest.so" , RTLD_LAZY)

2. 在shell中,输入命令export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH


1

对于我的情况,解决方案非常简单:

路径应该是绝对路径,除非明确指定为相对路径

所以我进行了替换:

dlopen("mylib.so", RTLD_NOW)

使用

dlopen("./mylib.so", RTLD_NOW)

问题已解决。


1
虽然我的情况不同,但在尝试使用RTLD_NOW后,问题已经显现出来了。我最初尝试了LD_DEBUG-libs,它很啰嗦,但对我没有用,因为我正在使用RTLD_LAZY模式进行打开,并且它没有抱怨库中缺少定义。但是当我使用了RTLD_NOW标志以及LD_DEBUG = libs时,作为第一行最底部,它显示了哪个cpp虚拟函数未实现。 - BaskarA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接