一、背景
我们使用Linux的过程中,例如安装程序或者部署一些如Python等,可能会遇到过如下动态链接库(共享库)报错:
ImportError: libcrypto.so.10: cannot open shared object file: No such file or directory
$"./lib/python3.8/lib/python3.8/ssl.py", line 98, in <module> import _ssl
# if we can't import it, let the error propagate ImportError:
libcrypto.so.10: cannot open shared object file: No such file or directory
例如这里的是报错,libcrypto.so.10 动态库没找到.
那我们来分析一下,Linux动态链接库的一个查找过程是怎么样的。为什么说没找到这个文件呢? 寻找的过程是怎么样的
二、动态链接库、共享库
1、定义
在 Linux 系统中,动态链接库(Dynamic Link Library)和共享库(Shared Library)是指同一概念的不同称谓,通常指的是 .so(shared object)文件。这类库在 Linux 和其他类 Unix 操作系统中非常常见,用于实现程序的模块化和资源的共享。
动态链接库/共享库 是一种二进制文件,其中包含了一组预先编译好的函数和数据结构,可以被多个不同的程序共享。这些库通常在程序运行时被加载,并且可以被多个进程同时使用。
在 Linux 中,动态链接库通常以 .so
扩展名命名,例如 libfoo.so
。这个扩展名表明这是一个共享对象文件,它可以被动态链接器加载。
Redhat系列一般存放于: /usr/lib/、/usr/lib64/ , 同时 / 下存在lib和lib64的软链接到/usr/lib、/usb/lib64/
Linux中命名系统中共享库的规则:
如文章开头缺失的共享库的名称就是crypto
2、寻找so动态链接库的过程
1、首先查找当前环境中,环境变量LD_LIBRARY_PATH路径(多路径使用:分隔,和定义PATH环境变量路径一样),依次遍历,查找是否存在libcrypto.10.so这个文件,存在则读取,停止搜索,否则继续往下执行
2、查找/etc/ld.so.cache已经缓存好的所有so动态库的路径,查看是否存在里面。存在则加载,否则查找so文件失败,程序报错. 我看可以看看/etc/ld.so.cache是什么东西? 这个是ldconfig根据/etc/ld.so.conf配置文件配置的共享库查找路径,预先查找到所有的so,记录了这些so的绝对路径形成的一个列表二进制文件(不能直接用cat打开, 使用strings打开查看内容).例如我们使用strings查看/etc/ld.so.cache文件内容:
ld.so.cache文件缓存好了查找/etc/ld.so.conf配置好的搜索动态库路径搜索到所有so的绝对路径。
这样应用程序查找的时候就没必要再次全量扫描/etc/ld.so.conf的路径下有没有对应的so了,直接从/etc/ld.so.cache匹配一下,效率更高、查找速度更快。
3、ldconfig、LD_LIBRARY_PATH、ldd命令的用处
1、ldconfig命令,重新生成/etc/ld.so.cache缓存
1、直接执行ldconfig会重新生成/etc/ld.so.cache缓存文件,一般用于,新添加了/etc/ld.so.conf搜索so的路径,需要重新生成缓存
2、ldconfig -p 查看当前缓存so路径内容, 类似strings /etc/ld.so.cache的效果
2、LD_LIBRARY_PATH 环境变量
ldconfig适用于全局的so查找路径。 但是因为作为全局,一般兼容性高,很少存在版本冲突问题。 如果我们应对的是相同的共享库,但是是这个共享库的不同版本。 例如我的A程序依赖于ssl的v1版本,但是系统依赖的是ssl的v2版本等等。 这就蛋疼了, 那这个ssl库保留哪个版本呢? 单独保留某一个版本,都无法满足需求。 要操作系统依赖的存在问题、要么应用程序存在问题。
所以,Linux提供给我们这个LD_LIBRARY_PATH环境变量,就是解决这种多版本问题。 可以作为临时设置so查找的路径,这样可以避免版本冲突以及查找优先级.
例如设置export LD_LIBRARY_PATH=/my/v1/:$LD_LIBRARY_PATH, 先把自己A程序查找共享库的路径放到前面,其它放在后面,那么一旦从我们的v1找到,就停止搜索了,后面v2的ssl.so就不会被搜索到了.
1、提高so共享库查找的优先级
2、可以解决版本冲突问题
3、ldd命令,查看一个二进制命令依赖共享库的信息
有时候我们关于共享库报错,那么我们想看下这个二进制是缺的什么共享库,用到了哪些共享库。 可以使用 ldd $程序二进制绝对路径查看,例如查看ssh命令的共享库依赖:
从ldd结果,如果某些库找不到,那么我们需要通过yum或者其他方式安装对应这个库依赖即可解决问题
4、回到案例,排查结果
我们知道了动态库的原理,那么针对文章开头的地方,我们去看了一下确实存在问题。 libcrypto.so.10软连接指向的源文件,路径搞错了,导致找不到文件:
源文件路径多了空格,并且源文件路径不存在。 导致应用程序查找到了.so,但是无效的软链接,所以报错。
三、总结
下次遇到动态链接库报错、多版本的so共享库不必慌张,原理就是如此。希望对大家有所帮助!