学习到了一个阶段之后,就需要不断的总结、沉淀、清零,然后才能继续“上路”。回想起自己当年刚接触Linux时,不管是用源码包编译程序,还是程序运行时出现的和动态库的各种恩恩怨怨,心里那真叫一个难受。那时候脑袋里曾经也犯过嘀咕,为啥Linux不弄成windows那样呢,装个软件那个麻烦不说,连运行软件都这么恼火呢?如果那样的话就不叫Linux了。借用小米公司CEO雷军一句话:小米,为发烧而生。我认为:Linux,为真理而在。特别是为那些喜欢折腾,热衷技术背后原理和实现细节的人们而生。
说到和动态库查找路径相关的问题,总体上可以分为两类:
第一类:通过源代码编译程序时出现的找不到某个依赖包的问题,而如果此时你恰好已经按照它的要求确确实实、千真万确、天地良心地把依赖库给装好了,它还给你耍混、犯二,有一股折腾不死人不偿命的劲儿,那让人真是气儿不打一处来,如果Linux此时有头有脸,你是不是特想抽它丫两大嘴巴;
第二类:就是在运行程序的时候,明明把那个程序需要的依赖包都已经安装的妥妥的了,可运行的时候人家就告诉你说“error while loading shared libraries: libxxx.so.y: cannot open shared object file: No such file or directory”,任凭你怎么折腾都没用。此时你要是心想“撤吧,哥们,Linux太TM欺负人了,不带这么玩儿的”,那你就大错特错了,只要你抱着“美好的事情的总会发生”和“办法永远比问题多”的信念坚持下去,你就一定会成功。话的意思有点自欺欺人,精神鸦片的味道在里面,但确实是这么个理儿。
上面两类问题最大的原因就是,你没弄白它们的机制和原理。你看到的只是现象,当年学马克思主义主义哲学原理的时候,老师怎么教导我们的?要透过现象看本质。如果你把上面两中应用的原理搞清了,那问题不就自然而然的迎刃而解了么。下面咱们就一一探讨一下这两个问题,以便对新进学习Linux的朋友们起一个的参考资料的作用。
问题1 :通过源代码安装程序
通过源码包安装程序时,主要用到了“三大步”策略:configure、make和make install 。出问题最多的就是在configure阶段,很多初学者由于不知道configure的那么多参数该怎么用,所以往往为了省事,一句简单的“./configure”下去,百分之八九十都能成功,可问题往往就出在剩下的百分之十几上面了。这让我们又一次相信了,小概率事件的发生对事情的影响是多么的深远。在安装的configure阶段,为了检测安装安装环境是否满足,通常情况下都是通过一个叫做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文件有啥用呢?我们随便打开一个来瞅瞅:
跟我们configure阶段相关的主要集中在Libs和Cflags两项上面,如果你此时再执行下面这两条命令,就全明白了:
也就是说,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手册时会有下面一段话:
以及这点补充:
上面提到的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在查找对应软件包的信息时的缺省搜索路径已经很清楚了,有一点写错了,不是${ libdir}/pkg-config,而应该是${ libdir}/pkgconfig和${ datadir}/pkgconfig 。如果你软件包对应的pc文件都不在这两个目录下时,pkg-config肯定找不到 。既然原因都已经找到了,那解决办法也就多种多样了。
方案一: 我们可以在安装我们那个被依赖的软件包时,在configure阶段用--prefix参数把安装目录指定到/usr目录下;
方案二: 也可以按照上面说的,通过一个名叫PKG_CONFIG_PATH的环境变量来向pkg-config指明我们自己的pc文件所在的路径,不过要注意的是PKG_CONFIG_PATH所指定的路径优先级比较高,pkg-config会先进行搜索,完了之后才是去搜索 缺省路径。
前者的优点是以后再通过源码安装软件时少了不少麻烦,缺点是用户自己的软件包和系统软件 混到一起不方便管理,所以实际使用中,后者用的要多一些。
方案二在实际操作中有两种实现方式:
1、针对没有root权限的情况,大多数情况都是执行:
说到和动态库查找路径相关的问题,总体上可以分为两类:
第一类:通过源代码编译程序时出现的找不到某个依赖包的问题,而如果此时你恰好已经按照它的要求确确实实、千真万确、天地良心地把依赖库给装好了,它还给你耍混、犯二,有一股折腾不死人不偿命的劲儿,那让人真是气儿不打一处来,如果Linux此时有头有脸,你是不是特想抽它丫两大嘴巴;
第二类:就是在运行程序的时候,明明把那个程序需要的依赖包都已经安装的妥妥的了,可运行的时候人家就告诉你说“error while loading shared libraries: libxxx.so.y: cannot open shared object file: No such file or directory”,任凭你怎么折腾都没用。此时你要是心想“撤吧,哥们,Linux太TM欺负人了,不带这么玩儿的”,那你就大错特错了,只要你抱着“美好的事情的总会发生”和“办法永远比问题多”的信念坚持下去,你就一定会成功。话的意思有点自欺欺人,精神鸦片的味道在里面,但确实是这么个理儿。
上面两类问题最大的原因就是,你没弄白它们的机制和原理。你看到的只是现象,当年学马克思主义主义哲学原理的时候,老师怎么教导我们的?要透过现象看本质。如果你把上面两中应用的原理搞清了,那问题不就自然而然的迎刃而解了么。下面咱们就一一探讨一下这两个问题,以便对新进学习Linux的朋友们起一个的参考资料的作用。
问题1 :通过源代码安装程序
通过源码包安装程序时,主要用到了“三大步”策略:configure、make和make install 。出问题最多的就是在configure阶段,很多初学者由于不知道configure的那么多参数该怎么用,所以往往为了省事,一句简单的“./configure”下去,百分之八九十都能成功,可问题往往就出在剩下的百分之十几上面了。这让我们又一次相信了,小概率事件的发生对事情的影响是多么的深远。在安装的configure阶段,为了检测安装安装环境是否满足,通常情况下都是通过一个叫做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 libdir/pkg-config:datadir/pkgconfig where libdir is the libdir where pkg-config and datadir is the datadir where pkg-config was installed. |
上面提到的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在查找对应软件包的信息时的缺省搜索路径已经很清楚了,有一点写错了,不是${ libdir}/pkg-config,而应该是${ libdir}/pkgconfig和${ datadir}/pkgconfig 。如果你软件包对应的pc文件都不在这两个目录下时,pkg-config肯定找不到 。既然原因都已经找到了,那解决办法也就多种多样了。
方案一: 我们可以在安装我们那个被依赖的软件包时,在configure阶段用--prefix参数把安装目录指定到/usr目录下;
方案二: 也可以按照上面说的,通过一个名叫PKG_CONFIG_PATH的环境变量来向pkg-config指明我们自己的pc文件所在的路径,不过要注意的是PKG_CONFIG_PATH所指定的路径优先级比较高,pkg-config会先进行搜索,完了之后才是去搜索 缺省路径。
前者的优点是以后再通过源码安装软件时少了不少麻烦,缺点是用户自己的软件包和系统软件 混到一起不方便管理,所以实际使用中,后者用的要多一些。
方案二在实际操作中有两种实现方式:
1、针对没有root权限的情况,大多数情况都是执行: