Xcode編譯流程

 
Xcode的構建過程本質上是執行一系列構建任務。如:代碼檢測,編譯代碼,鏈接目標文件,拷貝資源(圖片, plist, nib)文件,代碼簽名等。大部分任務是執行命令行工具,如(clang編譯、 ld鏈接、 codesign簽名, altool上傳)。這些工具使用xcode項目的配置信息,根據特定的順序執行。bulid System的工作就是創建構建任務,並協調這些任務按照正確的順序執行。
構建任務的順序是任務之間的依賴關係定的。
如有2個類文件,A文件和B文件, B文件使用了A文件的方法,引入了A文件。那麼他們的編譯任務是編譯A,再編譯B,等都編譯好,將兩個.o文件進行鏈接。
 
我們每次構建項目是對一個具體的 Target發起的,每個Target擁有自己的文件和編譯規則,在項目裏可以存在多個子項目,這導致了在編譯的時候如果使用了 Cocoapods 或者擁有多個 target 的項目會先編譯依賴庫,然後再編輯當前項目。
如果使用的workspace開發,會遍歷裏面管理的項目,找到Target的依賴進行編譯,然後再編譯當前項目。這些依賴庫的Target的編譯過程和我們項目的編譯流程是一樣的。

Xcode編譯流程
編譯準備階段
1.創建編譯計劃,檢查依賴: 檢查當前項目中使用的依賴庫是否已經安裝並能夠被正確地引用;確定編譯順序,
如工程A下有子工程B,類C中引用了類D,要根據依賴關係創建編譯計劃,先編譯獨立的類,子項目;再編譯有依賴的類和主項目。
2.創建構建產物過程中和結束時需要的目錄
 
編譯階段
1.寫輔助文件:創建app包目錄,後面編譯後的文件都會被放入app包目錄中;將項目的文件結構寫成.hmap映射文件,方便後面引用查詢使用;
生成.hmap文件:當編譯器處理.h文件時,它會生成一個.hmap文件,包含了所有的.h文件及其對應的目標文件的信息。這些信息將被用來加速下一次編譯過程。.hmap文件通常被存儲在Derived Data目錄下。
2.運行預設腳本:Cocoapods 會預設一些腳本,當然你也可以自己預設一些腳本來運行。這些腳本都在 Build Phases 中可以看到;【'[CP] Check Pods Manifest.lock','Copy Pods Resources'】


3.編譯文件:針對每一個文件進行編譯,先編譯.Swift後編譯.m文件,可以查看每個文件的編譯時間以及error和warning。
編譯源碼文件是編譯階段的重點,它會生成 Mach-O類型的.o文件。這過程涉及到了 LLVM三相設計的 的完整流程:編譯前端、優化器、編譯後端。
4.鏈接文件:將項目中的多個可執行文件合併成一個文件;鏈接分爲動態鏈接和靜態鏈接,這2項也是程序員必須要面對的2個重要概念,這個原理衍生了很多重要的應用場景,如:iOS原生代碼的熱更新,啓動性能優化,APP瘦身的符號剪裁等。
5.拷貝資源文件:將項目中的資源文件拷貝到目標app包;

6.編譯,鏈接 storyboard 文件:storyboard 文件也是會被編譯的;項目中的 storyboard 會被編譯成一個二進制文件,包含了界面的所有信息和結構,這個文件的後綴名爲 .storyboardc。.storyboardc 文件會在鏈接階段被鏈接到最終的應用程序中,以展示應用程序的用戶界面。
7.編譯 xib 文件:。 xib 文件會先解析成 XML 格式的文件,然後編譯成二進制格式的文件,即 nib 文件。編譯後的 nib 文件會被打包到應用程序的 bundle 中。
8.編譯 Asset 文件:我們的圖片如果使用 Assets.xcassets 來管理圖片,那麼這些圖片將會被編譯成機器碼,除了 icon 和 launchImage;

9.運行 Cocoapods 腳本:將在編譯項目之前已經編譯好的依賴庫和相關資源拷貝到包中。
10.將 Swift 標準庫拷貝到包中


11.生成 .app 包
12.對包進行簽名
13.完成打包

