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文件就可以准确定位,可以使用相同的编译和连接命令,使得编译和连接界面统一.

提示

编译软件时如果出现找不到所依赖的动态库时都全靠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

注意

上面的输出结果默认是会去查找/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

提示

上面的命令的前提是在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文件。

提示

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.confetc/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

上次更新:
贡献者: iEchoxu