工作时遇到了一个奇的问题。手动创建某个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 的参于。