XCode中項目的結構關係
Target:表示一種產物類型,它有很多設置可以做細節修改,如:Build Settings, Build Phases, Build Rules。
Configuration: 構建變體,如每個Target下默認就有2個構建變體Debug, Release。 這2個構建變體的設置內容都可以進行修改,如Deubeg下不產生DSYM符號文件加速編譯,Release下產生DSYM符號文件用於排查線上問題。
Scheme:產物生成驅動器,定義了產物生成的組成過程,Target和Configuaration是靜態的配置定義,Scheme是對這些定義的消費。
Project:是直接容器,它直接管理者代碼文件,資源文件,腳本文件等。它可以引入其他Project作爲它的依賴。
WorkSpace: 它是管理Project的項目容器,在它下面管理的Project可以通過依賴而使用,如A,B是WorkSpace下的兩個Project, A在它的Frameworks,Libraries..下點擊“+”添加B的產物就可以使用了。如果使用cocopods時,這些會被自動做。

編譯性語言與解釋性語言
解釋性語言:邊解釋邊運行。特點是調試快,運行慢。
解釋器在運行的時候把代碼逐行做詞法分析,語法分析,語義分析,生成可執行的中間碼,然後執行中間碼。
編譯性語言:先編譯成可以在CPU上直接運行的機器碼,再執行。特點是運行快,調試慢。
通過編譯器(採用三相設計:編譯器前端,LLVM IR中間碼優化器,編譯器後端),將代碼字符串做詞法分析,語法分析,語義分析,生成中間碼IR。
然後把IR中間碼交給優化器做優化。
IR優化器處理完後把結果交給編譯器後端編譯成不同架構(arm64, i386)的可執行文件。

三相設計
假如有N種語言(C、OC、C++、Swift…)的前端,同時也有M個架構(模擬器、arm64、x86…)的Target,是否就需要 N × M 個編譯器?
三相架構的價值就體現出來了,通過共享優化器的中轉,很好的解決了這個問題。
假如你需要增加一種語言,只需要增加一種前端;假如你需要增加一種處理器架構,也只需要增加一種後端,而其他的地方都不需要改動。

LLVM的組成
在Xcode編譯iOS項目的時候,都是使用的LLVM,其實在編寫代碼以及調試的時候都在接觸LLVM提供的功能,例如:代碼的亮度(Clang)、實時代碼檢查(Clang)、代碼提示(Clang)、debug斷點調試(LLDB)。
LLVM項目是模塊化和可重用的編譯器和工具鏈技術的集合。LLVM主要的子項目有一下幾個:
1.LLVM核心庫:
LLVM提供一個獨立的鏈接代碼優化器,爲許多流行CPU(以及一些不太常見的CPU)的代碼生成支持。
這些庫是圍繞一個指定良好的代碼表示構建的,稱爲LLVM中間表示(“LLVM IR”)。
LLVM還可以充當JIT編譯器 - 它支持x86 / x86_64和PPC / PPC64程序集生成,並具有針對編譯速度的快速代碼優化。
2.LLVM IR 生成器Clang:
Clang是LLVM的一個前端,它是LLVM的C / C ++ / Objective-C編譯器,旨在提供驚人的快速編譯(例如,在調試配置中編譯Objective-C代碼時比GCC快3倍),非常有用的錯誤和警告消息以及提供構建優秀源代碼工具的平臺。
3.LLDB項目:
LLDB項目以LLVM和Clang提供的庫爲基礎,提供了一個出色的本機調試器。它使用Clang AST和表達式解析器,LLVM JIT,LLVM反彙編程序等,以便提供“正常工作”的體驗。在加載符號時,它也比GDB快速且內存效率更高。
4.lld項目:
lld項目旨在成爲clang / llvm的內置鏈接器。目前,clang必須調用系統鏈接器來生成可執行文件。



參考文章:

https://blog.csdn.net/dangyalingengjia/article/details/103336421
https://blog.csdn.net/Future_One/article/details/81882359
http://chuquan.me/2021/02/16/understand-ios-xcode-build-process/
https://xilankong.github.io/ios開發基礎/2020/07/29/Xcode-build過程都做了什麼.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章