本节主要参考KralLee的文章iOS App 的编译过程。
编译其实是一个用代码解释代码的过程。在 Objective-C 和 Swift 的编译过程中,用来解释代码的,使用的是Low Level Virtual Machine 的编译器开发工具套件(LLVM)。简单的说,LLVM 是一个项目,其作用就是提供一个广泛的工具,可以将任何高级语言的代码编译为任何架构的 CPU 都可以运行的机器代码。它将整个编译过程分类了三个模块:前端、公用优化器、后端。
- 前端:对目标语言代码进行语法分析,语义分析,生成中间代码。在这个过程中,会进行类型检查,如果发现错误或者警告会标注出来在哪一行。我们在开发的过程中,其实 Xcode 也会使用前端工具对你的代码进行分析,并实时的检查出来某些错误。前端是针对特定语言的,如果需要一个新的语言被编译,只需要再写一个针对新语言的前端模块即可。
- 公用优化器:将生成的中间文件进行优化,去除冗余代码,进行结构优化。
- 后端:后段将优化后的中间代码再次转换,变成汇编语言,并再次进行优化,最后将各个文件代码转换为机器代码并链接。链接是指将不同代码文件编译后的不同机器代码文件合并成一个可执行文件。
clang
是 LLVM 的一个前端,它的作用是针对 C 语言家族的语言进行编译,像 c、c++、Objective-C。而 Swift 则自己实现了一个前端来进行 Swift 编译,优化器和后端依然是使用 LLVM 来完成,后面会专门对 Swift 语言的前端编译流程进行分析。
- iOS 项目编译过程简介
Xcode 在编译 iOS 项目的时候,使用的正是 LLVM,其实我们在编写代码以及调试的时候也在使用 LLVM 提供的功能。例如代码高亮(clang)、实时代码检查(clang)、代码提示(clang)、debug 断点调试(LLDB)。这些都是 LLVM 前端提供的功能,而对于后端来说,我们接触到的就是关于 arm64、armv7、armv7s 这些 CPU 架构了。
我们的项目是一个 target,一个编译目标,它拥有自己的文件和编译规则,在我们的项目中可以存在多个子项目,这在编译的时候就导致了使用了 Cocoapods 或者拥有多个 target 的项目会先编译依赖库。
1. 写入辅助文件:将项目的文件结构对应表、将要执行的脚本、项目依赖库的文件结构对应表写成文件,方便后面使用;并且创建一个 .app 包,后面编译后的文件都会被放入包中。
2. 运行预设脚本:Cocoapods 会预设一些脚本,当然你也可以自己预设一些脚本来运行。这些脚本都在 Build Phases 中可以看到。
3.编译文件:针对每一个文件进行编译,生成可执行文件 Mach-O,这过程涉及 LLVM 的完整流程,包括前端、优化器、后端。
4. 链接文件:将项目中的多个可执行文件合并成一个文件。
5. 拷贝资源文件:将项目中的资源文件拷贝到目标包;
6. 编译 storyboard 文件:storyboard 文件也是会被编译的;
7. 链接 storyboard 文件:将编译后的 storyboard 文件链接成一个文件;
8. 编译 Asset 文件:我们的图片如果使用 Assets.xcassets 来管理图片,那么这些图片将会被编译成机器码,除了 icon 和 launchImage;
9. 运行 Cocoapods 脚本:将在编译项目之前已经编译好的依赖库和相关资源拷贝到包中。
10. 对包进行签名
11. 完成打包
在上述流程中:2 - 9 步骤的数量和顺序并不固定,这个过程可以在Build Phases
中指定。Phases:阶段、步骤,这个选项Tab在Xcode中的意思就是编译步骤。其实在Xcode中我们不仅可以设定整个编译步骤和顺序,还可以对编译规则(Build Rules)和具体步骤的参数(Build Settings)进行设定。关于整个编译流程的日志和设定,可以查看这篇文章:Build 过程,跟着它的步骤来查看自己的项目将有助于你理解整个编译流程。还可以参考滴滴技术专家戴铭写的深入剖析 iOS 编译 Clang LLVM进行进一步学习。
- Swift文件的编译过程
解析:解析器是一个简单的递归下降解析器(在 lib / Parse 中实现),带有集成的手动编码词法分析器。解析器负责生成没有任何语义或类型信息的抽象语法树(AST),并针对输入源的语法问题发出警告或错误。
语意分析:语义分析(在 lib / Sema 中实现)负责解析 AST 并将其转换为格式良好的完全检查形式的 AST,并在源代码中发出语义问题的警告或错误。语义分析包括类型推断,如果成功,则所得到的代码是类型检查安全的 AST 。
Clang导入器:Clang导入器(在 lib / ClangImporter 中实现)导入Clang模块,并将它们导出的 C 或 Objective-C API 映射到相应的 Swift API中。结果导入的 AST 可以通过语义分析来引用。
SIL生成:Swift中间语言(Swift Intermediate Language,简称SIL)是一种高级的Swift特有的中间语言,适用于 Swift 代码的进一步分析和优化。SIL 生成阶段(在 lib / SILGen 中实现)将类型检查的 AST 降低到所谓的 “原始” SIL。SIL的设计描述在 docs/ SIL.rst 中可以看到。
SIL优化:在SIL优化(在 lib/Analysis,lib/ ARC,lib/LoopTransforms,和 lib/Transforms 中实现)执行额外的高级别,Swift 特有的优化的程序,包括(例如)自动引用计数优化,虚拟化和通用专业化。
LLVM IR生成:IR生成(在 lib/IRGen 中实现)将 SIL 降到 LLVM IR,此时LLVM可以继续对其进行优化并生成机器码。
网友评论