http://blog.chinaunix.net/uid-23069658-id-4028681.html
http://blog.jobbole.com/107977/
这篇博客介绍的比较详细,可以参考
总结起来,主要有以下几个要点:
1.编译阶段
1.编译源码时一般需要./configure(根据本机的环境生成所需要的编译参数,比如所需要的库的路径,头文件的路径等),一般使用pkg-config工具来解决依赖问题,也就是查找该工程所需要的库是否存在以及在什么地方(包括头文件的路径和库的路径),所以这里主要说明pkg-config是依据什么规则来搜索的:
一般我们安装某个库时,会提供以pc结尾的文件,当执行make install的时候,会copy到${prefix}/lib(或者lib64)/pkgconfig目录下(prefix就是configure时指定的prefix,如果没有指定,默认为/usr/local/lib/pkgconfig目录),可以看一下这些文件,里面就记录了该库的头文件的安装路径和库文件的安装路径,pkg-config --cflags librtmp命令就可以打印出-I/usr/local/include,表明头文件路径,pkg-config --libs librtmp就会打印出-L/usr/local/lib -lrtmp -lssl -lcrypto。所以这样就可以在configure命令很方便的获取某个库的编译参数。所以这个pc文件非常重要,一般正规的库都会提供这个pc文件。
如果说找不到某个库该怎么办。前提是你确确实实已经安装了它需要的库,不用多想,原因只有一个,pkg-config找不到与这个库对应的pc文件。为什么会找不到呢,原因又有两点:
1、pkg-config搜索了所有它认为合适的目录都没找着这个库对应的pc文件的下落;
2、这个库在发布时根本就没有提供它的pc文件。(实在不行就只能帮它写一个pc文件了)
所以对于1,那么pkg-config会去哪些路径去找pc文件呢?它会到prefix/lib(lib64)/pkgconfig下去寻找,prefix依照下面的规则
1、如果你的pkg-config是通过yum和rpm包安装的
prefix=/usr
libdir=${prefix}/lib=/usr/lib
datadir=${prefix}/share=/usr/share
2、如果你的pkg-config通过源码包安装的,且没有指定prefix的值(指定的情况同1)
prefix=/usr/local
libdir=${prefix}/lib=/usr/local/lib
datadir=${prefix}/share=/usr/local/share
如果你的pc文件放到其他路径下了,就需要给系统指定,PKG_CONFIG_PATH环境变量就是用来指定临时的pc文件路径的。当然,如果只在某个终端下export这个环境变量,则只是临时的,如果要永久记录,则可以在home目录下.bash_profile或者/etc/profile文件中加上这个export。
ok,到这里就把configure里面怎么寻找所需要的库的方法总结完了,主要就是利用pkg-config命令来找pc文件,该命令有默认的搜索路径,如果不在搜索路径下,则可以通过环境变量来指定。找到了某个库的pc文件,就可以获取编译链接该库的头文件和库路径作为编译参数。所以我们写某些工程时,也可以利用pkg-config命令来获取所需要的库的编译参数,使用非常方便。
2.运行动态链接阶段
这里的主要问题是:
1.运行时动态链接动态库时,默认的搜索路径有哪些?不在默认搜索路径下,有什么方法指定路径,包括临时的方法和永久的方法
linux系统中动态链接库的配置文件一般在/etc/ld.so.conf文件中,我们打开该文件可以看到其第一句一般就是include ld.so.conf.d/*conf,也就是把/etc/ld.so.conf.d目录下的所有conf文件都include进来了,我们可以看一下该目录下的文件,就会发现是各个软件或者库的conf文件,这些文件中写的就是库的路径。另外,在/etc/目录下还有一个ld.so.cache的文件(有些linux版本下有),这个就是ld.so.conf的缓存文件,也就是调用ldconfig命令,该命令就会根据ld.so.conf和ld.so.conf.d/*conf里面的内容生成cache文件,该cache文件被系统共享,也就是这些库的默认搜索路径。所以当我们把某个新库的路径写进ld.so.conf或者在ld.so.conf.d目录下新加一个该库的conf文件,然后调用ldconfig命令,就可以被同步到cache文件中,然后其他执行文件链接该库时就不用指定路径,会被默认搜索到。另外,ldconfig 目录名 也可以临时在cache文件中加入该目录,但会被后来的ldconfig命令来覆盖。
上面的是一种比较永久的方法,如果只是临时一个库文件放置到一个临时位置,则可以不用这么麻烦了,一种临时的方法就是直接ldconfig pwd来搞定,还有一种就是环境变量了LD_LIBRARY_PATH,同样可以指定,还可以放到home的.bash_profile或者/etc/profile中来永久有效。注意环境变量的优先级都是最高的,也就是会优先搜索环境变量指定的路径。
有没有发现,其实linux的搜索流程很是相似,一般有几个默认的路径,比如/usr/lib等,然后会有配置文件来指定一些路径,最后会有环境变量来临时指定,而且环境变量的优先级一般都是最高的。
1.如果自己安装的库放在一个特殊的路径下,没有在默认的搜索路径,其他程序链接这个库的时候总是找不到,比如安装sdl的时候装在了/usr/local目录下,但是这不是默认的搜索路径,在使用ffmpeg的时候需要用到这个库,运行ffmpeg的时候会提示加载sdl库时找不到该库,这时可以在/etc/ld.so.conf目录下创建sdl.conf文件,然后
vim /etc/ld.so.conf.d/sdl.conf
# 在conf文件中加入如下
/usr/local/lib //就是把sdl库的位置写在文件里。
# 最后执行
sudo ldconfig
3.主动链接动态库和主动链接静态库
linux系统默认链接的时候会优先链接动态库,其次链接静态库,如果想主动链接静态库,可以指定静态库的绝对路径(不推荐),还可以使用编译参数-static选项来指定,但这样会把所有库的链接都指定为static,所以
在要静态连接的库前指定-Bstatic ,在要动态连接的库前指定-Bdynamic选项。连接器在看到-Bstatic时会优于去找静态库,如果找不到再去找动态库。 -Bdynamic也是同样的情况,这里注意-Bstatic需要和-Wl配合使用
gcc test.cpp -L. -Wl,-Bstatic -ltestlib -Wl,-Bdynamic -ltestdll