前言
计算机语言分为:机器语言、汇编语言和高级语言。
高级语言又能分为:编辑语言、解释语言。
解释语言
解释语言编写的程序在每次运行时都需要通过解释器对程序进行动态解释和执行,即解释一条代码,执行一条代码。
优点:可移植好,因为只需要各种系统有解释器便可运行,不需要乱七八糟的系统库支持
缺点:执行速度慢,因为相比直接执行,多了一个翻译过程。
典型语言:php,javascript
编译语言
编译型语言的程序只要经过编译器编译之后,每次运行程序都可以直接运行,不需要再次“翻译”。
优点:执行速度快
缺点:可移植性差,因为编译需要对操作系统的库做出链接,所以程序运行时需要用到特定的系统库
典型语言:objective-c,C++
文件后缀名
在iOS编译和链接的过程中,不同的文件后缀名代表不同的文件类型和中间过程。
`.i `文件:`.i `文件是预处理器处理源代码之后生成的文件,其中包含了宏展开、条件编译等预处理操作后的代码。`.s` 文件:`.s` 文件是汇编器生成的汇编代码文件。它将预处理器生成的 .i 文件翻译成机器指令的文本表示形式,每个汇编指令对应一条机器指令。`.o` 文件:`.o` 文件是编译器生成的目标文件,也被称为对象文件。它包含了汇编器生成的机器指令以及一些符号表、重定位信息和其他调试信息。`.m` 文件:`.m` 文件是 Objective-C 源代码文件的常见扩展名。它包含了 Objective-C 的代码,可以与 C 和 C++ 代码混合使用。
这些文件在编译和链接过程中的不同阶段产生,并在整个过程中相互转换和传递,最终生成可执行文件或库文件。
编译和链接过程
OC是编译型语言,使用Low Level Virtual Machine 的编译器开发工具套件(LLVM)生成机器码,机器码可以直接在CPU上执行,效率更快。
LLVM 是一个项目,其作用就是提供一个广泛的工具,可以将任何高级语言的代码编译为任何架构的 CPU 都可以运行的机器代码。它将整个编译过程分类了三个模块:前端、公用优化器、后端。clang 是 LLVM 的一个前端,它的作用是针对 C 语言家族的语言进行编译,像 c、c++、Objective-C。而 Swift 则自己实现了一个前端来进行 Swift 编译,优化器和后端依然是使用 LLVM 来完成。
- 预处理:处理macro 宏(如#define), import 头文件替换及处理其他的预编译指令,产生.i文件。(都是以#号开头)
- 编译:把预处理完的一系列文件进行一系列词法、语法、语义分析,并且优化后生成相应的汇编代码,产生.s文件。
- 汇编:汇编器将汇编代码生成机器指令,输出目标文件,产生.o文件。(根据汇编指令和机器指令的对照表一一翻译就可以了)
- 链接:在一个文件中可能会到其他文件,因此,还需要将编译生成的目标文件和系统提供的文件组合到一起,这个过程就是链接。经过链接,最后生成可执行文件。
经过编译和链接,才会把写的代码转换成计算机能识别的二进制指令。
详解
iOS整个编译链接过程如图
预处理
处理macro 宏, import 头文件替换及处理其他的预编译指令,产生.i文件(都是以#号开头!)。规则如下:
- "#define"删除并展开对应宏定义。
- 处理所有的条件预编译指令。如#if/#ifdef/#else/#endif。
- "#include/#import"包含的文件递归插入到此处。
- 删除所有的注释"//或/**/"。
- 添加行号和文件名标识,编译调试会用到。
编译
这个过程就是把上面的main.i文件进行:词法分析、语法分析、静态分析,优化生成相应的汇编代码,最终生成main.s文件。
- 词法分析:词法分析的任务是从源代码中读取输入字符,按照构词规则构词规则切分成一系列的单词(token),提交给语法分析使用。词法分析器的分析结果,即输出为token序列,其中token包含两部分内容,即token=类型枚举+属性值,token也被称为“词素”,指的是单个有意义的元素。
- 语法分析:语法分析以词法分析程序输出的Token流为输入,分析源程序的语法结构,判断它是否为相应程序设计语言的合法程序,最后生成符合特定文法的语法分析树。
- 静态分析:使用语法树和符号表中的信息来检查源程序是否和语言定义的语义一致, 同时它也收集类型信息,并把这些信息存放在语法树或符号表中,供随后的中间代码生成使用。
- 代码生成: LLVM 会对代码进行编译优化,例如针对全局变量优化、循环优化、尾递归优化等,最后输出汇编代码。然后根据中间语言生成依赖具体机器的汇编语言,并优化汇编语言。
汇编
将main.s文件编译成main.o文件。(也就是我们常说的目标文件)
这个过程就是把上面得到的main.s文件里面的汇编指令翻译成机器指令,最终生成等到main.o。
链接
这个过程就是将main.o编译成对应的Mach-O文件,也就是我们常说的可执行文件。链接的本质就是把一个或多个目标文件和需要的库(静态库/动态库,如果需要的话)组合成一个文件(Mach-O可执行文件)。