原文連接: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 與我討論。