静态库是共享代码的一种实现方式。其名字出自于编译时静态加载,编译出的对象文件完全包含了静态库中的所有代码。
生成静态库只需要两步:
第一步将源文件*.c编译成*.o文件:cc -c *.c
第二步再简单地将*.o文件打包成*.a即可:ar crv libtarget.a *.o
静态库的使用:
由于静态加载,需要在link时就指定静态库,用来将静态库中的全部代码link到最终的目标文件中。
对于*.a文件可以使用nm这个命令来list symbols from object files:nm libtarget.a
还可以通过ar命令的x选项将*.a反向解压:ar xv libtarget.a,将libtarget.a解包成之前的一系列*.o文件。
静态库的应用场景是:
代码使用商要购买某个算法,或者产品套件中有配套的代码。
但是代码提供商出售代码时不希望公开源码,可以将编译的中间结果卖给代码使用商。
代码使用商就可以以*.a形式文件作为原料,制作动态库,或者制作成应用程序。
但是需要注意的是,*.o文件原则上不应该被代码版本管理工具(如git,svn)所收容,因为工程编译自己也会产生*.o文件,这对于代码管理会有干扰。
比如我修改了3个源文件,编译验证通过,本来要上库的,结果不仅提示3个源文件被更新,如果代码版本库中有*.o文件也会提示要更新。
所以一般代码提供商会将要发布的*.o文件打包成*.a文件,即静态库文件。
以如下实验代码为例:
源代码文件func.c,其中定义了func0,func1,func2,func3这四个函数
#include <stdio.h>
#define FUNC(TAG) \
int func##TAG(void) \
{ \
printf("%s.%d:%s\n", __FILE__, __LINE__, __func__); \
return 0; \
}
FUNC(0); /* func0 */
FUNC(1); /* func1 */
FUNC(2); /* func2 */
FUNC(3); /* func3 */
再有文件stub.c,其中定义了stub0,stub1,stub2,stub3这四个函数
#include <stdio.h>
#define FUNC(TAG) \
int stub##TAG(void) \
{ \
printf("%s.%d:%s\n", __FILE__, __LINE__, __func__); \
return 0; \
}
FUNC(0); /* stub0 */
FUNC(1); /* stub1 */
FUNC(2); /* stub2 */
FUNC(3); /* stub3 */
再有文件call.c,其中定义了call()函数,其引用了func0和stub0函数
int call()
{
func0();
stub0();
return 0;
}
最后在文件main.c中定义main函数,且依次调用func.c,stub.c和call.c中的函数
#include <stdio.h>
int main()
{
printf("%s begin\n", __func__);
#if 1
func1();
func2();
func3();
#endif
#if 1
stub1();
stub2();
stub3();
#endif
#if 1
call();
#endif
printf("%s return\n", __func__);
return 0;
}
如果直接编译main.c肯定会报错,因为link时找不到对应符号实际的定义:
test@test:~$ gcc main.c
/tmp/ccDTot2x.o: In function `main':
main.c:(.text+0x21): undefined reference to `func1'
main.c:(.text+0x2b): undefined reference to `func2'
main.c:(.text+0x35): undefined reference to `func3'
main.c:(.text+0x3f): undefined reference to `stub1'
main.c:(.text+0x49): undefined reference to `stub2'
main.c:(.text+0x53): undefined reference to `stub3'
main.c:(.text+0x5d): undefined reference to `call'
collect2: ld returned 1 exit status
这里我们将func.c和stub.c对应的代码制作成libcsdn.a
gcc -c func.c stub.c
ar crv libcsdn.a func.o stub.o
这样静态库文件就制作好了。
然后就可以将静态库文件当作普通的*.o来使用:
gcc main.c libcsdn.a call.c
这样生成的a.out应用程序就完整了包含了所有源代码文件的内容,在运行时全部加载入内存。
使用静态库:link时指定用到的静态库文件,且要注意顺序
例如:
gcc main.c libt3.a -o a.out