静态库与动态库的编译连接

  一.静态库和动态库的简单介绍缓存

  程序设计的模块化是人们一直在追求的目标,由于当一个系统十分复杂的时候,将系统模块化既能够并行开发,又能够加强程序的可用性,下降程序间的耦合度。在一个复杂的多模块系统中,app

各个模块编译完成后,会生成各自的目标文件*.o,最后经过连接器将各个模块连接起来生成可执行文件。模块化

         库其实就是一个模块文件。人们为了将一些功能模块提供给他人使用,同时又不想将源代码直接分发给别人(也多是不须要,毕竟库使用更方便,不用从新编译),就将功能模块作成库,函数

外部应用经过连接库来加载库的功能模块。好比glibc是GNU标准的C标准函数库。spa

         库有静态和动态之分。静态库在编译时被连接进可执行文件中,动态库是在程序运行时连接。静态库的优势是使用方便,只要编译时连接成功,在程序运行时就不会有找不到库或者库错乱的设计

问题,可是这也形成了升级更新困难和内存空间浪费的问题。对于静态库来讲,升级就必须从新编译应用程序连接静态库而后所有升级,并且若是多个应用程序都用到了同一个静态库,那么当多个内存

应用程序运行时,内存中就会有静态库的多个拷贝,十分浪费空间。由于这些缘由,动态库应运而生。动态库是程序运行时才连接,因此在程序更新时,咱们只须要更新动态库文件,从新启动应用开发

程序就会连接新库,并且当内存中已经有一个动态库的拷贝时,其余应用在运行时,若是须要连接库,会先从内存中查找库,找到后就直接连接该库,找不到再加载库到内存中,这保证了不会有同源码

一个库的多个拷贝在内存中占用空间。io

  二.静态库和动态库的编译和连接 

  2.1 程序源码

  咱们将会建立一个app,主要功能是输出“hello world”,具体实如今库libhello.a/libhello.so中实现。下面是各个文件的源代码:

      

  app源码

  #include<stdlib.h>

  #include<stdio.h>

  #include"hello.h"

 

  void main(void)

  {

          hello();

          hello();

  }

  

  库源码

  

  hello.c源码

  #include<stdlib.h>

  #include<stdio.h>

  void hello(void)

  {

          printf("\n======hello world======\n");

  }

 

  hello.h源码

  #ifndef HELLO_H

  #define HELLO_H

  void hello(void);

   #endif

  2.2.静态库的编译和连接

  

  第一步:生成目标文件

    # gcc -c hello.c

    生成目标文件hello.o

 

  第二步:编译生成静态连接库libhello.a

    # ar rcs libhello.a hello.o

 

  第三步:增长用于外部调用静态库函数的头文件hello.h

    hello.h头文件的做用是给外部调用库函数提供函数声明

 

  第四步:外部程序使用静态库

    在app.c中包含所用静态库函数声明的头文件hello.h

    生成app.o的目标文件

    #gcc -c app.c

    连接静态库libhello.a生成可执行文件app

    #gcc -o app app.o -L. -lhello

    执行app

    #./app

      ======hello world======

 

      ======hello world======

  2.3.动态库的生成

  一样是先生成目标文件hello.o,而后编译动态库文件libhello.so

  # gcc -shared -fPCI -o libhello.so hello.o

  # ls

  发现libhello.so已经生成了,而后咱们开始生成可执行文件。这里动态库并无连接。

  # gcc -o app app.o  -L. -lhello

  编译经过,执行app时出错

  #./app

  ./app: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory

  程序运行时,找不到动态库。那为何编译时能经过呢?由于编译时的-L指定了编译路径,因此编译能经过,可是在运行加载动态库时,会默认从/lib,/usr/lib路径下去找,而实际库不在该路径下,因此加载失败。

  

  解决的办法有三个:

  1.将库文件拷贝到默认的动态库路径/lib,/usr/lib,此为最简单,最快捷的方法

  2.程序编译时指定动态库路径,使用“-Wl,-rpath”。

    # gcc -o app app.o  -L. -lhello -Wl,-rpath=/mnt/hgfs/share/workspace/demo/LibraryDemo1

  注意:有的系统中多是"-Wl,-rpath,/path/to/dir",使用时须要注意。还有就是我本身在使用时出现的小问题,提醒下你们,我开始老是写成-Wl,rpath=path,结果编译怎么都不过,老是提示找不打rpath=path这个文件或路径,后来才发现少写了个“-”,提醒你们须要认真看错误提示。

     3.就是更改/etc/ld.so.conf。查看/etc/ld.so.conf发现它包含了/etc/ld.so.conf.d目录下的全部*.conf。到/etc/ld.so.conf.d/目录下,

   新建一个*.conf,在里面加上动态库的路径(你也能够直接在其中某一个conf中增长一条,可是最好不要这么干,不然之后可能有未知的混乱)。

   此时运行app仍然失败,缘由是系统查找动态库是经过查找/etc/ld.so.cache缓存,仅仅更改配置是不行的,还须要更新缓存。此时能够经过/sbin/ldconfig更新缓存。

   # /sbin/ldconfig

   有时候想知道动态库路径是否加入到缓存中,可使用ldconfig指令

   # sudo /sbin/ldconfig -p |grep path

     在执行更新缓存后,能够查看到:

   # libhello.so (libc6) => /mnt/hgfs/share/workspace/demo/LibraryDemo1/libhello.so

    以上三种方法亲测可用。

相关文章
相关标签/搜索