編譯流程
首先簡單寫一個demo以下: #import <stdio.h>
//#define C 30
//typedef int TD_INT_64;
int test(int a,int b){
return a + b + 3;
}
int main(int argc, const char * argv[]) {
int a = test(1, 2);
printf("%d",a);
return 0;
}
複製代碼
-
經過命令打印查看源碼的編譯階段
命令:clang -ccc-print-phases main.m
能夠發現主要分6個步驟
- 0:輸入文件:找到源文件。
- 1:預處理階段:這個過程處理包括宏的替換,頭文件的導入。
- 2:編譯階段:進行詞法分析、語法分析、檢測語法是否正確,最終生成IR。
- 3:後端:這裏
LLVM
會經過一個一個的Pass
去優化,每一個Pass
作一些事情,最終生成彙編代碼。
- 4:生成目標文件。
- 5:連接:連接須要的動態庫和靜態庫,生成可執行文件。
- 6:經過不一樣的架構,生成對應的可執行文件。
-
預處理階段
命令:clang -E main.m
宏在預處理階段會被替換掉,typedef
不會被替換掉,因此通常爲了安全可使用,作代碼混淆
-
編譯階段
-
詞法分析
預處理完成後就會進行詞法分析.這裏會把代碼切成一個個Token,好比大小括 號,等於號還有字符串等
命令: clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m
注:若是頭文件找不到能夠指定sdk
clang -isysroot (本身SDK路徑) -fmodules -fsyntax-only -Xclang -dump-tokens main.m
clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.1.sdk/ -fmodules -fsyntax-only -Xclang -dump-tokens main.m
-
語法分析
詞法分析完成以後就是語法分析,它的任務是驗證語法是否正確。在詞法分析的基礎上將單詞序列組合成各種語法短語,如「程序」,「語句」,「表達式」等等,而後將全部節點組成抽象語法樹(Abstract Syntax Tree, AST)。語法分析程序判斷源程序在結構上是否正確。
命令: clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
FunctionDecl
函數
ParmVarDecl
參數
CallExpr
調用一個函數
BinaryOperator
運算符
-
生成中間代碼IR
完成以上步驟後就開始生成中間代碼IR
了,代碼生成器(Code Generation)會將語法樹自頂向下遍歷逐步翻譯成LLVM IR
。經過下面命令能夠生成.11
的文本文件,查看IR代碼。
命令:clang -S -fobjc-arc -emit-llvm main.m
Objective C
代碼在這一步會進行runtime
的橋接:property
合成,ARC
處理等
IR的基本語法:
@
全局標識
%
局部標識
alloca
開闢空間
align
內存對齊
i32
32個bit, 4個字節
store
寫入內存
load
讀取數據
call
調用函數
ret
返回
IR優化:
LLVM的優化級別分別是-O0 -O1 -O2 -O3 -Os(第一個是大寫英文字母O)
優化命令:clang -Os -S -fobjc-arc -emit-llvm main.m -o main.ll
通常設置是在target - Build Setting - Optimization Level
(優化器等級)中設置 Debug
狀況下默認是不優化,Release
狀況下默認Fastest、Smallest
優化後的代碼:
-
bitCode
xcode7之後開啓bitcode
蘋果會作進一步的優化。生成.be
的中間代碼。 咱們經過優化後的IR
代碼生成.be
代碼
命令:clang -emit-llvm -c main.ll -o main.bc
-
生成彙編代碼
最終經過.be
或者.ll
代碼生成彙編代碼
命令:
clang -S -fobjc-arc main.bc -o main.s
clang -S -fobjc-arc main.ll -o main.s
固然生成的彙編代碼也能夠進行優化(注意若是生成IR
代碼已經作過優化了此時在優化不會再起做用)
命令:clang -Os -S -fobjc-arc main.m -o main.s
-
生成目標文件(彙編器)
目標文件的生成,是彙編器以彙編代碼做爲輸入,將彙編代碼轉換爲機器代碼, 最後輸出目標文件(object file)
命令: clang -fmodules -c main.s -o main.o
能夠發現是個Mach-O
文件
經過nm命令,查看下main.o中的符號
命令: xcrun nm -nm main.o
發現找不到_printf
這個方法,應爲_printf
是從外部的庫引入
-
生成可執行文件(連接)
鏈接器把編譯產生的.o
文件和(.dylib .a
)文件,生成一個mach-o
文件。
命令:clang main.o -o main
發現此時是一個可執行的Mach-O
文件
再查看連接以後的符號
應爲OC的特性運行時,動態庫實在運行時須要使用的時候再加載到內存的,因此編一階段找不到對應的方法