工作时遇到了一个奇的问题。手动创建某个so
符号链接似乎不能被ldconfig
识别。
事情的起因为是这样的,我有一个程序P,通过ldd
检查,它明确依赖libcrypto.so.1.0.0
,我的系统中只有这几个so
:
libcrypto.so
libcrypto.so.1.1
libcrypto.so.1.1.1k
所以最开始的想着建立一个符号链接就可以了,因为我在系统中只有libcrypto.so.1.0.2k
的时候成功过。所以我在/lib64
目录中创建了一个符号链接:
[root@localhost certus]# ll /lib64/ | grep libcrypto
lrwxrwxrwx. 1 root root 19 Dec 18 2023 libcrypto.so -> libcrypto.so.1.1.1k
lrwxrwxrwx. 1 root root 26 Sep 23 05:17 libcrypto.so.1.0.0 -> /lib64/libcrypto.so.1.1.1k
lrwxrwxrwx. 1 root root 19 Dec 18 2023 libcrypto.so.1.1 -> libcrypto.so.1.1.1k
-rwxr-xr-x. 1 root root 3087888 Dec 18 2023 libcrypto.so.1.1.1k
然后这样并没有达到预期效果,我的程序P无法运行。我知道这个应该是版本太高的原因。
所以我从其它机器上复了较低版本libcrypt.so.1.0.2k
,然后给它创建了符号链接libcrypt.1.0.0
,最后运行一下程序,发现可以正常运行。本来事情到这里就可以结束了。但是我觉得直接在系统的/lib64
目录中新文件的方式不太好,不如单独指定一个目录,然后通过ldconfig
来更新依赖库。于是我就遇到了一个困扰我一天的问题。
操作流程如下:
- 新建一个目录
/usr/local/lib64/foo
- 将
libcrpyto.so.1.0.2k
复制到/usr/local/lib64/foo
目录中 - 将
libcrypto.so.1.0.0
符号链接复制到/usr/local/lib64/foo
目录中 - 新建一个
ldconfig
配置文件/etc/ld.so.conf.d/foo.conf
,内容为:/usr/local/lib64/foo
- 执行
ldconfig
命令。
操作完上述流程后,我再次运行我的程序P,发现依然找不到libcrypto.so.1.0.0
。那么为什么/usr/local/lib64/foo
目录中的libcrypto.so.1.0.0
这个符号没有被找到呢?通过ldconfig -v
查看,发现ldconfig
根据libcrypto.so.1.0.2k
生成了libcrpyto.so.10
这个符号,而这个符号是可以被识别的。而我自己手动创建的符号libcrypto.so.1.0.0
却不能工作。我猜测肯定是有什么原因导致ldconfig
没有识别我的符号链接。于是我又偿试不用符号链接,直接把libcrypt.so.1.0.2k
重命名成libcrypto.so.1.0.0
,但是这样依然不能生效。
通过调试,发现search cache=/etc/ld.so.cache
里面就没有libcrypto.so.1.0.0
:
LD_DEBUG=libs /path/to/progP
后来我在/lib64
目录中创建符号链接libcrypto.so.1.0.0
,这里的符号是可以被程序P找到的。
搜索了很多资料,也没有发现有什么能解释这个问题的。问了chatgpt
,它跟我扯了一堆没用的,什么lib命名问题,权限的问题,优先级问题等等,都没有解决问题。
后来我想了一下,应该是和ldconfig
的机制有关,想去看看ldconfig
的源码,发现一时半会儿也理不清,就放弃了。但是我注意到ldconfig
会根据libcrypto.so.1.0.2k
自动生成符号链接libcrypto.so.10
,为什么ldconfig
自己生成的符号有效,而我手动创建的符号无效?我猜测ldconfig
在搜索目录时,可能只会处理目录中有效的SONAME
,我重新编译了一个 libcrypto.so.1.0.0
,然后放入/usr/local/lib64/foo
目录中,这次运行ldconfig
就能识别这个库了。
经过上述偿试,我最终猜测ldconfg
处理lib库的机制是:
ldconfig
遍历指定的目录,只搜索不是符号链接的lib*.so*
文件。- 从对应的
lib*.so*
文件提取SONAME
如果有SONAME
,那么就根据SONAME
创建对应的符号链接,如果SONAME
与文件名同名,则不用创建。把对应的SONAME
加入ld.so.cache
。如果没有SONAME
,那么就把该库本身加入ld.so.cache
。
这样就可以解释两点:
- 直接在
/usr/local/lib64/foo
中手动创建符号链接不生效:因为ldconfig
不处理符号链接。 - 将
libcrypto.so.1.0.2k
改名成libcrypto.so.1.0.0
不生效:因为ldconfig
会根据libcrypto.so.1.0.0
中的SONAME
生成对应的符号链接libcrypt.so.10
所以只会把libcrypto.so.10
加入ld.so.cache
。
至于为何直接在 /lib64
中手动创建符号可以生效,我猜测这个和 ldconfig
没有关系,因为 /lib64
是进程默认的 so
加载路径。所以可以直接找。通过 LD_LIBRARY_PATH
也可以指定程序搜索对应目录的 so
文件,也同样不需要 ldconfig
的参于。