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]

 

posted @ 2014-12-19 17:42  壹木人  阅读(622)  评论(0编辑  收藏  举报