[譯]理解 Xcode 構建系統

原文連接: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 構建系統 的主要目標是協調各類不一樣任務的執行,最終生成一個可執行程序。編程語言

Xcode 運行許多工具,並在它們之間傳遞數十個參數,處理執行順序、並行性等等。這確定不是你在編寫下一個 Swift 項目時想要手動處理的。

多數語言處理系統,包括 Xcode 構建系統,都包含 5 個部分:

  • Preprocessor(預處理器)
  • Compiler(編譯器)
  • Assembler(彙編器)
  • Linker(連接器)
  • Loader(加載器)

它們經過以下圖所示方式協做:

language processing system

讓咱們仔細瞭解一下各個步驟。

Preprocessing 預處理

預處理步驟的目的是將程序轉換爲能夠被提供給編譯器的形式。它將宏替換爲具體定義,發現依賴項並解析預處理器指令。

考慮到 Swift 編譯器中沒有預處理器,因此不容許在 Swift 項目中定義宏。儘管如此,Xcode 構建系統 仍是進行了部分補足,經過在項目構建設置中配置 Active Compilation Conditions (主動編譯條件) 方式來進行預處理。

Xcode 經過低級構建系統 llbuild 來解析依賴項,llbuild 是開源的,能夠在 Github 上的 swift-llbuild 頁面 找到更多信息。

Compiler 編譯器

編譯器 是一個程序,它將一個語言的源程序映射爲另外一個語言中語義等效的目標程序。換句話說,編譯器SwiftObjective-CC/C++ 代碼轉換爲機器碼而不丟失前者的含義。

Xcode 使用兩個不一樣的編譯器:一個負責編譯 Swift,另外一個負責編譯 Objective-CObjective-C++ 以及 C/C++ 文件。

clang 是蘋果官方的 C 語言家族編譯器,已經開源:swift-clang

swiftc 是一個 Swift 編譯器程序,被 Xcode 用於編譯及運行 Swift 源代碼。我冒昧地猜想你已經訪問過這個連接至少一次:它位於Swift 語言倉庫

編譯器 階段以下圖所示:

Xcode compiler

編譯器由兩個主要部分組成:前端和後端。

前端 部分將源程序分割爲單獨的部分,沒有任何語義或類型信息,使用特定語法結構。而後編譯器使用這個結構生成源程序的 中間描述(intermediate representation)前端 也會建立並管理 符號表(symbol table),以蒐集源程序相關信息。

符號(Symbol)是數據或代碼片斷的名稱。

符號表 存儲你所命名的變量、方法、類的名稱,每一個 符號 都映射到一個肯定的數據塊。

Swift 編譯器中間描述(intermediate representation) 被稱做 Swift 中間語言 Swift Intermediate Language (SIL)SIL 會被用於後續的分析及代碼優化。直接從 Swift 中間語言 生成機器碼是不可能的,所以 SIL 會再通過一次轉換變爲 LLVM 中間描述(LLVM Intermediate Representation)

後端 階段,以上LLVM 中間描述 會被轉換爲彙編碼。

Assembler 彙編器

彙編器 將可讀的彙編代碼轉換成 可重定向的機器代碼(relocatable machine code),生成 Mach-O 文件,基本上就是代碼與數據的集合。

上述定義中的術語:機器代碼* 和 Mach-O 文件 還須要進一步解釋。

機器代碼 是一種數字化語言,表示一組可由 CPU 直接執行的指令。之因此命名爲可重定向的,是由於無論對象文件在地址空間中何處,指令都會相對於所在空間來執行。

Mach-O 文件 是 iOS / macOS 操做系統中的一種特殊文件格式,用於對象文件、可執行文件及庫。它是以一些有意義的塊分組的字節流,運行於 iOS 設備上的 ARM 處理器或者 Mac 上的 Intel 處理器。

Linker 連接器

連接器 是一個計算機程序,它將不一樣的對象文件和庫合併起來生成一個能夠在 iOS 或 macOS 系統上運行的 Mach-O 可執行文件。連接器 接收兩種類型的文件做爲輸入,也就是來自 彙編 階段的對象文件以及不一樣類型的庫( .dylib, .tbd , .a)。

細心的讀者可能已經注意到 彙編器連接器 都生成了一個 Mach-O 文件做爲輸出。這二者應該有些不一樣,對吧?

來自彙編階段的對象文件並無處理完成,其中一些包含引用其餘對象文件或庫的缺失部分。舉個例子,若是在代碼中使用了 printf 方法,是 連接器 將這個符號與實現 printf 方法的 libc 庫粘合起來的。它使用 編譯 階段生成的 符號表 來解析跨不一樣對象文件與庫之間的引用。

Xcode 中構建具備上述特性的 Swift 項目時,你能夠已經發現過 「undefined symbol 未定義符號」 錯誤。

Loader 加載器

最後,做爲操做系統一部分,加載器 會將程序載入內存並執行。加載器分配運行程序所需內存空間並將寄存器初始化爲初始狀態。

總結

在軟件工程中很難低估 語言處理系統 的重要性。咱們能夠自由選擇幾乎任何高級編程語言,例如 SwiftObjective-C,而不用去編寫硬件才能理解的 0 和 1 二進制代碼。語言處理系統會處理其他工做,生成一個能夠在 iPhone、Mac 或其餘任何終端運行的可執行程序。

做爲 iOS / macOS 開發者,咱們平常基礎工做中都在使用 Xcode 構建系統。它的主要組件有:preprocessor 預處理器compiler 編譯器assembler 彙編器linker 連接器、以及 loader 加載器Xcode 針對 SwiftObjective-C 使用不一樣的編譯器,對應分別是 swiftcclang

理解 Xcode 編譯過程是基礎知識,對於初學者和經驗豐富的開發人員都很是重要。


感謝閱讀

若是你以爲不錯,能夠在 Twitter 上關注原做者;若是發現問題或有更好建議,歡迎留言或經過 Github 與我討論。

相關文章
相關標籤/搜索