你在 Unix 或 Linux 下开发过软件吗?写完一个程序,编译运行彻底正常,在你本机上工做得好好的,你放到源代码管理系统中。而后,告诉你的同事说,你能够取下来用了。这时,你长长的出了一口气,几天的工做没有白费,多么清新的空气啊,你开始飘飘然了。linux
“Hi,怎么编译不过去?”你还沉浸在那种美妙的感受之中,双臂充满着力量,彷佛没有什么问题能难倒你的。正在此时,那个笨蛋已经冲着你嚷开了。缓存
“不会吧,我这边好好的!”表面上你说得很客气,其实,你内心已经骂开了,真笨,不知道脑子干吗用的。也许,你想的没错,上次,他犯了一个简单的错误,不是你一去就解决了吗。安全
他喊三次以后,你不得不放下你手上的工做,刚才那种美妙的感受已经消失得无影无踪了,要不是你把情绪控制得很好,一肚子气就要撒在他身上了。你走到他的电脑前,键入 make,优雅的按下回车。怎么可能出错呢?你信心十足。然而,屏幕上的结果多少有点让人脸红,该死的,libxxx.so 怎么会让不到呢?bash
你在/usr目录中查找 libxxx.so,一切都逃不过你的眼睛。奇怪,libxxx.so 怎么在 /usr/local/lib 下,不是应该在 /usr/lib 下的吗?这你可不能怪别人,别人想安装在哪里都行,下次还可能安装到 /lib 目录下呢。工具
以上的场景并不是虚构,我都经历过好几回,明明在本机上好好的,在别人的机器上连编译都过不去。可能两人的操做系统如出一辙,须要的库都安装上,只是因为我的 喜爱不一样,安装在不一样的目录而已。遇到这种状况,每次都技巧性的绕过去了,用的补丁型的方法,内心老惦记其它地方能不能工做。ui
今天咱们要介绍的 pkg-config,为解决以上问题提供了一个优美方案。今后,你不再为此担心了。pkg-config提供了下面几个功能:spa
这一切都自动的,库文件安装在哪里都不要紧!操作系统
在使用前,咱们说说 pkg-config 的原理,pkg-config 并不是精灵,能够凭空获得以上信息。事实上,为了让pkg-config能够获得这些信息,要求库的提供者,提供一个.pc文件。好比gtk+-2.0的pc文件内容以下:线程
prefix=/usr
exec_prefix=/usr
libdir=/usr/lib
includedir=/usr/include
target=x11进程gtk_binary_version=2.4.0
gtk_host=i386-redhat-linux-gnuName: GTK+
Description: GIMP Tool Kit (${target} target)
Version: 2.6.7
Requires: gdk-${target}-2.0 atk
Libs: -L${libdir} -lgtk-${target}-2.0
Cflags: -I${includedir}/gtk-2.0
这个文件通常放在 /usr/lib/pkgconfig/ 或者 /usr/local/lib/pkgconfig/ 里,固然也能够放在其它任何地方,如像 X11 相关的pc文件是放在 /usr/X11R6/lib/pkgconfig 下的。为了让pkgconfig能够找到你的pc文件,你要把pc文件所在的路径,设置在环境变量 PKG_CONFIG_PATH 里。
使用 pkg-config 的 –cflags 参数能够给出在编译时所须要的选项,而 –libs 参数能够给出链接时的选项。例如,假设一个 sample.c 的程序用到了 Glib 库,就能够这样编译:
$ gcc -c `pkg-config –cflags glib-2.0` sample.c
而后这样链接:
$ gcc sample.o -o sample `pkg-config –libs glib-2.0`
或者上面两步也能够合并为如下一步:
$ gcc sample.c -o sample `pkg-config –cflags –libs glib-2.0`
能够看到:因为使用了 pkg-config 工具来得到库的选项,因此不论库安装在什么目录下,均可以使用相同的编译和链接命令,带来了编译和链接界面的统一。
使用 pkg-config 工具提取库的编译和链接参数有两个基本的前提:
GTK+ 及其依赖库支持使用 pkg-config 工具,因此剩下的问题就是如何告诉 pkg-config 到哪里去寻找库对应的 .pc 文件,这也是经过设置搜索路径来解决的。
对于支持 pkg-config 工具的 GTK+ 及其依赖库来讲,库的头文件的搜索路径的设置变成了对 .pc 文件搜索路径的设置。.pc 文件的搜索路径是经过环境变量 PKG_CONFIG_PATH 来设置的,pkg-config 将按照设置路径的前后顺序进行搜索,直到找到指定的 .pc 文件为止。
安装完 Glib 后,在 bash 中应该进行以下设置:
$ export PKG_CONFIG_PATH=/opt/gtk/lib/pkgconfig:$PKG_CONFIG_PATH
能够执行下面的命令检查是否 /opt/gtk/lib/pkgconfig 路径已经设置在 PKG_CONFIG_PATH 环境变量中:
$ echo $PKG_CONFIG_PATH
这样设置以后,使用 glib 库的其它程序或库在编译的时候 pkg-config 就知道首先要到 /opt/gtk/lib/pkgconfig 这个目录中去寻找 glib-2.0.pc 了(GTK+ 和其它的依赖库的 .pc 文件也将拷贝到这里,也会首先到这里搜索它们对应的 .pc 文件)。以后,经过 pkg-config 就能够把其中库的编译和链接参数提取出来供程序在编译和链接时使用。
另外还须要注意的是:环境变量的设置只对当前的终端窗口有效。若是到了没有进行上述设置的终端窗口中,pkg-config 将找不到新安装的 glib-2.0.pc 文件、从而可能使后面进行的安装(如 glib 以后的 Atk 的安装)没法进行。
在咱们采用的安装方案中,因为是使用环境变量对 GTK+ 及其依赖库进行的设置,因此当系统从新启动、或者新开一个终端窗口以后,若是想使用新安装的 GTK+ 库,须要如上面那样从新设置 PKG_CONFIG_PATH 和 LD_LIBRARY_PATH 环境变量。
这种使用 GTK+ 的方法,在使用以前多了一个对库进行设置的过程。虽然显得稍微繁琐了一些,但倒是一种最安全的使用 GTK+ 库的方式,不会对系统上已经存在的使用了 GTK+ 库的程序(好比 GNOME 桌面)带来任何冲击。
为了使库的设置变得简单一些,能够把下面的这两句设置保存到一个文件中(好比 set_gtk-2.10 文件):
export PKG_CONFIG_PATH=/opt/gtk/lib/pkgconfig:$PKG_CONFIG_PATH
export LD_LIBRARY_PATH=/opt/gtk/lib:$LD_LIBRARY_PATH
以后,就能够用下面的方法进行库的设置了(其中的 source 命令也能够用 . 代替):
$ source set_gtk-2.10
只有在用新版的 GTK+ 库开发应用程序、或者运行使用了新版 GTK+ 库的程序的时候,才有必要进行上述设置。
若是想避免使用 GTK+ 库以前上述设置的麻烦,能够把上面两个环境变量的设置在系统的配置文件中(如 /etc/profile)或者本身的用户配置文件中(如 ~/.bash_profile) ;库的搜索路径也能够设置在 /etc/ld.so.conf 文件中,等等。这种设置在系统启动时会生效,从而会致使使用 GTK+ 的程序使用新版的 GTK+ 运行库,这有可能会带来一些问题。固然,若是你发现用新版的 GTK+ 代替旧版没有什么问题的话,使用这种设置方式是比较方便的。
库文件在链接(静态库和共享库)和运行(仅限于使用共享库的程序)时被使用,其搜索路径是在系统中进行设置的。通常 Linux 系统把 /lib 和 /usr/lib 两个目录做为默认的库搜索路径,因此使用这两个目录中的库时不须要进行设置搜索路径便可直接使用。对于处于默认库搜索路径以外的库,须要将库的位置添加到库的搜索路径之中。设置库文件的搜索路径有下列两种方式,可任选其一使用:
将本身可能存放库文件的路径都加入到 /etc/ld.so.conf 中是明智的选择。( ^_^)
添加方法也极其简单,将库文件的绝对路径直接写进去就OK了,一行一个。例如:
/usr/X11R6/lib
/usr/local/lib
/opt/lib
须要注意的是:第二种搜索路径的设置方式对于程序链接时的库(包括共享库和静态库)的定位已经足够了,可是对于使用了共享库的程序的执行仍是不够的。这是 由于为了加快程序执行时对共享库的定位速度,避免使用搜索路径查找共享库的低效率,因此是直接读取库列表文件 /etc/ld.so.cache 从中进行搜索的。/etc/ld.so.cache 是一个非文本的数据文件,不能直接编辑,它是根据 /etc/ld.so.conf 中设置的搜索路径由 /sbin/ldconfig 命令将这些搜索路径下的共享库文件集中在一块儿而生成的(ldconfig 命令要以 root 权限执行)。所以,为了保证程序执行时对库的定位,在 /etc/ld.so.conf 中进行了库搜索路径的设置以后,还必需要运行 /sbin/ldconfig 命令更新 /etc/ld.so.cache 文件以后才能够。ldconfig ,简单的说,它的做用就是将 /etc/ld.so.conf 列出的路径下的库文件缓存到/etc/ld.so.cache以供使用。所以当安装完一些库文件(例如刚安装好 glib 或者修改 ld.so.conf 增长新的库路径)后,须要运行一下 /sbin/ldconfig 使全部的库文件都被缓存到 ld.so.cache 中,若是没作,即便库文件明明就在 /usr/lib 下的,也是不会被使用的,结果编译过程当中抱错,缺乏xxx库,去查看发现明明就在那放着,搞的想大骂 computer 蠢猪一个。 (^_^)
在程序链接时,对于库文件(静态库和共享库)的搜索路径,除了上面的设置方式以外,还能够经过 -L 参数显式指定。由于用 -L 设置的路径将被优先搜索,因此在链接的时候一般都会以这种方式直接指定要链接的库的路径。
前面已经说明过了,库搜索路径的设置有两种方式:在环境变量 LD_LIBRARY_PATH 中设置以及在 /etc/ld.so.conf 文件中设置。其中,第二种设置方式须要 root 权限,以改变 /etc/ld.so.conf 文件并执行 /sbin/ldconfig 命令。并且,当系统从新启动后,全部的基于 GTK2 的程序在运行时都将使用新安装的 GTK+ 库。不幸的是,因为 GTK+ 版本的改变,这有时会给应用程序带来兼容性的问题,形成某些程序运行不正常。为了不出现上面的这些状况,在 GTK+ 及其依赖库的安装过程当中对于库的搜索路径的设置将采用第一种方式进行。这种设置方式不须要 root 权限,设置也简单:
$ export LD_LIBRARY_PATH=/opt/gtk/lib:$LD_LIBRARY_PATH
能够用下面的命令查看 LD_LIBRAY_PATH 的设置内容:
$ echo $LD_LIBRARY_PATH
最后,我来总结一下,PKG_CONFIG_PATH 主要指明.pc文件的所在路径,这样 pkg-config 工具就能够根据.pc文件的内容动态生成编译和链接选项,好比 Cflags (编译用)和 Libs (链接用),若是使用的是动态连接库,那么程序在链接和运行时,通常 Linux 系统把 /lib 和 /usr/lib 两个目录做为默认的库搜索路径,对于处于默认库搜索路径以外的库,系统管理员能够设置 LD_LIBRARY_PATH 环境变量或在 /etc/ld.so.conf 文件中添加库的搜索路径。值得说明的是,使用 gcc 链接时的选项,若是不用 pkg-config 工具,须要显示的声明链接的动态连接库名。使用 gcc 的同窗能够查看下面的注意事项。
Linux 系统中,为了让动态连接库能被系统中其它程序共享,其名字应符合 lib*.so.* 这种格式。若是某个动态连接库不符合此格式,则 Linux 的动态连接库自动装入程序(ld)将搜索不到此连接库,其它程序也没法共享之。格式中,第一个*一般表示为简写的库名,第二个*一般表示为该库的版本号。如在个人系统中,基本C动态连接库的名字为 libc.so.6,线程 pthread 动态连接库的名字为 libpthread.so.0 等等。若是没有指定版本号,好比 libmy.so ,这也是符合要求的格式。
gcc 命令几个重要选项:
固然若是有 root 权限的话,能够修改 /etc/ld.so.conf 文件,而后调用 /sbin/ldconfig 来达到一样的目的,不过若是没有 root 权限,那么只能采用输出 LD_LIBRARY_PATH 的方法了。