原地址:https://objccn.io/issue-6-2/ ,https://objccn.io/issue-6-3/
1. XCODE編譯幫我們做了什么事情?
答: 將.h 和.m 文件轉(zhuǎn)換成字節(jié)碼文件 ,由ios的ARM處理器 or mac上的intel處理器執(zhí)行
2. 具體過程是怎么樣的?
答: xcode 默認(rèn) 所使用的編譯器是clang ,大體過程是
a.對objective-c做代碼的分析檢查
b. 在正確后轉(zhuǎn)為低級的類匯編代碼 (LLVM 中間表達(dá)碼)
c. 最后LLVM 會根據(jù)平臺不同轉(zhuǎn)換成對應(yīng)的字節(jié)碼
具體的過程可以用命令 clang -ccc-print-phases XX.m 查看,結(jié)果如下
0: input, "Income.m", objective-c
1: preprocessor, {0}, objective-c-cpp-output
2: compiler, {1}, ir
3: backend, {2}, assembler
4: assembler, {3}, object
5: linker, {4}, image
6: bind-arch, "x86_64", {5}, image
3. 每個階段做了些什么事振定?
0: 讀入文件?
1: 預(yù)處理 (宏替換雅宾,詞法翻譯,import展開)
? 預(yù)處理之宏替換:將源文件的宏展開, #import 文件的展開(#import文件如果有其它的import 也一并展開,一直遞歸下去),用命令clang -Ehello.c| less 后可以看到預(yù)處理的文件:
源文件 :
#define MAX(a,b) a > b ? a : b
int main() {
printf("largest: %d\n", MAX(10,100));
return 0;
}
處理后的文件 :
# 1 "hello.c"# 1 "" 1# 1 "" 3# 329 "" 3# 1 "" 1# 1 "" 2
# 1 "hello.c" 2
int main() {
printf("largest: %d\n", 10 > 100 ? 10 : 100);
return 0;}
ps :可以看到逢享,宏已經(jīng)被替換掉了罐监。 預(yù)處理的文件會在有變化的地方插入#(hash) 來標(biāo)記 ,#后的數(shù)字是源文件位置 ,最后的數(shù)字為新文件的位置瞒爬,這樣在出錯的時候就可以對應(yīng) 起來找到出錯的地方弓柱。
詞法解析標(biāo)記 : 在上一步的預(yù)處理完成后,每一個.m文件 里的聲明和定義會從 string 轉(zhuǎn)化成特殊的標(biāo)記 舉例如下:
源code:
intmain(){?
?NSLog(@"hello, %@", @"world");
return 0;}
利用命令 clang -Xclang -dump-tokens hello.m 可以查看到詞法解析后的內(nèi)容如下:按我的理解就是把源代碼翻譯成了符合編譯器語法的源代碼侧但,這樣編譯器就能認(rèn)識了. 其中 4:1 類似于NSRange矢空,可以知道源碼的起 始位置?
總的說來禀横, 在預(yù)編譯階段:會做宏替換屁药,會做頭文件引入,然后將m文件 符號 化后轉(zhuǎn)換成語法樹, 編譯器會根據(jù)這棵語法樹柏锄,做一些額外的操作以找出可能存在的錯誤酿箭,包括如下:
a. 類型檢查(動態(tài)&靜態(tài)檢查):即檢查程序中是否有類型錯誤 , 比如屬性和對應(yīng)的類型是否相同 ,一個對象有沒有對應(yīng)的方法 etc.
b. 檢查變量定義了但是未使用 etc, 可能存在的內(nèi)存問題趾娃,就是我們看到的Warning
3. 編譯 :將 AST 轉(zhuǎn)換為更低級的中間碼 (LLVM IR),對生成的中間碼做優(yōu)化,生成特定目標(biāo)代碼,輸出匯編代碼
4.匯編: 將匯編代碼轉(zhuǎn)換為目標(biāo)對象文件
5. 鏈接: ?將多個目標(biāo)對象文件合并為一個可執(zhí)行文件 (或者一個動態(tài)庫)?
6. 生成可執(zhí)行文件 :Mach-O
PS: 更詳細(xì)的請看開頭的原文LINK七问,該篇只是我看后的個人總結(jié)。茫舶。