【从编译的基本过程说起】
---
C语言的编译分为三个阶段:预编译阶段、编译阶段和链接阶段。正如下图所示的那样:
预编译阶段的产物是单个的“.c”文件。这一步骤的本质是文字替换:
以c源代码文件为中心,将所有 #include 所指向的任何文本文件(可以是头文件.h,可以是其它源代码文件.c,也可以是其它扩展名的文件——只要是文本文件就行)加入到当前的文件中
将宏替换为对应的文本(宏替换的本质是文本替换)
根据条件编译选择性的删除未被选中的文本
最终形成的“.c” 文件中将不存在任何宏、条件编译或是 #include
编译阶段将这些“.c”文件一个一个彼此独立的编译为对应的对象("*.obj")文件;
链接器(linker)会在最终阶段将这些对象文件(以及库文件)像乐高积木一样按照事先约定好的图纸(地址空间布局描述文件,又称linker script或者scatter script)组装到一起,最终生成在目标机器上可以运行的镜像文件。
大家也许已经注意到了,在第三个阶段,也就是链接阶段,库第一次出场了——在编译时刻被链接器直接用来生成最终镜像文件的库,就是我们所说的静态链接库。这里的“静态(static)”是相对那些在运行时刻(runtime)由操作系统负责组装——这一“动态(Dynamic)”过程而言的。简单的区分方法如下:
静态链接库在编译时刻(compile-time)由链接器(linker)使用;
动态链接库在运行时刻(
runtime)由操作系统负责组装。
【让静态链接库现出原形】
---
知道了静态链接库的“出场时间”以及“出厂地点”,那么静态链接库的真身是什么呢?我们不妨从编译器的视角来重新审视这个世界:
我们口中的变量和函数在编译器眼中有一个统一的名字:“符号(Symbol)”,而且很多时候,编译器并不关心一个符号具体指代的是变量还是函数,这个我们在后面的实践环节中会深切的体会到;
Section 是符号的容器,也就是说,函数和变量都一定保存在某一个 Section 中。
对象文件(*.o)是 Section 的容器。由于“.c”文件编译后会生成一个对应的对象文件,因此可以简单的认为,一个源代码文件编译后会变成一个容器,里面装的都是 Section。
静态链接库(.lib、.a)是对象文件的容器。但静态链接库不是简单的把一堆“.o”文件打包在一起就完事了,而是还贴心的准备了一个
备查表格——可以清晰的告诉linker:
对于linker所查找的具体某个“符号(Symbol)”应该到哪个对象文件中去查找。
简单说就是:
静态链接库 = 一堆 .o 打包在一起 + 一个符号索引表 【“假的”静态链接库制作教程】
---
以MDK为例,首先打开包含了我们库源代码的工程,在Option for Target对话框中切换到 Output 选项卡:
单击选择
Create Library,然后在
Name of Executable 文本框中给库一个名字。单击确认。
对IAR来说,打开目标工程,通过目录 Project 打开 Options 对话框:
在Category 中选择 General Options。切换到 Output 选项卡,选择 Library。
在 Category 中选择 Library Builder,可以单击 Override default 来指定库的保存路径和名字。 “好……今天的课程就到这里,下课!,班长?!”
“老~师~再~见~”
【“真的”静态链接库制作教程】
---
严格来说,上述教程只能算是“开发工具”的配置——仅仅是制作过程中最缺乏技术含量的一个步骤。而真正的静态链接库制作,起码需要考虑以下几个方面:
库的开发、以及日后的维护
库的封装和发布