解决有关链接的诸多问题
这篇文章主要记录在 linux 环境下,在编译或者执行程序的时候库找不到的问题。
编译时候的链接问题
编译时候遇到的问题多是某名称找不到的问题,对于这种问题只需要在库的搜索路径里补上一个名称就行了,这个时候对库的版本没有要求,库的版本只决定了运行时候的行为。
动态链接库路径搜索过程
在程序执行并进行动态链接的时候,ld.so 程序会按照一定的规则进行动态链接库的查找。使用 man ld.so 8
查看这个规则,总结得到如下的查找规则,按照先后的顺序排序如下:
- 对于直接以
/
形式给出的路径,直接按照这个路径去找。 - 首先查找环境变量
LD_LIBRARY_PATH
,这之中的路径会被指定为库的搜索路径。 - 查看 ELF 文件中的
DT_RUNPATH
,被DT_NEEDED
指定的库会到DT_RUNPATH
给定的路径中去查找。 - 到
/etc/ld.so.cache
中去查找。/etc/ld.so.cache
是一个 kv cache,记录库名称到库具体路径的映射,这个 cache 由 ldconfig 生成。 - 到默认的
/lib
和/usr/lib
中进行查找。
这就是整个查找流程,这个流程中并不包含 /usr/local/lib
,要实现这个路径的搜索要满足2设置环境变量,或在合适的时刻通过 ldconfig 将这个路径中的库更新到 kv cache 中。
ldconfig 命令
官方对这个命令的解释是对于动态链接运行时绑定的配置,简单的来讲,它就是 /etc/ld.so.cache
的维护者,调用 ldconfig,能够更新 /etc/ld.so.cache
的信息。那么ldconfig 将哪些路径下的库信息加入到 cache 中呢。这是由 /etc/ld.so.conf
这个文件决定的,这个文件中包含了许多路径,ldconfig 会到其指定的路径中进行搜索,对于能够推断其版本的库,它会将其加到 cache 中,形成类似于 xxx.so.16 -> /usr/local/lib/xxx.so.16
这样的kv,供前面动态链接程序进行查找。
ldconfig 在某些时刻会主动更新,比如开机的时候或者用 apt 安装包的时候,我们自己把库装到 /usr/local/lib
下的时候,ldconfig 并不会主动执行,因此某些时候我们需要主动进行 sudo ldconfig
来进行对于 cache 的刷新。
ldd 命令
ldd 命令,官方的解释是打印共享库的依赖关系。给定 ldd 一个文件,他能够打印出文件需要用到的库以及目前系统从哪里寻找这些库。这对于编程人员来说是极好的消息,根据此编程人员就能知道代码中调用的库其对应的版本到底是什么。同时系统找不到某些库,通过 ldd,我们也能够知道系统到底是找不到哪些库,哪些库的名称叫什么,我们能够通过在执行的位置建立软链接来解决找不到库的问题。
运行时候的问题
运行时候找不到库的问题可以使用 ldd 进行排查。有时候我们知道了哪些没装,并通过手动的方式安装上了,我们还是要面临手动安装库的路径并不在系统的路径搜索范围内,也还没更新到 cache 中,这就造成了我实际上已经安装了某个库,但是为什么系统还是找不到,我认为有两种解决方案。
- 临时的设置
LD_LIBRARY_PATH
值,即在 shell 中直接 export 的方式,这种方式简单,但是很容易对别的库的搜索产生影响,而导致其他错误。 - 更改
/etc/ld.so.cache
文件并进行 ldconfig,这是比较好的方式。