关于pkg-config与LD_LIBRARY_PATH与/etc/ld.so.conf文件的区别与作用

Linux 共享库

  Linux 系统上有两类根本不同的 Linux 可执行程序。

1. 第一类是静态链接的可执行程序。

  静态可执行程序包含执行所需的所有函数。因为这一原因,静态可执行程序不依赖任何外部库就可以运行。

2. 第二类是动态链接的可执行程序。

动态库是程序在

关于动态库设置的问题

通过源码包安装程序时,主要用到了“三大步”策略:configure、make和make install 。在安装的configure阶段,为了检测安装安装环境是否满足,通常情况下都是通过一个叫做pkg-config的工具来检测它需要依赖的动态库是否存在.

一般当我们安装完某个程序后,如果它提供了动态库的功能,在源码中都会有一个或多个以pc结尾的文件,当执行完make install后这些pc文件拷贝到${prefix}/lib/pkgconfig这个目录里,这里的prefix就是我们在configure阶段时通过配置参数–prefix指定的,缺省情况这个值就是/usr/local,所以这些pc文件最终会被拷贝到/usr/local/lib/pkgconfig目录下。

如果找不到某个库该怎么办。前提是你确确实实已经安装了它需要的库,原因只有一个,pkg-config找不到这个与这个库对应的pc文件。为什么会找不到呢,原因又有两点:
1. pkg-config搜索了所有它认为合适的目录都没找着这个库对应的pc文件的下落;
2. 这个库在发布时根本就没有提供它的pc文件。

pkg-config的查找路径是哪里?

pkg-config较老的版本里,缺省情况下会到/usr/lib/pkgconfig、/usr/loca/lib/pkgconfig、/usr/share/pkgconfig等目录下去搜索pc文件,据我所知在0.23以及之后的版本里pkg-config的源码里已经没有关于缺省搜索路径的任何硬编码的成分了,至于具体从哪个版本开始我也没有去追究,还望有知道的朋友分享一下。取而代之的是,当你看pkg-config的man手册时会有下面一段话:

pkg-config retrieves information about packages from special metadata files. These files are named after the package, with the extension .pc.
By default, pkg-config looks in the directory prefix/lib/pkgconfig for these files; it will also look in the colon-separated (on Windows, semicolon-separated) list of directories specified by the PKG_CONFIG_PATH environment variable.

以及

PKG_CONFIG_PATH
A colon-separated (on Windows, semicolon-separated) list of directories to search for .pc files. The default directory will always be searched after searching the path; the default is

${libdir}/pkgconfig and ${datadir}/pkgconfig

上面提到的prefix、libdir和datadir,就是安装pkg-config时被设定好的,具体情况是:
1、如果你是通过yum和rpm包安装的
prefix=/usr
libdir= prefix/lib=/usr/libdatadir= {prefix}/share=/usr/share
2、如果你是通过源码包安装的,且没有指定prefix的值(指定的情况同1)
prefix=/usr/local
libdir= prefix/lib=/usr/local/libdatadir= {prefix}/share=/usr/local/share

pkg-config在查找对应软件包的信息时的缺省搜索路径已经很清楚了. 如果你软件包对应的pc文件都不在这两个目录下时,pkg-config肯定找不到。既然原因都已经找到了,那解决办法也就多种多样了。

方案一:

我们可以在安装我们那个被依赖的软件包时,在configure阶段用–prefix参数把安装目录指定到/usr目录下;

方案二:

也可以按照上面说的,通过一个名叫PKG_CONFIG_PATH的环境变量来向pkg-config指明我们自己的pc文件所在的路径,不过要注意的是PKG_CONFIG_PATH所指定的路径优先级比较高,pkg-config会先进行搜索,完了之后才是去搜索缺省路径。
前者的优点是以后再通过源码安装软件时少了不少麻烦,缺点是用户自己的软件包和系统软件混到一起不方便管理,所以实际使用中,后者用的要多一些。

在用户的家目录下的.bash_profile文件里或系统文件/etc/profile的末尾添加上面一行也成,都可以。我的如下:
关于pkg-config与LD_LIBRARY_PATH与/etc/ld.so.conf文件的区别与作用_第1张图片
至此,动态库查找问题的第一种情况就彻底解决了。

程序运行时出现libxxx.so not found

这种情况,用配置文件或者“ldconfig 动态库所在路径”的方式解决,这是针对有root权限的用户的解决办法。没有root权限运行软件时,Linux也为我们提供了一个名为LD_LIBRARY_PATH的环境变量来解决运行时动态库查找路径的解决方案。同样地,由这个环境变量所指定的路径会被装载器/lib/ld-2.12.so优先查找,然后才是动态库库缓存文件/etc/ld.so.cache,所以LD_LIBRARY_PATH优先查找,其次才是/etc/ld.so.cache。


PKG_CONFIG_PATH和LD_LIBRARY_PATH

1. /etc/ld.so.conf文件

是动态库载入器而不是连接器,换句话说,配置ld.so.conf的作用就是如果.so文件在非标准路径,可执行文件能够找到,这是运行期做的事情
如果现在是编译,ld.so根本不起作用,所有用非标准路径的话必需手动指定库目录

