|
库的作用
大体上库的存在,有两方面的原因,一是代码的复用,二是声明和实现的分离。将功能相近的使用模块封装成库,使代码的复用、管理和分发变得简单了许多,例如著名的开源图形库ncurses,你可以自行编译,更可以直接使用已经编译好的现成的库文件。另外,由于库是二进制文件,某种意义上讲,将功能的实现部分隐藏了起来,这就为商业代码的保护提供了一种方式。
库文件按照链接方式和时机,可以分为动态库和静态库,下面分别介绍它们在Linux环境中的创建和使用方法。
静态链接库
静态库是指在程序的链接阶段,其中被用到的代码会被直接链接到可执行文件中的库。静态链接的可执行程序包含了其所需的全部库函数:所有库函数都连接到程序中。 这类程序是完整的,其运行不需要外部库的支持。 静态链接程序的优点之一是其安装之前不需要做环境准备工作 。
Linux中,静态库的扩展名通常为.a,它仅仅是一些目标文件(.o)的归档(archive)或者说打包,另外,为了链接时能够快速地定位其中的符号(函数、变量名等),静态库还会包含一个对其中符号的索引。
创建静态库的过程十分简单,除编译所必须的工具之外,要用到的命令只有两个ar和ranlib。ar可以将各个目标文件进行归档,ranlib对ar生成的归档文件(即静态库文件)进行索引。假设现在有这样几个源文件:plus.c, sub.c及相应的头文件,另外还有一个用来调用库文件中函数的主文件main.c,它们的内容分别是:
plus.c,
#include "plus.h"intplus(int a, int b){ return a + b;} sub.c,
#include "sub.h"intsub(int a, int b){ return a - b;} main.c,
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include "plus.h"intmain(int argc, char **argv){ int a = plus(1, 2); printf("%d\n", a); return 0;} 下面将plus.c和sub.c编译,制作成静态库libmath.a,依次执行:
$ cc main.c -L. -lmath -o main
$ ./main
动态链接库
动态库和静态库相似,也是各个目标文件的集合。但相比静态链接的程序,动态链接可执行程序要小得多:这类程序运行时需要外部共享 函数库的支持,因此好像并不完整。除了程序体小之外,动态链接允许程序包指定必须的库,而不必将库装入程序包内。动态链接技术还允许多个运行中的程序共享一个库,这样就不会出现同一代码的多份拷贝共占内存的情况了。由于这些原因,当前多数程序采用动态链接技术。
在Linux中的扩展名通常为.so。但在链接时,并不会被链接到可执行文件中,而是在执行时(需要时)由操作系统的动态加载模块动态地加载到内存,并链接到可执行文件地址空间的相应位置。
动态链接库的创建也分为编译和”归档”两个阶段,但不同的是在这两个阶段需要使用一些不同的命令选项。首先,需要将源文件编译成一种成为位置无关码(PIC: Position Independent Code)的目标文件,这种代码可以被加入到内存的任何位置却不需要加载器对其进行重定位,关于这种格式可以参考《链接器与加载器》和《程序员的自我修养–链接装载与库》中较为详尽的描述。接下来需要将这些位置无关码“归档”为.so文件。整个过程只需一个工具即可,即gcc。还是上面的源文件,执行以下命令:
<div class="wp_codebox">$ cc -c -fpic plus.c sub.c$ cc -shared -o libmath.so *.o |
|
|