http://blog.csdn.net/u014795020/article/details/72514109javascript
今天在Swift
工程中不當心建立了一個OC
文件,因而乎提示我建立一個橋接文件,那麼爲何須要建立橋接文件呢,它的原理又是什麼呢?html
打開百度一搜,全是教你怎麼建立橋接文件的,彷佛找不到答案~前端
LVVM - Low Level Virtual Machine
Clang - C Lange Family Frontend for LVVMjava
GNU編譯器套件(GNU Compiler Collection)包括C、C++、Objective-C、Fortran、Java、Ada和Go語言的前端,也包括了這些語言的庫(如libstdc++、libgcj等等)node
早起的OC 程序員都感覺過GCC編譯程序,可是蘋果爲何好好的GCC不用,本身要搞一套呢?python
1.GCC 的 objective-c Frontend不給力:GCC的前端不是蘋果提供維護的,想要添加一些語法提示等功能還得去求GCC的前端去作。ios
2.GCC 插件、工具、IDE的支持薄弱:不少編譯器特性沒有,自動補全、代碼提示、warning、靜態分析等這些流程不是很給力,都是須要IDE調用底層命令完成的,結果須要以插件的形式暴露出來,這一塊GCC作的不是很好。c++
3.GCC 編譯效率和性能不足:Apple的Clang出來之後,其編譯效率是GCC的3倍,編譯器性能好,編譯出的文件小。git
4.Apple要收回去工具鏈的控制 (lldb, lld…): Apple在早起從GCC前端到LLVM後端的編譯器,到Clang-LVVM的編譯器,之後後來的GDB的替換,一步一步收回對編譯工具鏈的控制,也爲swift
的出現奠基基礎。程序員
上圖是最簡單的三段式編譯器架構。
首先,咱們看到source
是咱們的源代碼,進入編譯器的前端Frontend
;在前端完成以後,就進入優化器這一模塊;優化完成以後進入後端這一模塊;在這所有完成以後,根據你的架構是x86,armv7等生產機器碼。
可是會有一個問題:
M (Language) * N (Target) = M * N (Compilers)
就是若是你有M種語言(C、C++、Objective-C…),N種架構(armv七、armv7s、arm6四、i38六、x86_64…),那麼你就有M * N中編譯方式須要處理,顯然是不合理的。
Clang/Swift - LLVM
編譯器架構:其中優化器部分(Common Optimizer)是共享的。而對於每一種語言都有其前端部分,假如新有一門語言,只須要實現該語言的前端模塊;若是新出一臺設備,它的架構不一樣,那麼也只須要單獨完成其後端模塊便可。改動很是小,不會作重複的工做。
下面詳解:
藍色的部分:C語言家族系列的前端,屬於Clang部分。
綠色的部分: Swift語言的前端,其中還包含本身的SIL中間語言和Optimzer中間語言的優化過程。
紫色的部分: 優化階段和後端模塊統一是LLVM部分。
Clang + LLVM 代碼模塊總共有400W行代碼,其中主體部分是C++寫的,大概有235W行。若是將全部的target,lib等文件編譯出來,大概有近20G的大小:
對比Swift Frontend 代碼規模,就少不少,只有43W行左右。可能在後端,好比優化器策略,生成機器碼部分就有不少代碼:
Clang在概念上是編譯器前端,同時,在命令行中也做爲一個「黑盒」的 Driver;
它封裝了編譯管線、前端命令、LLVM命令、Toolchain命令等,即一個Clang走天下;
方便從GCC遷移過來。
當咱們點擊run命令之後,以下圖:
就是咱們在build setting中的一些設置,組裝成命令,下面能夠看到是一個 oc文件在arc環境下的編譯過程:
#import <Foundation/Foundation.h> int main() { @autoreleasepool { id obj = [NSObject new]; NSLog(@"Hellow world: %@", obj); } }
1.Preprocess - 預處理
import 頭文件,include頭文件等
macro宏展開
處理’#’大頭的預處理指令,如 #if,#elseif等
終端輸入:
$ clang -E main.m
只會作預處理步驟,不日後面走,以下
能夠看到一個頭文件要導入不少行代碼,這裏就要說到pch文件。自己Apple給出這個文件,是讓咱們放入Foundation
或者UIKit
等這些根本不會變的庫,優化編譯過程,可是開發者卻各類宏,各類頭文件導入,致使編譯速度很慢。以致於後來蘋果刪除了這個文件,只能開發者本身建立。可是蘋果除了modules這個概念,能夠經過如下命令打開:
$ clang -E -fmodules main.m
默認把一些文件打包成庫文件, 在build setting中默認打開的,咱們能夠用@import Foundation:
2.Lexical Analysis - 詞法分析
詞法分析,也做Lex 或者 Tokenization
將預處理過得代碼文本轉化爲Token流
不會校驗語義
能夠在終端輸入如下命令:
$ clang -fmodules -fayntax-only -Xclang -dump-tokens main.m
以下圖:
3.Analysis - 語法分析
語法分析,在Clang中有Parser和Sema兩個模塊配合完成,驗證語法是否正確,並給出正確的提示。這就是Clang標榜GCC,本身的語法提示友好的體現。
根據當前的語法,生成語意節點,並將全部節點組合成抽象語法書(AST)
輸入命令:
$ clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
以下圖:
能夠經過語法樹,反寫回源碼,以下圖:
4.Static Analysis - 靜態分析(不是必須的)
經過語法書進行代碼靜態分析,找出非語法性錯誤
模擬代碼執行路徑,分析出 contro-flow graph (CFG)
預置了經常使用的 Checker
在Xcode中以下操做能夠實現:
5.CodeGen - IR 代碼生成
CodeGen負責將語法樹從頂至下遍歷,翻譯成LLVM IR,LLVMIR 是Frontend的輸入,也是LLVM Backend 的輸入,是先後端的橋接語言。
與Objective-C Runtime 橋接
①Class / Meta Class / Protocol / Category 內存結構生成,並存放在指定 session中(如Class: _DATA, _objc_classrefs)
②Method / Ivar / Property 內存結構生成
③組成 method_list / ivar_list / property_list並填入Class
④Non-Fragile ABI: 爲每一個Ivar合成 OBJC_IVAR_$_偏移常量
⑤存取 Ivar的語句(ivar = 123; int a = _ivar;) 轉寫成base + OBJC_IVAR$_的形式
⑥將語法樹中的 ObjCMessageExpr 翻譯成相應版本的objc_msgSend,對super關鍵字的調用翻譯成objc_msgSendSuper
⑦處理@synthsynthesize
⑧生成 block_layout
的數據結構
⑨變量 capture (__block/ __weak)
10.生成_block_invoke
函數
11.ARC: 分析對象引用關係,將 objc_storeStrong/ objc_storeWeak
等ARC 代碼插入
12.將 ObjCAutoreleasePoolStmt
轉譯成objc_autoreleasePoolPush/Pop
13.實現自動調用[super dealloc]
14.爲每一個擁有 ivar 的Class 合成.cxx_destructor
方法來自動釋放類的成員變量,代替MRC 時代下的」self.xxx = nil」
舉個栗子,嘿嘿:
終端輸入:
$ clang -S -fobjc-arc -emit-llvm main.m -o main.m
輸入以下:
介於C和彙編的中間形態。
若是加入優化:
$ clang -O3 -S -fobjc-arc -emit-llvm main.m -o main.m
明顯感受少了不少。
6. LVVM Bitcode - 生成字節碼
輸入命令:
$ clang -emit-llvm -c main.m -o main.bc
相信你們在iOS 9以後都聽過這個概念,其實就是對IR生成二進制的過程。
7.Assemble - 生成Target相關彙編
終端輸入:
$ clang -S -fobjc-arc main.m -o main.s
以下圖:
彙編代碼。
8.Assemble - 生成Target相關 Object(Mach-o)
終端輸入:
$ clang -fmodules -c main.m -o main.o
彙編的main.o的形式。
9.Link 生成 Executable
終端輸入:
$ clang main.m -o main $ ./main
總結一下吧:
至此,我猜想可能橋接文件是在Clang階段,將OC文件進行編譯,生成語法樹,而後再返成Swift能識別的類文件。
Apple給咱們留了3個接口:
1.LibClang
功能:
①C 的API來訪問Clang的上層能力,好比獲取Tokens、遍歷語法樹、代碼補全、獲取診斷信息;
②API穩定,不受Clang源碼更新影響
③只有上層的語法樹能夠訪問,不能獲取到所有信息
使用:
④使用原始的 C的API
⑤腳本語言: 使用官方提供的 Python binding 或開源的 node-js / ruby binding
⑥Objective-C: 開源庫 ClangKit
2.LibTooling
①對語法樹 有徹底的控制權
②可做爲一個 standalone 命令單獨使用,如 clang-format
③須要使用C++且對Clang源碼熟悉
3.ClangPlugin
①對語法樹有徹底的控制權
②做爲插件注入到編譯流程中,能夠影響build和決定編譯過程
③須要使用C++且對Clang源碼熟悉
參考資料:
http://clang.llvm.org/docs/index.html
http://blog.llvm.org/
https://www.objc.io/issues/6-build-tools/compiler/
http://llvm.org/docs/tutorial/index.html
https://github.com/loarabia/Clang-tutorial
http://lowlevelbits.org/getting-started-with-llvm/clang-on-os-x/
https://hevinaboos.wordpress.com/2013/07/23/clang-tutorial-part-i-introducation/
http://szelei.me/code-generator/