C++基本
关于C++由源文件到可执行文件的基本流程
预处理(Preprocessing)编译(Compilation)汇编(Assemble)链接(linking) C++基本 关于C++由源文件到可执行文件的基本流程
在学习CMake之前,我们首先要了解C++的完整的编译流程,以使得我们可以更好的理解CMake中一些特定语句的作用,以及其到底对应了编译过程中的哪个阶段。在这里我们指的“编译流程”是宽泛的,即:C/C++从程序源码到最终可执行的二进制文件的变换过程。我们以Linux下为例。
编译流程分为基本的四个步骤,分别是:预处理(Preprocess)、编译(Compile)、汇编(Assemble)、链接(link)
预处理(Preprocessing) 预处理输入:Source Code -> .c / .cpp / .h / .hpp 文件
预处理输出:Include Header, Expand Macro -> .i / .ii 文件
预处理阶段将输入的源文件中的预处理指令进行处理,简单来说预处理指令就是哪些程序中最前面带有井号“#”的指令,最常用到的如下:
#include //用于包含一个头文件#define //定义宏#ifdef //如果已经定义宏,则编译以下的代码直到#endif#ifndef //如果没有定义宏,则编译以下的代码直到#endif#if //如果给定条件为真,则编译以下代码直到#endif#else//如果以上的#if条件不为真,则编译以下代码直到#endif#elif //如果以上的#if条件不为真,且当前条件为真,则编译以下代码直到#endif#endif //终止当前条件分支语句块
另外还有一些可能不太常见的预处理指令(可能只是我不常用)
# //空指令,没有任何作用#undef //取消已定义的宏#error//停止编译并显式错误信息#pragma//#line//
在预处理阶段,预处理器通过这些预处理指令,将源文件.c/.cpp/.h/.hpp都转变成.i格式的文件,而这个转换过程,预处理器做了哪些事情呢?(我就举几个简单且主要的例子)
对于#include指令,预处理阶段将所包含的.h/.hpp统统纳入其被包含的文件,即用整个文件代替这条#include指令对于#define A B 将程序中的所有A均替换为B,无论B代表的是数值还是函数对于条件编译相关的指令,只保留条件为true内部的语句块,其他部分进行移除(这里我还不是很确定)所以总体来说,预编译阶段工作可以概括为:对源程序中涉及带“#”的预编译指令的部分进行“替换”,生成一个/一系列没有“包含”、没有“宏定义”、没有”重复编译”的文件,以.i作为文件名后缀。
编译(Compilation) 输入:预处理生成的.i/.ii文件(但是这个具体叫什么呢?)
输出:.s文件(这个叫做汇编语言源程序,不错,就是之后汇编阶段所要输入的文件)
注意:.s(小写)文件与.S(大写)文件还有所不同。其中.s之后的操作只有汇编,而.S文件还需要/允许在汇编之前执行预处理操作
这里没有需要特殊注意的地方,生成的.s或.S文件同样是文本文件,是汇编代码。
汇编(Assemble) 输入:上一步编译生成的汇编码源码
输出:机器码,.o/.obj后缀的文件
这一步中,每一个源文件(特指.c/.cpp)都会产生一个目标文件(.o/.obj)
链接(linking) 输入:上一步汇编生成的.o文件以及必要的库文件,可以是静态链接库(.a)也可以是动态链接库(.so)
输出:可执行文件(.out文件/Windows下是exe文件)
这一步主要是链接库文件并生成可执行文件,注意:带有main函数的源文件才会生成可执行文件(关于库文件的生成我们在CMake中继续介绍,在此不作深入讨论)