APP編譯過程

2、LLVM、Clang

LLVM

LLVM自己並非編譯器,只是一套用於開發編譯器、解釋器等程序語言相關工具的,主要聚焦於編譯器後端功能,如代碼生成、代碼優化、JIT等。前端

LLVM1 an umbrella project that hosts and develops a set of close-knit low-level toolchain components (e.g., assemblers, compilers, debuggers, etc.) LLVM 是一個涵蓋和開發一系列緊密結合的低級工具鏈組件(例如,彙編器,編譯器,調試器等)的綜合項目objective-c

傳統的編譯器一般分爲三個部分,前端(frontEnd),優化器(Optimizer)和後端(backEnd),在編譯過程當中,前端主要負責詞法和語法分析,將源代碼轉化爲抽象語法樹;優化器則是在前端的基礎上,對獲得的中間代碼進行優化,使代碼更加高效;後端則是將已經優化的中間代碼轉化爲針對各自平臺的機器代碼。編程

Clang

Clang 是一個C、C++、Objective-C和Objective-C++編程語言的編譯器前端。它採用了LLVM做爲其後端。swift

Clang是2005年由蘋果電腦發起,是LLVM編譯器工具集的前端(front-end),目的是輸出代碼對應的抽象語法樹(Abstract Syntax Tree, AST),並將代碼編譯成LLVM Bitcode。接着在後端(back-end)使用LLVM編譯成平臺相關的機器語言 。Clang支持C、C++、Objective C。後端

Clang自己性能優異,其生成的AST所耗用掉的內存僅僅是GCC的20%左右,測試證實Clang編譯Objective-C代碼時速度爲GCC的3倍,還能針對用戶發生的編譯錯誤準確地給出建議。bash

iOS中的編譯

Objective C採用Clang做爲前端,而Swift則採用swift()做爲前端,兩者LLVM(Low level vritual machine)做爲編譯器後端。編譯過程以下圖架構

來看看一個文件的編譯過程,新建Test.mapp

#import <Foundation/Foundation.h>

int main(){
    @autoreleasepool {
        NSLog(@"%@",@"Hello Leo");
    }
    return 0;
}

複製代碼

在終端輸入: clang -ccc-print-phases -framework Foundation test.m -o test 會看到下列的:編程語言

0: input, "Foundation", object 
1: input, "test.m", objective-c
2: preprocessor, {1}, objective-c-cpp-output//預處理
3: compiler, {2}, ir //編譯生成IR(中間代碼)
4: backend, {3}, assembler//彙編器生成彙編代碼
5: assembler, {4}, object//生成機器碼
6: linker, {0, 5}, image//連接
7: bind-arch, "x86_64", {6}, image//生成Image,也就是最後的可執行文件
複製代碼

編譯器前端

編譯器前端的任務是進行:語法分析,語義分析,生成中間代碼(intermediate representation )。在這個過程當中,會進行類型檢查,若是發現錯誤或者警告會標註出來在哪一行。函數

編譯器優化

LVVM優化器會進行BitCode的生成,連接期優化等等

編譯器後端

LLVM機器碼生成器會針對不一樣的架構,好比arm64等生成不一樣的機器碼

4、Xcode執行Build的流程

  • 編譯信息寫入輔助文件,建立編譯後的文件架構(name.app)
  • 寫入輔助文件:將項目的文件結構對應表、將要執行的腳本、項目依賴庫的文件結構對應表寫成文件,方便後面使用
  • 運行預設腳本:Cocoapods 會預設一些腳本,固然你也能夠本身預設一些腳原本運行。這些腳本都在 Build Phases 中能夠看到;
  • 編譯文件:針對每個文件進行編譯,生成可執行文件 Mach-O,這過程 LLVM 的完整流程,前端、優化器、後端;使用CompileC和clang命令。
  • 連接庫,例如Foundation.framework,AFNetworking.framework…
  • 拷貝資源文件:將項目中的資源文件拷貝到目標包;
  • 編譯 storyboard 文件:storyboard 文件也是會被編譯的;
  • 連接 storyboard 文件:將編譯後的 storyboard 文件連接成一個文件;
  • 編譯 Asset 文件:咱們的圖片若是使用 Assets.xcassets 來管理圖片,那麼這些圖片將會被編譯成機器碼,除了 icon 和 launchImage;
  • 運行 Cocoapods 腳本:將在編譯項目以前已經編譯好的依賴庫和相關資源拷貝到包中。
  • 建立.app文件和對其簽名

dSYM 文件

咱們在每次編譯事後,都會生成一個dsym文件。dsym文件中,存儲了16進制的函數地址映射。

在App實際執行的二進制文件中,是經過地址來調用方法的。在App crash的時候,第三方工具(Fabric,友盟等)會幫咱們抓到崩潰的調用棧,調用棧裏會包含crash地址的調用信息。而後,經過dSYM文件,咱們就能夠由地址映射到具體的函數位置。

5、提升項目Build速度

查看編譯時間

咱們須要一個途徑,可以看到編譯的時間,這樣纔能有個對比,知道咱們的優化究竟有沒有效果。 對於XCode 8,關閉XCode,終端輸入如下指令 $ defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES

代碼優化-forward declaration

@class CLASSNAME,而不是#import CLASSNAME.h。這樣,編譯器能大大提升#import的替換速度。

對經常使用工具類打包

打包成Framework或者靜態庫,這樣編譯的時候這部分代碼就不須要從新編譯了。

經常使用頭文件放到預編譯文件裏

XCode的pch文件是預編譯文件,這裏的內容在執行XCode build以前就已經被預編譯,而且引入到每個.m文件裏了。

Debug模式下,不生成dsym文件

上文提到了,dysm文件裏存儲了調試信息,在Debug模式下,咱們能夠藉助XCode和LLDB進行調試。因此,不須要生成額外的dsym文件來下降編譯速度。

Debug開啓Build Active Architecture Only

在XCode -> Build Settings -> Build Active Architecture Only 改成YES。這樣作,能夠只編譯當前的版本,好比arm7/arm64等等,記得只開啓Debug模式。這個選項在高版本的XCode中自動開啓了。

相關文章
相關標籤/搜索