iOS
编译采用 Clang
作为编译器前端,LLVM
作为编译器后端,编译器前端负责语法分析,语义分析,生成生成中间码 (LLVM IR)
,在这个过程中,会进行类型检查,如果发现错误或者警告会标注出来在哪一行;编译器后端会进行机器无关的代码优化,生成机器语言,并且进行机器相关的代码优化。
当一个 xcode
工程 build
之后一般会执行如下几个步骤:
Clang 的编译过程
预处理
预处理器会处理源文件中的宏定义,将代码中的宏用其对应定义的具体内容进行替换,删除注释,展开头文件,产生 .i
文件。
词法分析
预处理完成了以后,开始词法分析,这里会把代码切成一个个 Token
,比如大小括号,等于号还有字符串等。
语法分析
语法分析,在 Clang
中由 Parser
和 Sema
两个模块配合完成,验证语法是否正确,根据当前语言的语法,生成语意节点,并将所有节点组合成抽象语法树 AST
。
静态分析
一旦编译器把源码生成了抽象语法树,编译器可以对这棵树做分析处理,以找出代码中的错误,比如类型检查:即检查程序中是否有类型错误。例如:如果代码中给某个对象发送了一个消息,编译器会检查这个对象是否实现了这个消息(函数、方法)。此外,clang
对整个程序还做了其它更高级的一些分析,以确保程序没有错误。
类型检查
一般会把类型检查分为两类:动态的和静态的。动态的在运行时做检查,静态的在编译时做检查。以往,编写代码时可以向任意对象发送任何消息,在运行时,才会检查对象是否能够响应这些消息。由于只是在运行时做此类检查,所以叫做动态类型。
至于静态类型,是在编译时做检查。当在代码中使用 ARC
时,编译器在编译期间,会做许多的类型检查:因为编译器需要知道哪个对象该如何使用。
LLVM 的编译过程
目标代码的生成与优化
CodeGen
负责将语法树 AST
丛顶至下遍历,翻译成 LLVM IR
中间码,LLVM IR
中间码编译过程的前端的输出后端的输入。
编译器后端主要包括代码生成器、代码优化器。代码生成器将中间代码转换为目标代码,代码优化器主要是进行一些优化,比如删除多余指令,选择合适寻址方式等,如果开启了 bitcode
苹果会做进一步的优化,有新的后端架构还是可以用这份优化过的 bitcode
去生成。优化中间代码生成输出汇编代码,把之前的 .i
文件转换为汇编语言,产生 .s
文件
汇编
目标代码需要经过汇编器处理,把汇编语言文件转换为机器码文件,产生 .o
文件。
链接
链接又分为静态链接和动态链接。
对 .o
文件中的对于其他的库的引用的地方进行引用,生成最后的可执行文件(同时也包括多个 .o
文件进行 link
)。
静态链接
静态链接:在编译链接期间发挥作用,把目标文件和静态库一起链接形成可执行文件。
动态链接
动态链接:链接过程推迟到运行时再进行。
如果多个程序都用到了一个库,那么每个程序都要将其链接到可执行文件中,非常冗余,动态链接的话,多个程序可以共享同一段代码,不需要在磁盘上存多份拷贝,但是动态链接发生在启动或运行时,增加了启动时间,造成一些性能的影响。 静态库不方便升级,必须重新编译,动态库的升级更加方便。
参考
点击 Run 之后发生了什么?