Linux出错error while loading shared libraries:提示找不到xx.so文件

青山 2021-11-3014:15:38
评论
2734字

在Linux服务器上,应该会有很多人遇到过这种问题吧,在我们编译文件的时候,提示错误:“error while loading shared libraries:提示找不到xx.so文件”,对于一些新手来说,xx.so文件是什么文件可能都不知道是什么,那么xx.so文件是什么?有什么用?如何解决找不到xx.so文件。下面就来给大家科普下。

Linux出错error while loading shared libraries:提示找不到xx.so文件

xx.so文件相当与windows上的dll文件,也就是常说的动态链接库。动态链接库是为了减少发布程序的大小,可以将具有相同功能的code放在动态链接库中,随应用程序一起发布。而对于应用程序来说,只需要知道其接口就可以,在运行时动态的加载代码到内存中,与其相反的是静态链接库。

我们在编译的时候提示的错误如下:

baiyang@baiyang-Lenovo-G450:~/Desktop$ ./test_cal_features
./test_cal_features: error while loading shared libraries: libCGAL.so.5: cannot open shared object file: No such file or directory

分析原因:

1.为何能通过编译与链接,却不能运行?

2.我明明将libCGAL.so.5,安装到了/usr/local/lib下啊,既然能通过编译与链接,应该能找到啊?

3.执行./test_cal_features时,到底发生了什么事?

4.linux下,应用程序如何对.so进行搜索?

我们来举一个新的例子

新建一个plus.c 文件

int plus(int a, int b)  
{  
    return a + b;  
}

将其编译成动态链接库

gcc plus.c -o libfoo.so -shared -fPIC

这时候会产生动态链接库libfoo.so,然后我们再写一个main.c文件

#include <stdio.h>  
#include <stdlib.h>  
  
int main(int argc, char *argv[])  
{  
    int sum = plus(3, 5);  
    printf("%d\n", sum);  
  
    return 0;  
}

到这里,我们需要考虑应该如何存放libfoo.so位置?

我们先将libfoo.so存放在当前目录中,进行编译和链接

gcc main.c -o output -lfoo //-lfoo告诉gcc,我们需要动态链接foo库。

编译好会出现下面代码

baiyang@baiyang-Lenovo-G450:~/workspace/test_so$ ls
libfoo.so  main.c  plus.c
baiyang@baiyang-Lenovo-G450:~/workspace/test_so$ gcc main.c -o main -lfoo
/usr/bin/ld: cannot find -lfoo
collect2: ld returned 1 exit status

这里的提示意思是:gcc不能找到foo库,那么我们如果显示的指示gcc如何搜寻foo呢,我们可以修改LIBRARY_PATH值。

baiyang@baiyang-Lenovo-G450:~/workspace/test_so$ export LIBRARY_PATH="."
baiyang@baiyang-Lenovo-G450:~/workspace/test_so$ gcc main.c -o main -lfoo
baiyang@baiyang-Lenovo-G450:~/workspace/test_so$ ls
libfoo.so  main  main.c  plus.c

修改过我们会发现找到了。

如果此时我们再次运行代码

baiyang@baiyang-Lenovo-G450:~/workspace/test_so$ ./main
./main: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory

会发现还是遇到开始提到的问题了,那我们怎么看输出到可执行文件main怎么读取libfoo.so呢,在运行过程中到底读的什么文件呢?

这里我们用strace命令来查看到底有什么信号发生

strace ./main

运行后发现它搜索到路径是/lib/i386-linux-gnu,/usr/lib等路径目录下,也就说,是因为没有搜索当前目录,我们继续用以下命令进行修改

baiyang@baiyang-Lenovo-G450:~/workspace/test_so$ export LD_LIBRARY_PATH=".":$LD_LIBRARY_PATH
baiyang@baiyang-Lenovo-G450:~/workspace/test_so$ ls
libfoo.so  main  main.c  plus.c
baiyang@baiyang-Lenovo-G450:~/workspace/test_so$ ./main
8

成功运行,用strace查看存在这一句open(“./libfoo.so”, O_RDONLY|O_CLOEXEC) = 3,现在搜索了当前目录。

总结:

LIBRARY_PATH 该环境变量可设置为一个或多个目录名字列表,连接 程序会搜寻该目录,以查找特殊连接程序文件,和由 -l (字母 l )命令行选项指定名字的库。由 -L 命令行选项指定的目录在环境变 量的前面,首先被查找。也见 COMPILER_PATH 。

LD_LIBRARY_PATH 该环境变量不会影响编译程序,但程序运行的时 候会有影响。变量指定一个目录列表,程序会查找该列表定位共享库。 只有当未在编译程序的目录中找到共享库的时候,执行程序必须设置该变量。

动态库的搜索路径搜索的先后顺序是:

1 编译目标代码时指定的动态库搜索路径,LIBRARY_PATH【编译阶段】;

2 在运行时,环境变量LD_LIBRARY_PATH指定的动态库搜索路径【运行阶段】;

3 配置文件/etc/ld.so.conf中指定的动态库搜索路径【编译阶段】;

4 默认的动态库搜索路径/lib【编译阶段】;

5 默认的动态库搜索路径/usr/lib【编译阶段】。

对二进制文件进行处理

strace/gdb/objdump/nm这几个工具,都可以让你查看二进制文件到底干了什么,比如,我们用objdump可以查看可执行文件需要什么链接库。

baiyang@baiyang-Lenovo-G450:~/workspace/test_so$ objdump -x main | grep NEED
NEEDED libfoo.so
NEEDED libc.so.6
VERNEED 0x08048354
VERNEEDNUM 0x00000001

匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: