error while loading shared libraries 找不到动态库问题如何解决

在使用 c 或 c++ 开发应用时,在启动程序时,有时会遇到这个错误,找不到动态库。这个时候,我们使用 ldd 来查看,发现可执行文件依赖的动态库显示为 not found。

1 实验代码

使用如下 3 个文件做实验。

hello.h 中声明了函数 say_hello()。

hello.c 中实现了函数 say_hallo(), 在函数中打印 hello,hello.c 编译出一个动态库。

main.c 中调用 hello.c 中的函数 say_hello(),main.c 编译出可执行文件。

hello.h:

void say_hello();

hello.c

#include <stdio.h>
#include "hello.h"

void say_hello() {
  printf("hello\n");
}

main.c

#include "hello.h"

int main() {
  say_hello();
  return 0;
}

使用 gcc -fPIC -shared hello.c -o libhello.so 编译出动态库,使用 gcc main.c libhello.so 编译可执行文件,编译之后的文件目录如下,libhello.so 是动态库,a.out 是可执行文件。

这个时候直接执行 a.out 却无法执行,打印错误信息是找不到动态库。

除了使用 ldd 查看文件依赖的动态库之外,还可以使用 objdump 或 readelf 来查看可执行文件依赖的动态库。

objdump -x a.out |grep NEED

readelf -d a.out |grep NEED

2 动态库路径配置

有几种方式可以配置动态库的路径,这几种方式都是可行的,其中 LD_LIBRARY_PATH 是工作中最常使用的。

2.1 LD_LIBRARY_PATH 

工作中,我们常用的是设置一个环境变量 LD_LIBRARY_PATH,将依赖的动态库路径追加到这个环境变量中,可执行文件就可以执行了。在执行可执行文件时,linux 加载器会从这个环境变量所包含的路径中找动态库。

如下图所示,将 libhello.so 追加到环境变量,使用 ldd 查看 a.out 依赖的库,也不会显示 not found 了,执行 a.out 也可以正确执行。

2.2 /etc/ld.so.conf.d/

先看看这个目录下,默认有什么文件。可以看到,有 3 个 .conf 文件,文件中的内容分别是 /usr/local/lib,/lib/x86_64-linux-gnu、/usr/lib/x86_64-linux-gnu,/usr/lib/x86_64-linux-gnu/libfakeroot。这个目录下配置的路径下的动态库会被查找到。

在该目录下配置的路径下的动态库,可以通过 ldconfig -p 查看到。

如果要把本文中的 libhello.so 也加入到这个目录下,操作如下:

(1)首先在目录下增加一个 .conf 文件,文件名没有要求,只要不重复就可以,文件里写入 libhello.so 所在的目录

(2)执行 ldconfig,添加配置之后执行 ldconfig 才会生效

执行完两个步骤之后,使用 ldconfig -p 就可以看到 libhello.so 出现在缓存里了。

2.3 编译时添加路径

在编译的时候使用 -Wl,rpath  来添加动态库路径。其中 rpath 是 run path 的意思,使用 rpath 指定的路径,在加载时会到这个路径下查找动态库。

gcc main.c -lhello -L. -Wl,-rpath /home/wyl/test/libtest/

使用上边的命令编译之后,使用 ldd 查看 a.out 依赖的动态库,能够找到 libhello.so。

使用 objdump 可以看到,这个路径被直接写到了 a.out 文件中。

3 不同配置下的动态库查找顺序

LD_DEBUG 可以用来查看链接和加载过程的信息,用来调试。LD_DEBUG 可以赋不同的值,不同的值可以查看不同的调试信息。

我们使用 libs 来显示库的加载信息。在实验之前,做如下工作:

(1)编译时使用 rpath 选项

这样的话,就会将 /home/wyl/test/libtest/ 写到编译的目标文件中

gcc main.c -lhello -L. -Wl,-rpath /home/wyl/test/libtest/

(2)配置 LD_LIBRARY_PATH

export LD_LIBRARY_PATH=/home/wyl/test/libtest/lib1:$LD_LIBRARY_PATH

(3)配置 /etc/ld.so.conf.d/hello.conf

这样的话,3 种方式都做了配置,但是 3 个方式配置的路径是不一样的。同时我们只让 libhello.so 存在于 /home/wyl/test/libtest/lib2 中,另外两个目录下不放 libhello.so。

使用 LD_DEBUG 的打印信息如下,从打印信息可以看出来:

(1)首先查找的路径是 LD_LIBRARY_PATH 中的路径

(2)LD_LIBRARY_PATH 路径找不到,从 rpath 选项中的路径查找

(3)rpath 路径找不到,则从 /etc/ld.so.cache 中查找,该文件中保存的就是配置在 /etc/ld.so.conf.d/ 中配置的目录下的动态库

  • 29
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值