這篇文章是對于自己學(xué)習(xí) App編譯過程的一個總結(jié)
學(xué)習(xí)的相關(guān)文章
iOS App的編譯過程
iOS 編譯過程的原理和應(yīng)用
iOS 中的靜態(tài)庫與動態(tài)庫勇垛,區(qū)別、制作和使用
本文的大綱
為何要了解
- 自己的興趣方篮,解開一些疑惑付秕;
- 有利于解決一些編譯過程中出現(xiàn)的問題;
- 對于優(yōu)化App有很大的幫助锉矢。
什么是編譯
為什么要編譯
我們通常所使用的編程語言編寫的代碼梯嗽,計算機的CPU(只能執(zhí)行二進制代碼)無法執(zhí)行,所以要編譯沽损。
為什么要編譯
什么是編譯
利用編譯程序?qū)⒏呒壵Z言所編寫的代碼變?yōu)镃PU可執(zhí)行的代碼的過程就叫編譯灯节。
App的編譯過程
我分別用OC和Swift語言創(chuàng)建兩個Demo,通過BulidLog看一下整個編譯過程:
Build的得到的.app也可以通過查看包內(nèi)容,直觀的看到得到的文件
根據(jù)圖中和參考的文章總結(jié)一下 iOS 項目編譯過程:
- 寫入輔助文件:將項目的文件結(jié)構(gòu)對應(yīng)表炎疆、將要執(zhí)行的腳本卡骂、項目依賴庫的文件結(jié)構(gòu)對應(yīng)表寫成文件,方便后面使用形入;
- 創(chuàng)建App架構(gòu):為填充后面步驟編譯得到的文件等全跨;
- 運行預(yù)設(shè)腳本:Cocoapods 會預(yù)設(shè)一些腳本,當(dāng)然你也可以自己預(yù)設(shè)一些腳本來運行亿遂。這些腳本都在 Build Phases 中可以看到浓若;
- 編譯.m文件:這個過程是由LLVM完成的,編譯成一個可執(zhí)行文件(Mach-0)崩掘;
- 鏈接編譯后得到的文件七嫌;
- 拷貝項目中的資源,比如 圖片資源苞慢;
- 編譯 storyboard
- 編譯 asset文件:圖片如果使用 Assets.xcassets 來管理圖片诵原,那么這些圖片將會被編譯成機器碼,除了 icon 和 launchImage挽放;
- 處理info.plist 绍赛;
- 執(zhí)行CocoaPod腳本;
- 拷貝swift標(biāo)準(zhǔn)包辑畦;
- 構(gòu)建.app并簽名吗蚌;
- 完成打包。
以上纯出,就是iOS項目大體的編譯過程蚯妇,下面說一下解釋代碼用到的LLVM 。
什么是LLVM
The LLVM Project is a collection of modular and reusable compiler and toolchain technologies. Despite its name, LLVM has little to do with traditional virtual machines. The name "LLVM" itself is not an acronym; it is the full name of the project.
LLVM項目是模塊化暂筝、可重用的編譯器和工具鏈技術(shù)的集合箩言。盡管名為LLVM,但它與傳統(tǒng)的虛擬機幾乎沒有關(guān)系焕襟≡墒眨“LLVM”這個名字本身并不是首字母縮略詞;這是項目的全稱。
LLVM在編譯過程中分為了三個模塊: 前端鸵赖、中間優(yōu)化器和后端 务漩。(跟web前端,service后端沒有任何關(guān)系)它褪。
LLVM各個模塊的作用:
- 前端:對目標(biāo)語言代碼進行語法分析饵骨,語義分析,生成中間代碼茫打。在這個過程中宏悦,會進行類型檢查镐确,如果發(fā)現(xiàn)錯誤或者警告會標(biāo)注出來在哪一行包吝;
- 中間優(yōu)化器:對中間代碼進行優(yōu)化饼煞,去除冗余代碼,這個過程會進行BitCode的生成诗越,鏈接期優(yōu)化等砖瞧;
- 后端:先進行與機器無關(guān)的代碼優(yōu)化,生成匯編語言嚷狞,在生成匯編語言之后會再進次進行與機器相關(guān)的代碼優(yōu)化块促,最后將各個文件的機器代碼鏈接。
在iOS中床未,OC和Swift兩種語言的編譯在前端是有差別的:OC中使用的編譯器前端為:Clang,在Swift中使用的編譯器前端為swift自己編寫的竭翠,這個我們可以在BuildLog里面具體看到。
OC的文件編譯處理過程:
Objective-C 的文件中薇搁,只有 .m 文件會被編譯 .h 文件只是一個暴露外部接口的頭文件斋扰,它的作用是為被編譯的文件中的代碼做簡單的共享,并且因為OC沒有private和public的用法啃洋,用.h和.m來實現(xiàn)private和public传货。
- 預(yù)處理 :處理一些預(yù)處理指令( 比如#define、#ifdef,#else,#endif等)并將預(yù)處理后的代碼進行符號化處理宏娄,以便下一步進行詞法分析和語義分析问裕;
- 詞法分析和語義分析:
<1> 將符號化的代碼抽象為語法樹(abstract syntax tree – AST);
<2> 靜態(tài)分析:對語法樹進行遍歷分析,包括類型檢查孵坚、實現(xiàn)檢查(某個類是否存在某個方法)粮宛、變量使用,還會有一些復(fù)雜的檢查卖宠,例如在 Objective-C 中巍杈,給某一個對象發(fā)送消息(調(diào)用某個方法),檢查這個對象的類是否聲明這個方法(但并不會去檢查這個方法是否實現(xiàn)逗堵,這個錯誤是在運行時進行檢查的)秉氧,如果有什么錯誤就會進行提示。因此可見蜒秤,Xcode 對 clang 做了非常深度的集成汁咏,在編寫代碼的過程中它就會使用 clang 來對代碼進行分析,并及時對代碼錯誤進行提示作媚。- 生成 LLVM 代碼(也就是中間代碼LLVM Intermediate Representation LLVM IR)攘滩,并將代碼遞交給優(yōu)化器,這也是LLVM前端 Clang的最后一步纸泡;
- 優(yōu)化:將一些不合適且消耗內(nèi)存的代碼進行優(yōu)化漂问;
- 生成目標(biāo)文件:這之后就是由LLVM后端完成了,將優(yōu)化過的代碼根據(jù)不同架構(gòu)的 CPU 轉(zhuǎn)化生成匯編代碼,再生成對應(yīng)的可執(zhí)行文件蚤假,這樣對應(yīng)的 CPU 就可以執(zhí)行了栏饮;
- 生成可執(zhí)行文件(Mach - 0)。
以上的文件編譯流程在文章的開頭鏈接里有詳細(xì)步驟和說明磷仰。
Swift的文件編譯處理過程:
總體而言袍嬉,Swift編譯器主要負(fù)責(zé)將Swift源代碼轉(zhuǎn)換為高效、可執(zhí)行的機器代碼灶平。但是伺通,Swift編譯器前端還支持許多其他工具,包括與語法著色逢享、代碼完成和其他便利的IDE集成罐监。本文件對Swift編譯器的主要組件進行了高層描述:
- 解析:解析器是一個簡單的遞歸解析器(在lib/Parse中實現(xiàn)),帶有一個集成的瞒爬、手工編碼的lexer弓柱。解析器負(fù)責(zé)生成沒有任何語義或類型信息的抽象語法樹(AST),并對輸入源的語法問題發(fā)出警告或錯誤疮鲫。
- 語義分析:語義分析(在lib/Sema中實現(xiàn))負(fù)責(zé)將解析后的AST轉(zhuǎn)換為結(jié)構(gòu)良好的吆你、完全類型檢查的AST形式,為源代碼中的語義問題發(fā)出警告或錯誤俊犯。語義分析包括類型推斷妇多,如果成功,則表明從生成的經(jīng)過類型檢查的AST生成代碼是安全的燕侠。
- Clang導(dǎo)入:Clang導(dǎo)入器(在lib/ClangImporter中實現(xiàn))導(dǎo)入Clang模塊者祖,并將它們導(dǎo)出的C或Objective-C api映射到相應(yīng)的Swift api中。產(chǎn)生的導(dǎo)入的ast可以通過語義分析來引用绢彤。
- SIL生成:Swift中間語言(SIL)是一種高級的七问、特定于Swift的中間語言,適用于Swift代碼的進一步分析和優(yōu)化茫舶。SIL生成階段(在lib/SILGen中實現(xiàn))將類型檢查的AST降低為所謂的“原始”SIL械巡。SIL的設(shè)計在doc /SIL.rst中進行了描述。
- SIL保證轉(zhuǎn)換:SIL保證轉(zhuǎn)換(在lib/SILOptimizer/Mandatory中實現(xiàn))執(zhí)行影響程序正確性的附加數(shù)據(jù)流診斷(例如使用未初始化的變量)饶氏。這些轉(zhuǎn)換的最終結(jié)果是“規(guī)范的”SIL讥耗。
- SIL優(yōu)化:SIL優(yōu)化(在lib/Analysis、lib/ARC疹启、lib/LoopTransforms和lib/Transforms中實現(xiàn))對程序執(zhí)行額外的高級特定于swift的優(yōu)化古程,包括(例如)自動引用計數(shù)優(yōu)化、去虛擬化和泛型專門化喊崖。
- LLVM IR生成:IR生成(在lib/IRGen中實現(xiàn))降低SIL到LLVM IR挣磨,此時LLVM可以繼續(xù)優(yōu)化并生成機器代碼雇逞。
生成LLVM IR 之后的步驟就跟OC一樣了。