目录
1.动静态库
- 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静 态库
- 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文 件的整个机器码
- 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个 过程称为动态链接(dynamic linking)
- 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚 拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。
1.1.如何制作一个库
库(Library)是一种预先编写好的可重用代码集合,它包含了一组函数、类、数据结构或其他可执行代码的集合。库的目的是为了提供一些常用的功能,以便开发人员可以在自己的程序中直接调用这些功能,而不需要从头开始编写代码。
在我们实际开发的场景下,当我们写好一个库时,我们往往是将源代码(.c文件)经过编译后的文件(.o文件)和头文件一起打包给库的使用者,也就是我们写好的库是不包含源代码的。
文件编译
一堆源文件和头文件最终变成一个可执行程序需要经历以下四个步骤:
- 预处理: 完成头文件展开、去注释、宏替换、条件编译等,最终形成xxx.i文件。
- 编译: 完成词法分析、语法分析、语义分析、符号汇总等,检查无误后将代码翻译成汇编指令,最终形成xxx.s文件。
- 汇编: 将汇编指令转换成二进制指令,最终形成xxx.o文件。
- 链接: 将生成的各个xxx.o文件进行链接,最终形成可执行程序。
库中包含着.h文件和.o文件
接下来我们写一个demo并把它打包成库
我们以实现计算器这个库
一般来说我们要编译这个test.c这个可执行文件,需要将三个.c文件同时编译使用
gcc test.c add.c sub.c
但是这样子就需要将源代码给到别人,而开发中的源代码一般是闭源的,所以我们需要先将这几个实现.h文件的.c文件编译成.o文件
gcc -c add.c sub.c // 生成对应的.o文件
那么我们现在开始创建库的雏形,只给.h文件和.o文件(这个图add.c应该为add.h)
用户在使用时通过先将自己的测试文件转换为.o文件然后再一起编译这几个.o文件
gcc test.o add.o sub.o
假设在实际开发中,有10000个.o文件那这样子编译会不会容易漏掉,所以这时候我们需要打包文件,生成静态库
// 通过这条指令我们打包了一个静态库mycal ar -rc libmycal.a *.o
如图所示我们就打包好了一个静态库
一般来说我们通常通过makefile来打包好静态库
static-lib=libmycal.a $(static-lib):add.o sub.o ar -rc $@ $^ %.o:%.c gcc -c $< .PHONY:clean clean: rm -f *.o
1.2.静态库的使用和管理
我们在1.1.中制作了一个mycal的静态库,那么从库的使用角度出发我们怎么来使用这个库呢?
首先当我们写了一个库给他人使用时,此时作为第三方库,gcc无法认识这个库,需要链接指定的库