程序的编译链接过程如上图, 从源文件生成了目标文件和静态库,目标文件和静态库生成可执行文件,可执行文件运行时通过LD_LIBRARY_PATH查找加载动态库运行
1.目标文件、静态库、动态库文件的生成
目标文件xxx.oc的生成,使用 -c
选项,指定只生成而不链接
gcc -c xxx.c -o xxx.o
静态库的生成,需先生成目标文件,使用ar rcs
命令对其做转换
gcc -c xx1.c -o xx1.o
gcc -c xx2.c -o xx2.o
ar rsc libxxx.a xx1.o xx2.o
动态库的生成,使用-shared
要求生成动态库,通常还加上-fpic
要求生成的代码地址无关,就是要动态库内部的使用相对偏移寻址,防止安全攻击
gcc xxx.c -fPIC -shared -o libxxx.so
2. 头文件的查找顺序
头文件查找顺序:
1.先搜索当前目录
2 然后搜索-I
指定的目录
3.环境变量CPLUS_INCLUDE_PATH
(c使用的是C_INCLUDE_PATH
)
4.最后搜索gcc/g++的内定目录
/usr/include
/usr/local/include
/usr/lib/gcc/x86_64-redhat-linux/4.1.1/include
3.库的查找顺序
- 运行时动态库的查找顺序:
1.环境变量LD_LIBRARY_PATH
2./etc/ld.so.conf下所包含的路径
其中,关于ld.so.conf中,参见此文:
Linux的动态链接库绝大多数都在`/lib`和`/usr/lib`下,操作系统也会默认去这两个路径下搜索动态链接库。另外,`/etc/ld.so.conf`文件里可以配置路径,`/etc/ld.so.conf`文件会告诉操作系统去哪些路径下搜索动态链接库。这些位置的动态链接库很多,如果链接器每次都去这些路径遍历一遍,非常耗时,Linux提供了`ldconfig`工具,这个工具会对这些路径的动态链接库按照SONAME规则创建软连接,同时也会生成一个缓存Cache到`/etc/ld.so.cache`文件里,链接器根据缓存可以更快地查找到各个`.so`文件。每次在`/lib`和`/usr/lib`这些路径下安装了新的库,或者更改了`/etc/ld.so.conf`文件,都需要调用`ldconfig`命令来做一次更新,重新生成软连接和Cache。但是`/etc/ld.so.conf`文件和`ldconfig`命令最好使用root账户操作。非root用户可以在某个路径下安装库文件,并将这个路径添加到`/etc/ld.so.conf`文件下,再由root用户调用一下`ldconfig`。
- 编译链接时,库查找顺序:
1.-L或 -Wl, rpath指定的路径
2.查找环境变量LIBRARY_PATH
下的路径
3.查找 /etc/ld.so.conf 下包含的路径
4 /lib 和 /usr/lib
其中,-L和-Wl, rpath都能够显示的指定库所在的目录,但它们存在区别,参见此文:
-L指定的库路径,在动态链接的时候,库的路径信息不会被存到到目标文件中,运行时目标文件只能通过LD_LIBRARY_PATH以及ld.so.conf提供的路径查找,如果使用-Wl, rpath则库的路径会存到目标文件中,运行时目标文件会先去这个路径查找,找不到了,再去LD_LIBRARY_PATH和ld.so.conf中找
4. 链接静态库和动态库的优先级
直接使用-l
查找路径的时候,gcc/g++默认优先链接动态库,找不到动态库后,才去找静态库
gcc xxx.c -o xxx -lopenssl // 链接openssl.so
要链接静态库就需要使用或者 -static 进行显示指定全都使用静态库
gcc xxx.c -o xxx -static -lopenssl // 链接libopenssl.a
也可以使用 -Wl,-Bstatic
, 这个选项使用后,后续的-l都是去找静态库,但可以通过Wl,-Bdynamic
再指定后面的都是动态库
//连接 libxx1.a libxx2.a libxx3.so
gcc xxx.c -o xxx -WL,-Bstatic -lxx1 -lxx2 -WL,-Bdynamic -lxx3