功能包/库路径的配置是引用该包的关键,不然总是会出现各种莫名其妙的问题,需要折腾半天。解决这些问题的关键是需要厘清Linux下引用链接关系是怎么实现的。下面分别介绍一下两种安装时常见的问题以及解决方案。
通过源码包安装程序时,主要步骤有:
①解压缩
tar -zxvf http-2.2.29.tar.gz
②进入解压目录
cd http-2.2.29
③查阅文件 README INSTALL
vim README
vim INSTALL
④检测配置 生成文件 configure
./configure --prefix=/usr/local/apache2/
⑤编译
cmake ..
make
⑥安装
make install
运行
configure阶段虽然简单,但却最容易出错。configure是一个脚本,这个脚本的最终目的是为了生成Makefile文件的。但是在生成Makefile文件之前,由于每个人的机器环境不一样,所以它要做各种各样的检测看当前的环境是否满足运行这个软件的需求,所以会看到各种各样的checking。
上述过程主要是运行pkg-config工具来检测它需要依赖的动态库是否存在,pkg-config通常情况都是位于/usr/bin目录下,是个可执行程序。在configure阶段,通常都会用pkg-config来判断所依赖的动态库是否存在。现在问题就是,这个工具是如何判断的呢?它的依据是什么?
安装完某个功能包后,如果它提供了动态库的功能,在源码中都会有一个或多个以pc结尾的文件,当执行完make install后这些pc文件拷贝到${prefix}/lib/pkgconfig这个目录里(prefix是在configure阶段时通过配置参数–prefix指定的,缺省情况这个值就是/usr/local),所以这些pc文件最终会被拷贝到/usr/local/lib/pkgconfig目录下。以下为一个pc文件的实例:
[root@localhost ~]# cat /usr/local/lib/pkgconfig/librtmp.pc
prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
incdir=${prefix}/include
Name: librtmp
Description: RTMP implementation
Version: v2.3
Requires: libssl,libcrypto
URL: http://rtmpdump.mplayerhq.hu
Libs: -L${libdir} -lrtmp -lz
Cflags: -I${incdir}
跟我们configure阶段相关的主要集中在Libs和Cflags两项上面,如果你此时再执行下面这两条命令,就全明白了:
[root@localhost ~]# pkg-config --cflags librtmp
-I/usr/local/include
[root@localhost ~]# pkg-config --libs librtmp
-L/usr/local/lib -lrtmp -lz -lssl -lcrypto
也就是说,pkg-config把在Makefile里指定编译和链接时所需要用到的参数从手工硬编码的模式变成了自动完成,节约了多少跨平台移植的兼容性问题。假如说,如果我们将要的编译的软件包依赖librtmp这个动态库,那么此时在我系统上这个检测就算通过了。
如果提示缺少某个库。在已经安装的前提下原因一般是: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 lib dir/pkgconfig:datadir/pkgconfig where libdir is the libdir where pkg-config and datadir is the datadir where pkg-config was installed.
(参考链接3)
上面提到的prefix、libdir和datadir,就是安装pkg-config时被设定好的,具体情况是:
1、如果你是通过yum和rpm包安装的
prefix=/usr
libdir=$ {prefix}/lib=/usr/lib
datadir=$ {prefix}/share=/usr/share
2、如果你是通过源码包安装的,且没有指定prefix的值(指定的情况同1)
prefix=/usr/local
libdir=$ {prefix}/lib=/usr/local/lib
datadir=$ {prefix}/share=/usr/local/share
pkg-config在查找对应软件包的信息时的缺省搜索路径已经很清楚了。如果软件包对应的pc文件都不在这两个目录下时,pkg-config肯定找不到。以下为解决方案:
1:在configure阶段用–prefix参数把安装目录指定到/usr目录下;
2:通过一个名叫PKG_CONFIG_PATH的环境变量来向pkg-config指明我们自己的pc文件所在的路径,不过要注意的是PKG_CONFIG_PATH所指定的路径优先级比较高,pkg-config会先进行搜索,完了之后才是去搜索缺省路径。
前者的优点是以后再通过源码安装软件时少了不少麻烦,缺点是用户自己的软件包和系统软件混到一起不方便管理,所以实际使用中,后者用的要多一些。针对没有root权限的情况,大多数情况都可以执行:
export PKG_CONFIG_PATH=/your/local/path:$PKG_CONFIG_PATH
问题一般为:libxxx.so.y => not found,此时可以采用ldconfig命令解决,该命令一个动态链接库管理命令。
与库加载相关的文件说明:
/lib/ld.so 运行时库加载器
/etc/ld.so.conf 由逗号、空格、制表符、换行符或引号分隔的目录列表。ld将会在这些目录中查找连接库。
/etc/ld.so.cache 包含了在/etc/ld.so.conf.d中指定的目录中查找到所有连接库。按顺序存储。
/etc/ld.so.conf
文件内容一般只有一句话:include /etc/ld.so.conf.d/*.conf
,因此需要在etc/ld.so.conf.d/
目录下创建一个***.ld.so.conf文件,文件只需一行即为依赖包的链接库地址:
/usr/local/lib ##例子,根据具体目录设定
可用以下程序实现:
export INSTALL_DIR=/usr/local/lib
sudo sh -c "echo $INSTALL_DIR > /etc/ld.so.conf.d/***.conf"
sudo ldconfig ##更新
除了通过配置ldconfig 动态库所在路径的方式解决,Linux也为提供了一个名为LD_LIBRARY_PATH的环境变量来解决运行时动态库查找不到的问题。同样地,由这个环境变量所指定的路径会被装载器/lib/ld-2.12.so优先查找,然后才是动态库库缓存文件/etc/ld.so.cache。该方法只是测试使用,不推荐把“export LD_LIBRARY_PATH=…” 添加到.bash_profile或者/etc/profile里。
这里可能需要注意软链接的问题,具体例子参看参考链接2
库目录里×××.so.0只是××× .so.0.0.0的一个符号链接,真正需要链接的是后者,×××.so.0就是×××.so.0.0.0的软链接,这是动态库的命名规范的一种公约,有时候需要在目录下建立一个名为×××.so.0的到×××.so.0.0.0的软链接。
小结
PKG_CONFIG_PATH就是“软件包的配置路径”,编译软件时如果出现找不到所依赖的动态库时都全靠PKG_CONFIG_PATH了;
LD_LIBRARY_PATH是装载器的库路径,LD是Loader的简写,在Linux系统启动一个程序的过程就叫做装载,一个程序要执行时它或多或少的会依赖一些动态库(静态编译的除外)。当你用ldd ×××
查看一个软件启动时所依赖的动态库,如果输出项有“libxxx.so.y=> not found”
一项,你这个软件100%运行不起来。
参考:
1.https://blog.csdn.net/leo115/article/details/7672144
2.http://blog.chinaunix.net/uid-23069658-id-4028681.html
3.https://www.freebsd.org/cgi/man.cgi?query=pkg-config&manpath=SuSE+Linux/i386+11.3
4.http://people.freedesktop.org/~dbn/pkg-config-guide.html