原文连接:www.vadimbulavin.com/xcode-build… by Vadim Bulavin前端
翻译:CoderWangxgit
每个 Swift 程序在真实设备上运行前都要经历一系列转换。这个过程一般是由 Xcode 构建系统处理的。在这篇文章中咱们将了解 Xcode 构建系统的各个部分。程序员
任何计算机系统都包含两方面:即 软件 与 硬件。github
硬件 是计算机的物理部分,例如显示器、键盘。硬件 一般由 软件 控制,软件 是指导硬件如何工做地一系列指令集合。软件负责编排过程,硬件负责实际执行工做,缺一不可。编程
做为软件工程师,咱们主要关注软件部分。然而,硬件并不能直接理解使用 Swift 编写的代码,它只能接收电荷形式的指令,包含两个级别,分别称做*‘逻辑 0’和‘逻辑 1’*。swift
这里就有个问题:“如何将 Swift 代码转换成硬件能接受的形式”? 答案是语言处理系统。后端
语言处理系统 是一系列程序的集合,这些程序能够从一组用任意源语言编写的指令中生成可执行程序。这样就容许程序员使用高级语言而不用去写机器代码,大大下降了编程复杂度。xcode
咱们在 iOS 或 macOS 开发中平常使用的语言处理系统就称做 Xcode 构建系统。app
Xcode 构建系统 的主要目标是协调各类不一样任务的执行,最终生成一个可执行程序。编程语言
Xcode 运行许多工具,并在它们之间传递数十个参数,处理执行顺序、并行性等等。这确定不是你在编写下一个 Swift 项目时想要手动处理的。
多数语言处理系统,包括 Xcode 构建系统,都包含 5 个部分:
它们经过以下图所示方式协做:
让咱们仔细了解一下各个步骤。
预处理步骤的目的是将程序转换为能够被提供给编译器的形式。它将宏替换为具体定义,发现依赖项并解析预处理器指令。
考虑到 Swift 编译器中没有预处理器,因此不容许在 Swift 项目中定义宏。尽管如此,Xcode 构建系统 仍是进行了部分补足,经过在项目构建设置中配置 Active Compilation Conditions (主动编译条件) 方式来进行预处理。
Xcode 经过低级构建系统 llbuild 来解析依赖项,llbuild 是开源的,能够在 Github 上的 swift-llbuild 页面 找到更多信息。
编译器 是一个程序,它将一个语言的源程序映射为另外一个语言中语义等效的目标程序。换句话说,编译器 将 Swift、Objective-C、C/C++ 代码转换为机器码而不丢失前者的含义。
Xcode 使用两个不一样的编译器:一个负责编译 Swift,另外一个负责编译 Objective-C、Objective-C++ 以及 C/C++ 文件。
clang
是苹果官方的 C 语言家族编译器,已经开源:swift-clang。
swiftc
是一个 Swift 编译器程序,被 Xcode 用于编译及运行 Swift 源代码。我冒昧地猜想你已经访问过这个连接至少一次:它位于Swift 语言仓库。
编译器 阶段以下图所示:
编译器由两个主要部分组成:前端和后端。
前端 部分将源程序分割为单独的部分,没有任何语义或类型信息,使用特定语法结构。而后编译器使用这个结构生成源程序的 中间描述(intermediate representation)。前端 也会建立并管理 符号表(symbol table),以搜集源程序相关信息。
符号(Symbol)是数据或代码片断的名称。
符号表 存储你所命名的变量、方法、类的名称,每一个 符号 都映射到一个肯定的数据块。
在 Swift 编译器 里 中间描述(intermediate representation) 被称做 Swift 中间语言 Swift Intermediate Language (SIL)。SIL 会被用于后续的分析及代码优化。直接从 Swift 中间语言 生成机器码是不可能的,所以 SIL 会再通过一次转换变为 LLVM 中间描述(LLVM Intermediate Representation)。
在 后端 阶段,以上LLVM 中间描述 会被转换为汇编码。
汇编器 将可读的汇编代码转换成 可重定向的机器代码(relocatable machine code),生成 Mach-O 文件,基本上就是代码与数据的集合。
上述定义中的术语:机器代码* 和 Mach-O 文件 还须要进一步解释。
机器代码 是一种数字化语言,表示一组可由 CPU 直接执行的指令。之因此命名为可重定向的,是由于无论对象文件在地址空间中何处,指令都会相对于所在空间来执行。
Mach-O 文件 是 iOS / macOS 操做系统中的一种特殊文件格式,用于对象文件、可执行文件及库。它是以一些有意义的块分组的字节流,运行于 iOS 设备上的 ARM 处理器或者 Mac 上的 Intel 处理器。
连接器 是一个计算机程序,它将不一样的对象文件和库合并起来生成一个能够在 iOS 或 macOS 系统上运行的 Mach-O 可执行文件。连接器 接收两种类型的文件做为输入,也就是来自 汇编 阶段的对象文件以及不一样类型的库( .dylib
, .tbd
, .a
)。
细心的读者可能已经注意到 汇编器 和 连接器 都生成了一个 Mach-O 文件做为输出。这二者应该有些不一样,对吧?
来自汇编阶段的对象文件并无处理完成,其中一些包含引用其余对象文件或库的缺失部分。举个例子,若是在代码中使用了 printf
方法,是 连接器 将这个符号与实现 printf
方法的 libc 库粘合起来的。它使用 编译 阶段生成的 符号表 来解析跨不一样对象文件与库之间的引用。
在 Xcode 中构建具备上述特性的 Swift 项目时,你能够已经发现过 “undefined symbol 未定义符号” 错误。
最后,做为操做系统一部分,加载器 会将程序载入内存并执行。加载器分配运行程序所需内存空间并将寄存器初始化为初始状态。
在软件工程中很难低估 语言处理系统 的重要性。咱们能够自由选择几乎任何高级编程语言,例如 Swift 或 Objective-C,而不用去编写硬件才能理解的 0 和 1 二进制代码。语言处理系统会处理其他工做,生成一个能够在 iPhone、Mac 或其余任何终端运行的可执行程序。
做为 iOS / macOS 开发者,咱们平常基础工做中都在使用 Xcode 构建系统。它的主要组件有:preprocessor 预处理器、compiler 编译器、assembler 汇编器、linker 连接器、以及 loader 加载器。Xcode 针对 Swift 和 Objective-C 使用不一样的编译器,对应分别是 swiftc
和 clang
。
理解 Xcode 编译过程是基础知识,对于初学者和经验丰富的开发人员都很是重要。
感谢阅读
若是你以为不错,能够在 Twitter 上关注原做者;若是发现问题或有更好建议,欢迎留言或经过 Github 与我讨论。