Swift编译过程

前言

做Swift开发一段时间了,一直在做上层的coding,很少输出Swift底层的东东,例如代码的编译过程。今天我们就来聊一聊编译过程。说起编译,最开始接触是大学的《编译原理》课程,说实话,这门课程是我大学期间,我认为最难的课程之一,然而对于现在来说,又是最最重要的知识点。掌握和理解编译原理,对深入理解App的底层原理非常重要。

在讲编译之前,先讲下构建(Build)。首先,构建和编译是不同的,前者是从一份代码变成一个可执行程序的过程;后者是一份代码变成机器码的过程(构建过程的一部分)。主要的差异点是最后一步的链接过程

下面先讲一下通用应用程序的构建的过程。

构建四步骤

应用程序的构建有四个步骤:

1.预处理(Prepressing)

2.编译(Compilation)

3.汇编(Assembly)

4.链接(Linking)

预处理(Prepressing)

处理源码中“#”开头的预编译指令。

1.删除所有”#define“,因为”#define“在底层指令中没有对应的指令,需要转化成具体指令;

2.处理”#if“,#”elif“、”#else“等条件预编译指令;

3.处理包含语句”#include“或”#import“;

4.保留#Pragma编译指令等等预处理的事情等等过程。

通过以上的预处理过程,优化了编写的部分代码,方便下一步的处理。

编译(Compilation)

把前一步处理完的文件进行一系列的词法分析、语法分析、语义分析和优化产生汇编代码文件。

汇编(Assembly)

将上一步骤生成的汇编代码转变成机器可以执行的指令。

链接(Linking)

是把各个模块之间相互引用的部分处理好,使得各个模块之间能够正常的衔接。

通过上面四个步骤,就可以把我们code的代码转化成可以运行的程序了。

Swift编译过程

讲完了通用的应用程序构建过程,再具体讲一讲Swift语言的构建过程。

苹果为Swift代码(Swift语言并非苹果公司首创的,在此之前已经存在了且是开源的,苹果公司从原始的Swift社区拿过来并在此基础上加入新的特性,最终独立与原始的Swift社区版本,成为一个不同的版本,再加上苹果的大力宣传。所以现在市面上所说的Swift就是苹果改进之后的Swift版本)单独写了swiftc来编译前端代码。为了兼容Objetive-C语言,swift在编译时需要对Objetive-C和Swift分开编译,整个流程大致如下示意图:图片

大致流程:

源代码经过clang编译器和swiftc编译器分别编译后生成中间代码,然后由LLVM后端对代码进行一步加工处理生成.o文件并进行链接,绑定对应的arch最终生成可执行文件。

说起编译器,不得不提下LLVM

LLVM

LLVM是一款跨平台编译器框架,包含了系列的模块化编译组件和工具链,以C++编写而成,用于优化以任意程序语言编写的程序的编译时间(compile-time)、链接时间(link-time)、运行时间(run-time)以及空闲时间(idle-time)。

LLVM启动于2000年,最初由美国UIUC大学的Chris Lattner博士主持开展。2006年Chris Lattner加盟Apple Inc.并致力于LLVM在Apple开发体系中的应用。

经典的LLVM三段式架构分为前端(Frontend),优化器(Optimizer)和后端(Backend)

前端可以使用不同的编译工具对代码文件做词法分析以形成抽象语法树AST,然后将分析好的代码转换成LLVM的中间表示IR(intermediate representation);优化器只对IR操作,通过一系列的pass对IR做优化;后端负责将优化好的IR解释成对应平台的机器码。图片

前端(Frontend)

前端经过词法分析(Lexical Analysis),语法分析(Syntactic Analysis)生成 AST,语义分析(Semantic Analysis),中间代码生成(Intermediate Code Generation)等步骤,生成IR。

优化器(Optimizer)

