Linux库文件查找路径探索
Linux 库文件查找路径,让你不再为此困惑。
描述
相信很多人在Linux上编译或者运行程序时都会碰到如下两个问题:
通过源代码编译程序时出现的找不到某个依赖包
运行的时候说“error while loading shared libraries: libxxx.so.y: cannot open shared object file: No such file or directory”
问题一:
编译软件都是通过configure
工具来生成Makefile文件再通过gcc进行编译,在configure过程中需要检查相应依赖环境时(例:所依赖软件的版本、相应库版本等),通常会通过pkg-config的工具来检测相应依赖环境。
pkg-config是通过库提供的一个.pc文件获得库的各种必要信息的,包括版本信息、编译和连接需要的参数等。需要的时候可以通过pkg-config
提供的参数(–cflags, –libs),将所需信息提取出来供编译和连接使用。这样,不管库文件安装在哪,通过库对应的.pc文件就可以准确定位,可以使用相同的编译和连接命令,使得编译和连接界面统一.
TIP
编译软件时如果出现找不到所依赖的动态库时都全靠PKG_CONFIG_PATH
pkg-config作用
1:检查库的版本号。如果所需要的库的版本不满足要求,它会打印出错误信息,避免链接错误版本的库文件。
2:获得编译预处理参数,如宏定义,头文件的位置。
3:获得链接参数,如库及依赖的其它库的位置,文件名及其它一些连接参数。
4:自动加入所依赖的其它库的设置。
事实上,为了让pkg-config可以得到这些信息,要求库的提供者,提供一个.pc文件
获取.pc文件的位置
第一种:取系统的/usr/lib/pkgconfig
下的所有*.pc文件。
第二种:在默认情况下,每个支持 pkg-config 的库对应的.pc文件在安装后都位于安装目录中的lib/pkgconfig目录下,如用户新安装的软件的.pc文件都在/usr/local/lib/pkgconfig/
目录下,但需要将此目录添加到PKG_CONFIG_PATH
环境变量,这样才能让系统找到它.
查看现有可用的.pc文件:
pkg-config –list-all
WARNING
上面的输出结果默认是会去查找/usr/lib/pkgconfig
下所有的.pc文件并显示出来,如果你设置了PKG_CONFIG_PATH
环境变量,那也会包含PKG_CONFIG_PATH
环境变量设置的路径下的所有.pc文件,否则则不显示.
下面以libtcmalloc.pc文件介绍下pc文件:
[echoxu@mysql pkgconfig]$ more libtcmalloc.pc
prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: gperftools
Version: 2.7
Description: Performance tools for C++
URL: http://code.google.com/p/gperftools/
Requires:
Libs: -L${libdir} -ltcmalloc
Libs.private: -pthread -lpthread
Cflags: -I${includedir}
安装libtcmalloc时会将头文件安装在/usr/local/include
目录下,而库文件会安装在/usr/local/lib
下,.pc文件会安装在/usr/local/lib/pkgconfig
目录下.
pkg-config --cflags libtcmalloc
可以查看到头文件的位置
pkg-config --libs libtcmalloc
可以查看库文件的位置
当然也可以将--libs和--cflags同时使用:
pkg-config --cflags --libs libtcmalloc
TIP
上面的命令的前提是在pkg-config –list-all
里可以查到libtcmalloc.
添加自建的.pc文件
把你的pc文件,直接放到/usr/lib/…默认路径下。
把你的pc文件的路径写到PKG_CONFIG_PATH环境变量里。
比如,你可以在/etc/.bashrc或者/home/chenxf/.bashrc的文件末尾添加:
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/home/echoxu/gpeftools/lib/pkgconfig
export PKG_CONFIG_PATH
那么,pkg-config就会到/home/echoxu/gpeftools/lib/pkgconfig
寻找*.pc文件。
我猜你想问,那我这个pc文件何时生效呢?
答案是,如果是/usr/lib下,立马生效!!!如果在环境变量里,只要先source ~/.bashrc
一下,让环境变量生成,也立马生效。
并不需要什么pkg-config update啥命令,让其更新信息。
其实每次你执行pkg-config,都会去遍历所有的*.pc文件。
TIP
PKG_CONFIG_PATH所指定的路径优先级比较高,pkg-config会先进行搜索,完了之后才是去搜索缺省路径
这样再用configure编译时就不会报错了.
看着上面写了那么多是不是还有些困惑?只要记住编译软件时如果出现找不到所依赖的动态库时都全靠PKG_CONFIG_PATH
。
程序运行时出现libxxx.so.y => not found
我们先来讲讲Linux上的库文件:
库文件种类
静态库:
静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。
静态库的后缀是.a,它的产生分两步:
Step 1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表
Step 2.ar命令将很多.o转换成.a,成为静态库
共享库(动态库):
共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。
动态库的后缀是.so,它由gcc加特定参数编译产生。
库文件查找顺序
程序读取库文件默认先从/etc/ld.so.cache
中查找所需的库文件,如果缓存中没有就去/etc/ld.so.conf
及etc/ld.so.conf.d/
中搜索
当库文件不在标准库文件目录(/usr/lib
、/lib
、/lib64
及/usr/local/lib
)时,一定要在/etc/ld.so.conf或者etc/ld.so.conf.d/中添加库文件所在的路径.然后执行ldconfig -v生成库文件缓存.
/lib、/usr/lib/、/usr/local/lib区别
/lib是内核级的,/usr/lib是系统级的,/usr/local/lib是用户级的
/lib目录下放置的是/bin和/sbin目录下系统程序所需的库文件
/usr/lib/目录下含有更多用于用户程序的库文件
/usr/local/lib目录下是户自己特定的的库文件。不用担心会被系统升级之类的行为覆盖,破坏
查看可执行程序依赖的库
ldd命令可以查看一个可执行程序依赖的共享库,下面以libtcmalloc.so为例查看其依赖哪些库文件:
[echoxu@mysql lib]$ ldd libtcmalloc.so
linux-vdso.so.1 => (0x00007ffd331cf000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f0e22670000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f0e22369000)
libm.so.6 => /lib64/libm.so.6 (0x00007f0e22066000)
libc.so.6 => /lib64/libc.so.6 (0x00007f0e21ca3000)
/lib64/ld-linux-x86-64.so.2 (0x0000558dfb593000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f0e21a8d000)
添加非默认存储路径下的库文件
设置库文件的搜索路径有下列两种方式,可任选其一使用:
在环境变量
LD_LIBRARY_PATH
中指明库的搜索路径,不需要root权限.一般在
/etc/ld.so.conf.d/gpeftools.conf
文件里添加库文件的真实路径而不直接添加在/etc/ld.so.conf
里,需要root权限.(推荐)
再详细介绍下第二种方法:
为了使得动态链接库可以被系统使用,当我们修改了/etc/ld.so.conf
或/etc/ld.so.conf.d/
目录下的任何文件,或者往那些目录下拷贝了新的动态链接库文件时,都需要运行一个很重要的命令:ldconfig
,该命令位于/sbin目录下,主要的用途就是负责搜索/lib和/usr/lib,以及配置文件/etc/ld.so.conf
里所列的目录下搜索可用的动态链接库文件,然后创建处动态加载程序/lib/ld-linux.so.2所需要的连接和(默认)缓存文件/etc/ld.so.cache
(此文件里保存着已经排好序的动态链接库名字列表)。
也就是说:当用户在某个目录下面创建或拷贝了一个动态链接库,若想使其被系统共享,可以执行一下"ldconfig目录名"这个命令。此命令的功能在于让ldconfig将指定目录下的动态链接库被系统共享起来,即:在缓存文件/etc/ld.so.cache中追加进指定目录下的共享库。请注意:如果此目录不在/lib,/usr/lib及/etc/ld.so.conf文件所列的目录里面,则再次单独运行ldconfig时,此目录下的动态链接库可能不被系统共享了。单独运行ldconfig时,它只会搜索/lib、/usr/lib以及在/etc/ld.so.conf文件里所列的目录,用它们来重建/etc/ld.so.cache。
因此,我们自己开发的共享库就可以将其拷贝到/lib、/etc/lib目录里,又或者修改/etc/ld.so.conf文件将我们自己的库路径添加到该文件中,再执行ldconfig命令。
- 实战:添加gpeftools库文件
echo /usr/local/lib > /etc/ld.so.conf.d/gpeftools.conf
sudo ldconfig
第一种方法不推荐,记住: 不要在生成环境的.bash_profile里添加LD_LIBRARY_PATH