定位库文件包括两个方面:
- 在程序构建时,需要知道所依赖库的位置及头文件。
- 在程序运行时,需要知道所依赖库的位置,只针对动态库。
只有动态库在程序运行时加载,静态库是构建时就已经链接到程序中。
在构建过程中定位库
静态库的命名规则
lib + library name +.a
library name
才是静态库实际的名字,比如libtest.a
,库名为test
。
动态库的命名规则
lib + library name + .so + library version information
动态库相比静态库多了库的版本信息,指定了版本信息后,库名一样版本不同也是不同的库,因为包含的符号不同。经常遇见依赖多个不同版本的动态,版本号是区分这些库的重要方式。
库的实际名字也是library name
。
在构建时不管是依赖的静态库还是动态库,指定所依赖的库的路径都是一致的,通过通过-L
和-l
选项来指定构建过程中库文件的路径。
gcc main.o -L../lib -ltestlib -o test
-L
是指定库的目录,-l
是指定库名就是库的实际名字,-ltestlib
对应的库为libtestlib.so或libtestlib.a
-L
告诉编译器用于定位库的目录。-l
对于动态库,指定的库名还会写入最终生成的执行文件,在程序运行时,加载器会查找指定的库,但是定位库的规则就不是按-L
的规则了。
-l
后面也可以跟路径+库名的方式,比如:
gcc main.o -l/home/test/lib/libtestlib.so -o test
但是这种方式,-l
后面的内容会全部写入执行文件,在程序运行时,加载器会按照固定的位置/home/test/lib/libtestlib.so
加载动态库。如果编译机与运行机不一样,那么就会因为找不到库而运行失败。
运行时动态库的定位规则
按照优先级的如下规则:
LD_LIBRARY_PATH
ld.so.cache
- 默认库路径(/lib/和/usr/lib等)
动态库的定位,还有更高优先级的rpath
和runpath
,这两个值会被写入动态库或执行程序ELF文件。但是这个两个配置的决策过程比较复杂,并且还面临着gcc版本不同处理方式不同的问题。所以这里没有列出它们。通常我们使用LD_LIBRARY_PATH
和ldconfig
就足以。
LD_LIBRARY_PATH
设置环境变量LD_LIBRARY_PATH
是我们在开发过程中经常使用的方式,但这并不是标准方式,通常临时验证下程序的正确性,可以配置该环境变量,如下:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:动态库目录
ld.so.cache
ld.so.cache
是加载器(ld.so
或ld-linux.so
)的定位库目录的缓存文件。可以通过ldconfig
工具更新它。
一种标准的代码部署过程是基于ldconfig
工具,它通常是包安装过程中的最后一步,通常需要将指向包含库目录的路径作为出输入参数传递,将其写入ld.so.cache
文件,保证加载器能定位到所依赖的库。
ldconfig creates the necessary links and cache to the most recent shared libraries found in the directories specified on the command line, in the file /etc/ld.so.conf, and in the trusted directories (/lib and /usr/lib).
ldconfig
会搜索指定的目录,/etc/ld.so.conf
,系统库默认目录/lib
,/usr/lib
。将其中库的路径信息写入/etc/ld.so.cach
,它被链接器(ld.so
或ld-linux.so
)用于查找依赖库。
ldconfig
还有一个重要的功能是更新动态库的版本,这个会在后面的文件详细介绍。
所以当我们需要定位我们自己的所依赖的库时,可以将目录直接写入/etc/ld.so.conf
中,但是/etc/ld.so.conf
通常是如下内容:
cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
**include ld.so.conf.d/*.conf**
表示包含了**/etc/ld.so.conf.d/**
目录下所有文件,所以我们通常是在该目录下建立一个包含所依赖库目录的conf文件。
#ls -lrt /etc/ld.so.conf.d/
-rw-r--r-- 1 root root 19 8月 9 2019 dyninst-x86_64.conf
-rw-r--r-- 1 root root 17 4月 3 2020 mariadb-x86_64.conf
-rw-r--r-- 1 root root 26 6月 1 2020 bind-export-x86_64.conf
-r--r--r-- 1 root root 63 8月 26 2020 kernel-3.10.0-1127.19.1.el7.x86_64.conf
#ldconfig
再通过ldconfig
让其更新目录到/etc/ld.so.cach
文件中,可以通过ldconfig -p
查看cach中缓存的动态库及其路径信息,确认是否已经写入(ldconfig -p | grep 依赖的动态库
)。