Linux下动态链接库和静态链接库
第一部分:编译过程
先了解一下linux下C代码的编译过程,C代码的编译,一般分成四个阶段,包括:预编译,编译,汇编和链接,这四个阶段的分工是
预处理过程,负责头文件展开,宏替换,条件编译的选择,删除注释等工作。gcc –E表示进行预处理。
编译过程,负载将预处理生成的文件,经过词法分析,语法分析,语义分析及优化后生成汇编文件。gcc –S表示进行编译。
汇编,是将汇编代码转换为机器可执行指令的过程。通过使用gcc –C或者as命令完成。
链接,负载根据目标文件及所需的库文件产生最终的可执行文件。链接主要解决了模块间的相互引用的问题,分为地址和空间分配,符号解析和重定位几个步骤。实 际上在编译阶段生成目标文件时,会暂时搁置那些外部引用,而这些外部引用就是在链接时进行确定的。链接器在链接时,会根据符号名称去相应模块中寻找对应符 号。待符号确定之后,链接器会重写之前那些未确定的符号的地址,这个过程就是重定位。
第二部分:动态链接库和静态链接库的编译过程及隐式调用
链接库的隐式调用,一方面可以采用-L 参数指定链接库地址,或者在环境变量中将链接库的地址加入,或者将链接库加入到内定的目录中(/usr/lib/,/lib/等),具体方法如下面几部分,保证运行过程中,可以找到链接库的地址。
gcc -O test a.o c.so
gcc -o test a.o -L /usr/local/mm/c.so
第三部分:静态库链接时搜索路径顺序
1. ld会去找GCC命令中的参数-L
2. 再找gcc的环境变量LIBRARY_PATH
3. 再找内定目录 /lib /usr/lib /usr/local/lib 这是当初compile gcc时写在程序内的
第四部分:动态链接时、执行时搜索路径顺序
1. 编译目标代码时指定的动态库搜索路径 (-L 参数)
2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径
例如动态库libhello.so在/home/ting/lib目录下,以bash为例,使用命令:$export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ting/lib
3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径
修改/etc/ld.so.conf文件,把库所在的路径加到文件末尾,并执行ldconfig刷新。这样,加入的目录下的所有库文件都可见
4. 默认的动态库搜索路径/lib
5. 默认的动态库搜索路径/usr/lib
所以可以把库拷贝到/usr/lib和/lib目录下。
第五部分: 显式运行动态链接库
#include ... #include <dlfcn.h>// 显式加载需要用到的头文件 int main() { void *pdlHandle = dlopen("./mylib.so", RTLD_LAZY); // RTLD_LAZY 延迟加载 char *pszErr = dlerror(); if( !pdlHandle || pszErr ) { printf("Load mylib failed!n"); return 1; } void (*Print)() = dlsym(pdlHandle, "Print"); // 定位动态链接库中的函数 if( !Print ) { pszErr = dlerror(); printf("Find symbol failed!%sn", pszErr); dlclose(pdlHandle); return 1; } Print(); // 调用动态链接库中的函数 dlclose(pdlHandle); // 系统动态链接库引用数减1 return 0; }
第六部分:LINUX下头文件查找
#include <> : 直接到系统指定的某些目录中去找某些头文件。
#include “” : 先到源文件所在文件夹去找,然后再到系统指定的某些目录中去找某些头文件。
gcc寻找头文件的路径:
1. 在gcc编译源文件的时候,通过参数-I指定头文件的搜索路径,如果指定路径有多个路径时,则按照指定路径的顺序搜索头文件。命令形式如:“gcc -I /path/where /theheadfile/in sourcefile.c“,这里源文件的路径可以是绝对路径,也可以是相对路径。比如设当前路径为/root/test,include_test.c如果要包含头文件“include/include_test.h“,有两种方法:
1)include_test.c中#include “include/include_test.h”或者#include "/root/test/include/include_test.h",然后gcc include_test.c即可
2)include_test.c中#include <include_test.h>或者#include <include_test.h>,然后gcc –I include include_test.c也可
2.通过查找gcc的环境变量来搜索头文件位置,分别是:
CPATH/C_INCLUDE_PATH/CPLUS_INCLUDE_PATH/OBJC_INCLUDE_PATH。
3. 再在缺省目录下搜索,分别是:
/usr/include
/usr/local/include
/usr/lib/gcc-lib/i386-linux/2.95.2/include
参考文献:
Linux GCC常用命令 [http://www.cnblogs.com/ggjucheng/archive/2011/12/14/2287738.html]
linux 编译,链接和加载 [http://blog.csdn.net/stephen_yin/article/details/7762069]
Linux动态链接库的隐式加载和显示加载 [http://www.nginx.cn/1293.html]