2. PKG_CONFIG_PATH变量

从字面意思上翻译,就是“软件包的配置路径”,编译软件时如果出现找不到所依赖的动态库时都全靠PKG_CONFIG_PATH了;

2. LD_LIBRARY_PATH

“装载器的库路径”,LD是Loader的简写,在Linux系统启动一个程序的过程就叫做装载,一个程序要执行时它或多或少的会依赖一些动态库(静态编译的除外)。当你用“ldd 可执行程序名”查看一个软件启动时所依赖的动态库,如果输出项有“libxxx.so not found”一项,你这个软件肯定运行不起来。



静态可执行程序与动态可执行程序比较

  我们可以用 ldd 命令来确定某一特定可执行程序是否为静态链接的:
  # ldd /sbin/sln
  not a dynamic executable
  “not a dynamic executable”是 ldd 说明 sln 是静态链接的一种方式。现在,让我们比较 sln 与其非静态同类 ln 的大小:
  # ls -l /bin/ln /sbin/sln
  -rwxr-xr-x 1 root root 23000 Jan 14 00:36 /bin/ln
  -rwxr-xr-x 1 root root 381072 Jan 14 00:31 /sbin/sln
  如您所见,sln 的大小超过 ln 十倍。ln 比 sln 小这么多是因为它是动态可执行程序。动态可执行程序是不完整的程序,它依靠外部共享库来提供运行所需的许多函数。
  动态链接相关性
  要查看 ln 依赖的所有共享库的列表,可以使用 ldd 命令:
  # ldd /bin/ln
  libc.so.6 => /lib/libc.so.6 (0x40021000)
  /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
  如您所见,ln 依赖外部共享库 libc.so.6 和 ld-linux.so.2。通常,动态链接的程序比其静态链接的等价程序小得多。不过,静态链接的程序可以在某些低级维护任务中发挥作用。例如,sln 是修改位于 /lib 中的不同库符号链接的极佳工具。但通常您会发现几乎所有 Linux 系统上的可执行程序都是某种动态链接的变体。
  动态装入器
  那么,如果动态可执行程序不包含运行所需的所有函数,Linux 的哪部分负责将这些程序和所有必需的共享库一起装入,以使它们能正确执行呢?答案是动态装入器(dynamic loader),它实际上是您在 ln 的 ldd 清单中看到的作为共享库相关性列出的 ld-linux.so.2 库。动态装入器负责装入动态链接的可执行程序运行所需的共享库。现在,让我们迅速查看一下动态装入器如何在系统上找到适当的共享库。
  ld.so.conf
  动态装入器找到共享库要依靠两个文件 — /etc/ld.so.conf 和 /etc/ld.so.cache。如果您对 /etc/ld.so.conf 文件进行 cat 操作,您可能会看到一个与下面类似的清单:
  $ cat /etc/ld.so.conf
  /usr/X11R6/lib
  /usr/lib/gcc-lib/i686-pc-linux-gnu/2.95.3
  /usr/lib/mozilla
  /usr/lib/qt-x11-2.3.1/lib
  /usr/local/lib
  ld.so.conf 文件包含一个所有目录(/lib 和 /usr/lib 除外,它们会自动包含在其中)的清单,动态装入器将在其中查找共享库。
  ld.so.cache
  但是在动态装入器能“看到”这一信息之前,必须将它转换到 ld.so.cache 文件中。可以通过运行 ldconfig 命令做到这一点:
  # ldconfig
  当 ldconfig 操作结束时,您会有一个最新的 /etc/ld.so.cache 文件,它反映您对 /etc/ld.so.conf 所做的更改。从这一刻起,动态装入器在寻找共享库时会查看您在 /etc/ld.so.conf 中指定的所有新目录。
  
  ldconfig 技巧
  
  要查看 ldconfig 可以“看到”的所有共享库,请输入:
  
  # ldconfig -p | less
  还有另一个方便的技巧可以用来配置共享库路径。有时候您希望告诉动态装入器在尝试任何 /etc/ld.so.conf 路径以前先尝试使用特定目录中的共享库。在您运行的较旧的应用程序不能与当前安装的库版本一起工作的情况下,这会比较方便。
  LD_LIBRARY_PATH
  要指示动态装入器首先检查某个目录,请将 LD_LIBRARY_PATH 变量设置成您希望搜索的目录。多个路径之间用冒号分隔;例如:
  # export LD_LIBRARY_PATH=”/usr/lib/old:/opt/lib”
  导出 LD_LIBRARY_PATH 后,如有可能,所有从当前 shell 启动的可执行程序都将使用 /usr/lib/old 或 /opt/lib 中的库,如果仍不能满足一些共享库相关性要求,则转回到 /etc/ld.so.conf 中指定的库。


一般的当安装一个库时(从RPM,deb或其他二进制包管理系统),会包括一个后缀名为pc的文件,它会同其他.pc文件一起放入一个文件夹(依赖与你的系统设置)。

在这个文件里包含有数个条目。这些条目通常包含用于其他使用这个库的程序编译时需要的库设置,以及头文件的位置,版本信息和一个简介。

你可能感兴趣的:(Ubuntu)