IR经过优化器进行优化,优化器会调用执行各类Pass。所谓Pass,就是遍历一遍IR,在进行针对性的处理的代码。LLVM 内置了若干Pass,开发者也可自定义Pass实现特定功能,比如插桩统计函数运行耗时等。

例如,Xcode中的Optimization Level就是一个很好的Pass选项

在Xcode – Build Setting – Apple Clang – Code Generation – Optimization Level中,可以选定优化级别。

  •   -O0表示无优化,即不调用任何优化Pass。
  •   其他优化级别则调用执行对应的Pass

图片

后端(Backend)

后端将IR转成生成相应CPU架构的机器码。为后面的链接做好准备。

LLVM的优点:

1.良好的归一性。不同的前端语言最终都转换成同一种的IR。

2.良好的扩展性。当需要支持新语言时只需实现前端部分,需要支持新的架构只需实现后端部分,连接前后端的是IR,IR独立于编程语言和机器架构,故IR阶段的优化可以做到抽象而通用。

讲完了LLVM,再讲下苹果的swiftc编译器。

swiftc编译器概述

swiftc是苹果单独为swift代码开发的一款编译器,相比较clang它有更多的约束来保证swift的代码安全。比如未初始化的变变量,边界和溢出检查。

swiftc编译器架构

整体而言,swiftc的主要职责在于将Swift源代码翻译为高效执行的机器码。其中swiftc的前端同样支持其它工具,包括与IDE 集成的语法高亮、代码补全、以及其它提供便利的组件。下面简单描述下swiftc的主要组件:

1.解析(Parsing)

解析器是一个简易的递归下降解析器(在 lib/Parse 中实现),并带有完整手动编码的词法分析器。

2.语义分析(Semantic Analysis)

语义分析阶段(在 lib/Sema 中实现)负责获取已解析的 AST(抽象语法树)并将其转换为格式正确且类型检查完备的 AST,以及在源代码中提示出现语义问题的警告或错误。语义分析包含类型推断,如果可以成功推导出类型,则表明此时从已经经过类型检查的最终 AST 生成代码是安全的。

3.Clang 导入器(Clang Importer)

Clang 导入器(在 lib/ClangImporter 中实现)负责导入 Clang 模块,并将导出的 C 或 Objective-C API 映射到相应的 Swift API 中。最终导入的 AST 可以被语义分析引用。

4.SIL 生成(SIL Generation)

Swift 中间语言(Swift Intermediate Language,SIL)是一门高级且专用于 Swift 的中间语言,适用于对 Swift 代码的进一步分析和优化。SIL 生成阶段(在 lib/SILGen 中实现)将经过类型检查的 AST 弱化为所谓的「原始」SIL。

5.SIL 保证转换(SIL Guaranteed Transformations)

SIL 保证转换阶段(在 lib/SILOptimizer/Mandatory中实现)负责执行额外且影响程序正确性的数据流诊断(比如使用未初始化的变量)。这些转换的最终结果是「规范」SIL。

6.SIL 优化(SIL Optimizations)

SIL 优化阶段(在 lib/Analysis、lib/ARC、lib/LoopTransforms 以及 lib/Transforms 中实现)负责对程序执行额外的高级且专用于 Swift 的优化,包括自动引用计数优化、去虚拟化、以及通用的专业化。

7.LLVM IR 生成(LLVM IR Generation)

IR生成阶段(在lib/IRGen中实现)将SIL弱化为LLVM LR,此时LLVM可以继续优化并生成机器码。图片

通过以上7步,加上LLVM中后端处理,完成应用程序的编译并生成机器码。为最后的应用程序的链接做好准备。

至此,Swift的编译过程介绍到此。

参考资料:
http://t.zoukankan.com/kekec-p-13707098.html
https://www.jianshu.com/p/ba7b80f181f6
https://blog.csdn.net/jiodg/article/details/125249261

声明:文中观点不代表本站立场。本文传送门:http://eyangzhen.com/17230.html

(0)
联系我们
联系我们
分享本页
返回顶部