Linux环境下编译过程总体概览
GCC整个编译过程可分为这几个步骤:预处理、编译、汇编、链接
预编译
预编译过程主要是处理源代码文件中那些以#开头的预编译指令,具体来说
- 处理#define, 将所有的宏定义#define展开
- 处理#if, #else, #endif等等条件编译指令
- 处理#include, 原地插入文件(有时候你可以看到很有意思的头文件包含)
- 删除注释
可以使用以下命令来调用预编译器
gcc -E HelloWorld.c -o HelloWorld.i
cpp HelloWorld.c > HelloWorld.i
编译
编译过程是最核心也是最复杂的过程, 复杂性从GCC的编译选项中就可以略知一二,它主要是对预编译完的文件进行词法,语法,语义分析并进行优化,最终产生对应的汇编代码文件。
可以使用以下命令来调用编译器
- gcc -S HelloWorld.i -o HelloWorld.s
汇编
汇编器把汇编代码转换成目标文件,比较单纯。
可以使用以下命令来调用汇编器
- as HelloWorld.s -o HelloWorld.o
链接
链接器最终将多个目标文件链接起来形成可执行文件
为什么需要链接?
简单来说因为每个源代码模块都独立地进行编译,链接就是要处理各个模块之间的相互引用,使他们之间能够互相衔接。比如说我们的HelloWorld.c中的main函数并不知道printf这个函数的地址,链接器在链接的时候会根据引用到的符号printf,自动去相应的模块查找printf的地址,然后将HelloWorld.c模块中引用到printf的指令进行重新修正,让它的目标地址成为真正的printf函数的地址,这个就是链接的基本过程。