前言
C语言是一种结构化程序设计语言,当项目达到一定规模后,采用模块化设计是种必然的选择。所谓模块化设计是指对项目按照“自顶向下”的分析,将项目划分为一个个子系统,每个子系统再划分为多个模块,直到每一模块足够小并且功能单一为止。再按照“自底向上”的方式进行程序设计,将模块用C语言函数来实现,形成逐层调用关系,最终构成整个项目。
模块化设计可以降低程序复杂度,使程序设计、调试和维护等操作简单化。库函数是一种实现模块化的重要手段,在C语言编程中常见的通过包含头文件使用输入输出函数、数学函数等就属于库函数方式。函数库分为静态库和动态库两种,静态库是一系列的目标文件(.o文件)的归档文件(文件名格式为 libname.a),如果在编译某个程序时链接静态库,则链接器将会搜索静态库,从中提取出它所需要的目标文件并直接复制到该程序的可执行二进制文件(ELF格式文件)之中;动态库(文件名格式为 libname.so )在程序编译时并不会被链接到目标代码中,而是在程序运行时才被载入。
静态库的实现
以例子求分数和为例,原例中子函数 multi(m) 和主函数 main() 放在同一源文件中,先将其分成两个不同源文件 multi.c 和test.c。
/*multi.c 这是一个求分数和的函数实现,单独在multi.c文件中,没有其他函数*/
float multi(int m)
{
int i;
float s = 0;
for(i = 1;i <= m;i ++)
{
s = s + 1/i;
}
return s;
}
/*test.c 这是主文件,包含main函数,其中调用multi.c文件中的multi函数*/
#include<stdio.h>
float multi(int m);
void main()
{
for(int i = 1;i <= 20;i++)
{
printf("m=%d,s=%f\n",i,multi(i));
}
}
可以看到 test. c和 multi.c是调用与被调用关系,下面把 mult.c 编译成静态库。
#gcc -c multi.c
#ar r libmulti.a multi.o
ar: creating libmulti.a
第一行命令用gcc选项表示只编译不链接,因为 multi.c 是单一源文件,所以不需要链接,同时因为文件中没有 main() 函数,链接反而会报错。编译成功后,可以看见在文件夹中生成了 multi.o 文件。
第二行命令是将 mult.o 文件压缩打包到库文件。库文件必须以 lib 开头,以 .a 为扩展名,除开头和扩展名之外的部分,将作为库文件的标识被使用。
ar命令是Linux的一个备份压缩命令,用来做备存文件管理,可以创建、修改备存文件( archive),或从备存文件中抽取成员文件。备存文件以一定的结构打包一个或多个成员文件,且成员文件的内容、模式、时间戳等信息将被保存在备存文件中。
创建成功后,可以看到在文件夹生成了 libmulti.a 文件。至此,由模块文件成功生成了静态库。下面来看,在主文件test.c中怎样使用生成的静态库。首先分析一下 test.c 源文件。在源文件的 main() 函数中使用了 multi 函数,而且在 main() 函数前通过 int multi(intm); 声明了 multi 函数的调用方式。但函数 multi 的函数体定义在 libmulti. a 中,编译时,通过静态方式将 libmulti.a 链接到 test 中,命今如下:
# gcc -o test test.c -L. -l multi
-L. 表示将当前路径加人到库查找路径,这是因为 libmulti.a 目前在当前路径的缘故。可以将静态库文件复制到系统默认的查找路径,这时就可以省略 L. 选项。
-l multi 表示链接 libmulti.a 库文件,请留意文件名的对应。
成功后即可生成 test 可执行程序文件,运行 test 即可看到运行效果。
动态库的实现
动态库是函数库的另外一种实现方式。静态库方式下可以看到,在由主文件 test.c 编译生成可执行程序阶段,main() 函数所需的 multi 函数模块一次性从 libmulti.a 中链接到了 test 。此后,生成的 test 可以独立使用,和 libmulti.a 再无关系。因此,静态库方式生成的可执行程序比较大。
以动态库方式提供的函数库,只有在使用它的程序执行时才被链接使用,而不将需要的函数模共在编前就链接到可执行文件中,一个动态库以被多个程序同时使用,故可称为共零库,相比静态库,使用动态库会使可执行程序更轻便,函数库升级更容易但部署相对比较困难,因为可执行程序需要和动态库一起才能使用。下面来看动态库方式下函数库的制作及使用过程。
首先将 multi.c 文件制作成动态库:
#gcc-fPIC-shared- c multi.c -o libmulti.so
-fPIC 表示生成和位置无关的代码;-shared指示编译器生成动态库编译成功后,文件夹就会生成 libmulti.so文件,表明生成动态库完成。
下面编译主函数文件,使用生成的动态库:
gcc test.c -L. -l mulIiti -o test
生成 test 后运行./test,即可看到输出结果。
参考书
清华大学出版社《嵌入式Linux程序设计》——田卫新