Linux下的静态库为lib*.a格式的二进制文件(目标文件),对应于Windows下的.lib格式的文件。
(1)命名规则
lib+库名字+ .a libMytest.a ,则库名字为mytest。下面以具体的代码为例介绍如何制作静态库。
//main.c
#include <stdio.h>
#include "head.h"
int main(void)
{int sum = add(2, 24);printf("sum = %d\n", sum);return 0;
}//head.h
#ifndef __HEAD_H_
#define __HEAD_H_
int add(int , int);
int sub(int , int);
int mul(int , int);
int div(int , int);
#endif//add.c
int add(int a, int b)
{int result = a + b;return result;
}//div.c
int div(int a, int b)
{int result = a / b;return result;
}//mul.c
int mul(int a, int b)
{int result = a * b;return result;
}//sub.c
int sub(int a, int b)
{int result = a - b;return result;
}
以上有5段代码:main.c、head.h、add.c、div.c、mul.c和sub.c。要求将add.c、div.c、mul.c和sub.c制作成库文件提供给客服使用,这4个文件都是关于头文件head.h中函数的详细实现,因此为了不想让客服知道函数实现的细节和方法,不能将源码提供给客服,而是以库文件(二进制文件)的形式提供给客服使用即可。至于如何使用,库文件已经将函数接口留在了头文件head.h中,即4个函数声明。用户看了头文件就知道如何使用库文件了,即如何使用函数。因此最后只需要将main.c、head.h和库文件给客服即可。(因此,一般库文件与相对应的头文件是同一个人来完成的)
先强调一下gcc的一个使用。-c参数是用来生成目标文件.o的,但是不链接。如: gcc -c zsx.s -o zsx.o gcc -c zsx.c -o zsx.o 对于上面4个.c文件,若工作目录中只有这4个.c文件,可以用*.c表示这四个文件: gcc -c *.c 则会生成4个.o文件:add.o div.o mul.o和sub.o(在不指出输出文件名字时,默认是将.c文件的.c改为.o) 。 gcc -c *.c 等价于对每一个单独的.c文件进行预处理、编译、汇编后生成各自的 .o文件(档案库文件)。同理,对于gcc a.c b.c c.c d.c 最后生成一个a.out文件,其先对每一个源文件生成目标文件,然后将这些目标文件与需要的静态库文件链接形成可执行文件,至于需要的动态库文件则是在程序运行时才会加载进去。
(2)制作静态库
1)生成对应的.o文件 2)将生成的.o文件打包。 ar rcs + 静态库的名字(libmytest.a)+ 生成的所有的.o
一个头文件(head.h,/mnt/hgfs/share/gcc/Calc/include)和四个.c文件(add.c、div.c、mul.c、sub.c, /mnt/hgfs/share/gcc/Calc/src): [root@localhost src]# gcc -c *.c
[root@localhost src]# ls
add.c add.o div.c div.o mul.c mul.o sub.c sub.o
[root@localhost src]# ar rcs libMytest.a *.o
[root@localhost src]# ls
add.c add.o div.c div.o libMytest.a mul.c mul.o sub.c sub.o
此时已经生成了静态库文件libMytest.a,该库文件包含了4个库函数add.o、div.o 、mul.o和sub.o。ar 工具不包含在gcc中,r --> 将文件插入静态库中;c --> 创建静态库,不管库是否存在(存在就不创建);s --> 写入一个目标文件索引到库中,或者更新一个存在的目标文件索引(即方便找到需要的库函数)。ar类似于命令,rcs是三个参数。
(3)使用静态库
将生成的libMytest.a库文件和头文件head.h发送给客服,客服就可以根据头文件中的接口情况,来知道库文件的功能 (具体怎么实现的他也不知道),从而客服就可以使用库文件来完成自己的工作了(main.c):
[root@localhost Calc]# gcc -pedantic -pipe -Wall main.c -I include/ -L src/ -lMytest -o zsx 也等价于:
[root@localhost Calc]# gcc -pedantic -pipe -Wall main.c -I include/ src/libMytest.a -o zsx
[root@localhost Calc]# ./zsx
sum = 26
分析main.c可以知道,还另外有一个头文件stdio.h,其对应的是printf函数的声明,其库文件是printf函数实现的库文件,该库文件有C提供,它们是标准头、库文件,因此不需要指明路径和名称,且该库函数为动态库函数,当程序在运行过程中需要该库函数时,才会根据头文件找到相应的库函数并加载进入内存空间。而,libMytest.a不一样,为静态库文件,因此在载入内存之前就已经链接在了一起成为程序代码的一部分。注意:main函数只是用了add函数,因此在链接时只是链接了add.o库函数,并非链接了整个库文件,只需要链接使用到的库函数即可。 例如,一个库文件libZsx.a包含了qw.o(其有a( )和b( )两个函数的实现)、qe.o(其有c( )和d( )两个函数的实现)和qr.o(其有e( )和f( )两个函数的实现)。当mani函数只是用到a( )和d( )两个函数时,则最终在链接生成可执行程序时,只是会链接qw.o和qe.o两个库函数,即main函数和这两个库函数都在代码区。
库函数与可执行程序只是差最后一步,都具有前面是哪个阶段,且各种规定都完全一样,都是二进制代码。
调试通过之后,加上-O参数,对代码进行优化,可以减小最后可执行文件的体积。
(3)静态库的优缺点
nm命令可以查看静态库文件(.a)和最后生成的可执行文件的详细属性。nm ibMytest.a 可以查看该静态库文件有哪些库函数(.o文件)。 nm zsx 显示的信息中有:
000000000040056c T add
0000000000400530 T main //main函数在链接的时候加进去的启动代码
参数T代表add和main在代码区。即参数T表示在代码区的内容。
静态库优点:1.发布程序的时候不需要提供对应的库(动态库需要);2.加载库的速度快(库函数就在代码区)。缺点:库被打包到代码中,增加了代码的体积;2.库一旦发生了改变,需要对整个程序进行重新编译。