一、编译流程
1.预处理
2.编译
编译阶段后面会有文章进行详细解读
3.汇编
4.链接
二、编译阶段
1.编译阶段阶段分别是检查和各个文件组成整体,也会出现全局空间的函数多出定义。原因是头文件被释放到多个源文件中
tips:
1.标准C和C++将编译过程
标准C和C++将编译过程定义为9个阶段(PhasesofTranslation):
- 字符映射(CharacterMapping)
文件中的物理源字符被映射到源字符集中,其中包括三字符运算符的替换、控制字符(行尾的回车换行)的替换。许多非美式键盘不支持基本源字符集中的一些字符,文件中可用三字符来代替这些基本源字符,以??为前导。但如果所用键盘是美式键盘,有些编译器可能不对三字符进行查找和替换,需要增加-trigraphs编译参数。在C++程序中,任何不在基本源字符集中的字符都被它的通用字符名替换。
- 行合并(LineSplicing)
以反斜杠/结束的行和它接下来的行合并。
- 标记化(Tokenization)
每一条注释被一个单独的空字符所替换。C++双字符运算符被识别为标记(为了开发可读性更强的程序,C++为非ASCII码开发者定义了一套双字符运算符集和新的保留字集)。源代码被分析成预处理标记。
- 预处理(Preprocessing)
调用预处理指令并扩展宏。使用#include指令包含的文件,重复步骤1到4。上述四个阶段统称为预处理阶段。
- 字符集映射(Character-setMapping)
源字符集成员、转义序列被转换成等价的执行字符集成员。例如:'/a'在ASCII环境下会被转换成值为一个字节,值为7。
- 字符串连接(StringConcatenation)
相邻的字符串被连接。例如:"""hahaha""huohuohuo"将成为"hahahahuohuohuo"。
- 翻译(Translation)
进行语法和语义分析编译,并翻译成目标代码。
- 处理模板
处理模板实例。
- 连接(Linkage)
解决外部引用的问题,准备好程序映像以便执行。
2.如何避免出现全局空间的函数多出定义?
- 对头文件中出现的内容进行限制
- 通过"#define"配合条件编译解决
三、linux相关指令gcc/g++
1.编译阶段命令
阶段 | 选项 | 作用 | 命令 |
预处理 | -E | GCC的选项-E使GCC在进行完预处理后即停止 | |
编译 | -S | GCC的选项-S使GCC在执行完编译后停止,生成汇编程序 | |
汇编 | -c | GCC的选项-c使GCC在执行完汇编后停止,生成目标文件 | |
2.链接阶段命令
上图中的链接库分为动态链接库和静态链接库,即.a和.so
静态链接和动态链接的区别?
静态库链接和动态库链接的查找路径
静态库链接库.a查找路径,在Linux系统中,gcc编译链接时的动态库搜索路径的顺序通常为:
- 首先从gcc命令的参数-L指定的路径寻找;
- 再从环境变量LIBRARY_PATH指定的路径寻址;
- 再从默认路径/lib、/usr/lib、/usr/local/lib寻找;
动态库链接.so查找路径,在Linux系统中,执行二进制文件时的动态库搜索路径的顺序通常为:
- 将动态库添加到系统默认的搜索路径下,如/lib、/usr/lib
- 设置临时动态库路径的环境变量,这种方法设置的是临时的,系统重启之后就没了
$ export LD_LIBRARY_PATH=./
# 取消设置
$ export LD_LIBRARY_PATH=
- /etc/ld.so.cache中缓存了动态库路径,可以通过修改配置文件/etc/ld.so.conf中指定的动态库搜索路径,然后执行ldconfig命令来改变
- 编译链接添加-WL,-rpath命令选项,将运行时动态库的搜索路径记录在可执行程序中
- 再从默认路径/lib、/usr/lib寻找。
阶段 | 选项 | 作用 | 命令 |
链接 | - | 编译链接一起,生成a.out | |
-I | 指定文件查找目录 | -include file -I file 指定包含的文件 | |
-L | 指定链接库(静态库和动态库),动态库和静态库名字一致时,优先使用动态库 | -L library 指定路径 -llibrary 指定特定文件 | |
-fPIC | 生成动态库 | |
附加项
阶段 | 选项 | 作用 | 命令 |
-g | 在编译的时候,产生调试信息,程序运行时可以dbg调试 | |