Xcode的編譯過程

今天我們來對iOS開發(fā)的常用工具Xcode的編譯流程進行一個簡單的了解和分析

image

OC:source code > Clang -> LLVM -> Backend -> Executable
Clang做的事情是詞法分析-> token流->語法分析-> AST -> LLVM IR

AST(Abstract Syntax Tree 抽象語法樹)
IR(intermediate representation 中間代碼)


swift:source code > swiftc -> LLVM -> Backend -> Executable
swiftc:swift AST -> Raw Swift IL -> Canonical Swift IL -> LLVM IR

Raw Swift IL : Swift特有的中間代碼
Canonical Swift IL:將Raw Swift IL進行降級簡化成更加簡潔的中間代碼版本

swift的編譯器前端是swiftc搓蚪,于Clang相比吐葵,LLVM的前端編譯過程中吁断,AST和IR之間,多了一層SIL(Swift Intermediate Language)殉农,這么做的目的是希望彌補clang編譯器的一些缺陷,比如無法執(zhí)行一些高級分析,可靠的診斷和優(yōu)化吱晒,而 AST 和LLVM IR 都不是合適的選擇财著。因此联四,SIL應(yīng)運而生,用來解決現(xiàn)有的缺陷


AST(Abstract Syntax Tree 抽象語法樹)

生成AST的過程

詞法分析(lexical analysis
也叫掃描器撑教,讓源代碼的字符流根據(jù)構(gòu)詞規(guī)范生成token流

tokenize:tokenize就是按照一定的規(guī)則朝墩,例如token令牌(通常代表關(guān)鍵字,變量名伟姐,語法符號等)收苏,將代碼分割為一個個的“串”亿卤,也就是語法單元)。涉及到詞法解析的時候鹿霸,常會用到tokennize排吴。

語法分析(parse analysis)是編譯過程的一個邏輯階段。語法分析的任務(wù)是在詞法分析的基礎(chǔ)上將單詞序列組合成語法樹杜跷,如“程序”傍念,“語句”,“表達式”等等.語法分析程序判斷源程序在結(jié)構(gòu)上是否正確葛闷。源程序的結(jié)構(gòu)由上下文無關(guān)文法描述憋槐。

image

Clang:

AST的轉(zhuǎn)換例子

@property (nonatomic, strong) NSString *haoyuString;

PS:屬性(Property)是Objective-C語言的其中一個特性,它把類對象中的實例變量及其讀寫方法統(tǒng)一的封裝

生成的AST如下:

 ObjCPropertyDecl 0x7f96f693a400 <line:13:1, col:41> col:41 haoyuString 'NSString *' readwrite nonatomic strong
 | |-ObjCMethodDecl 0x7f96f693a478 <col:41> col:41 implicit - haoyuString 'NSString *'
 | |-ObjCMethodDecl 0x7f96f693a4f8 <col:41> col:41 implicit - setHaoyuString: 'void'
 | | `-ParmVarDecl 0x7f96f693a578 <col:41> col:41 haoyuString 'NSString *'

常見的數(shù)據(jù)類型聲明在AST中表示

 NSString *str = @"hahahah"; //oc中賦值代碼

AST中的表示為:

 VarDecl 0x7fd06cc91ae8 <line:24:5, col:22> col:15 str 'NSString *__strong' cinit //聲明局部變量
 | | | `-ObjCStringLiteral 0x7fd06cc91ba8 <col:21, col:22> 'NSString *' //聲明變量類型
 | | |  `-StringLiteral 0x7fd06cc91b88 'char [8]' lvalue "hahahah" //右邊的字符串有char類型表示

String:StringLiteral
NSInteger ,Int: IntegerLiteral
Float: FloatingLiteral
Array: ObjCArrayLiteral
Dictionary : ObjCDictionaryLiteral

將源代碼生成語法樹 AST:

clang -fmodules -fsyntax-only -Xclang -ast-dump main.m

Swiftc:

生成AST的方式和Clang類似,這里著重介紹下swiftc編譯器的SIL(Swift Intermediate Language )

1.生成的main.swift文件中編寫如下代碼

import Foundation
class Teacher {
    var age: Int = 18
    var name: String = "Tom"
}

var person = Teacher()
person.age = 6

通過終端進入main.swift所在的文件夾淑趾,輸入如下指令:

swiftc -emit-sil main.swift  //生成了main.sil文件
// 打開`main.sil` 文件阳仔,首先看到了Teacher的聲明
class Teacher {
  @_hasStorage @_hasInitialValue var age: Int { get set }
  @_hasStorage @_hasInitialValue var name: String { get set }
  @objc deinit
  init()
}

@_hasStorage @_hasInitialValue var person: Teacher { get set }

// person
sil_global hidden @main.person : main.Teacher : $Teacher
  1. @_hasStorage表示的是儲存屬性
  2. @_hasInitialValue表示的是具有初始值
  3. @sil_global表示的是全局變量
  4. 一個析構(gòu)方法deinit
  5. 一個初始化函數(shù)init()

這里聲明了Teacher類,并定義了一個全局的person屬性扣泊,屬于Teacher類

2.看下main.sil文件中的main 函數(shù)

每個程序的開始都是main函數(shù)近范,swift語言也不例外,但是swift中的main函數(shù)被隱藏了延蟹,main.swift文件就代表了整個main函數(shù)评矩,在文件里寫的代碼會在main中運行

// main函數(shù),相當于c程序入口函數(shù)int main(int argc, char * argv[])
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
//%0阱飘,%1……在SIL也叫寄存器斥杜,這里我們可以理解為我們?nèi)粘i_發(fā)的常量,
//一旦賦值之后就不可以在修改沥匈,如果SIL中還要繼續(xù)使用蔗喂,那么就不斷的累加數(shù)字
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
//初始化全局變量person  alloc_global是創(chuàng)建一個全局變量
  alloc_global @main.person : main.Teacher       // id: %2
//創(chuàng)建對之前由alloc_global初始化的全局變量地址的引用
//global_addr是拿到全局變量的地址,賦值給%3
  %3 = global_addr @main.person : main.Teacher : $*Teacher // users: %7, %8
//元類型Teacher
//metatype是拿到Teacher的Metaldata賦值給%4
  %4 = metatype $@thick Teacher.Type              // user: %6
// 方法__allocating_init()的引用
//接下來就是將__allocating_init()的函數(shù)地址賦值給%5
  %5 = function_ref @main.Teacher.__allocating_init() -> main.Teacher : $@convention(method) (@thick Teacher.Type) -> @owned Teacher // user: %6
//調(diào)用函數(shù)__allocating_init高帖,并傳入?yún)?shù)元類型Teacher
//apply是調(diào)用函數(shù)缰儿,這里是調(diào)用%5也就是__allocating_init(),%4是參數(shù)散址,并將返回值給%6
  %6 = apply %5(%4) : $@convention(method) (@thick Teacher.Type) -> @owned Teacher // user: %7
//將函數(shù)__allocating_init的結(jié)果存入person的引用
//然后將%6的值存儲到%3乖阵,也就是我們剛剛創(chuàng)建的全局變量的地址
  store %6 to %3 : $*Teacher                      // id: %7
//開始訪問全局變量地址的引用
  %8 = begin_access [read] [dynamic] %3 : $*Teacher // users: %9, %11
//將內(nèi)容載入%9
  %9 = load %8 : $*Teacher                        // users: %16, %14, %15, %10
//引用計數(shù)加一
  strong_retain %9 : $Teacher                     // id: %10
//結(jié)束訪問
  end_access %8 : $*Teacher                       // id: %11
//創(chuàng)建字面量6
  %12 = integer_literal $Builtin.Int64, 6         // user: %13
//生成Int值6,swift中Int是結(jié)構(gòu)體
  %13 = struct $Int (%12 : $Builtin.Int64)        // user: %15
//Teacher.age的setter方法
  %14 = class_method %9 : $Teacher, #Teacher.age!setter : (Teacher) -> (Int) -> (), $@convention(method) (Int, @guaranteed Teacher) -> () // user: %15
//調(diào)用setter方法预麸,傳入Int值6义起,和類實例本身
  %15 = apply %14(%13, %9) : $@convention(method) (Int, @guaranteed Teacher) -> ()
//引用計數(shù)減一
  strong_release %9 :
//創(chuàng)建字面量0
  %17 = integer_literal $Builtin.Int32, 0         // user: %18
//生成Int值0,swift中Int是結(jié)構(gòu)體
  %18 = struct $Int32 (%17 : $Builtin.Int32)      // user: %19
//最后將0從main函數(shù)中返回出去
  return %18 : $Int32                         // id: %16
} // end sil function 'main'
  1. @main 這里是標示我們當前main.swift的入口函數(shù)师崎,SIL中的標示符以 @作為前綴
  2. %0默终,%1……在SIL也叫寄存器,這里我們可以理解為我們?nèi)粘i_發(fā)的常量,一旦賦值之后就不可以在修改齐蔽,如果SIL中還要繼續(xù)使用两疚,那么就不斷的累加數(shù)字
  3. alloc_global是創(chuàng)建一個全局變量
  4. global_addr是拿到全局變量的地址,賦值給%3
  5. metatype是拿到Teacher的Metaldata賦值給%4
  6. 接下來就是將__allocating_init()的函數(shù)地址賦值給%5
  7. apply是調(diào)用函數(shù)含滴,這里是調(diào)用%5也就是__allocating_init()诱渤,%4是參數(shù),并將返回值給%6
  8. 然后將%6的值存儲到%3谈况,也就是我們剛剛創(chuàng)建的全局變量的地址
  9. 然后是構(gòu)建Int并return

3. 這里面有些固定搭配

1.初始化一個引用

//初始化全局變量person
  alloc_global @main.person : main.Teacher
//創(chuàng)建對之前由alloc_global初始化的全局變量地址的引用
  %3 = global_addr @main.person : main.Teacher 

2.調(diào)用一個方法

// 方法__allocating_init()的引用
  %5 = function_ref @main.Teacher.__allocating_init() -> main.Teacher : $@convention(method) (@thick Teacher.Type) -> @owned Teacher
//調(diào)用函數(shù)__allocating_init勺美,并傳入?yún)?shù)元類型Teacher
  %6 = apply %5(%4) : $@convention(method) (@thick Teacher.Type) -> @owned Teacher

3.獲得swfit的基本類型

//創(chuàng)建字面量6
  %12 = integer_literal $Builtin.Int64, 6
//生成Int值6,swift中Int是結(jié)構(gòu)體
  %13 = struct $Int (%12 : $Builtin.Int64)

swiftc命令:

生成可執(zhí)行文件:swiftc -o main.out main.swift

生成抽象語法樹的命令(AST):swiftc main.swift -dump-ast

生成中間語言(SIL):swiftc main.swift -emit-sil

LLVM中間表示層(LLVM IR):swiftc main.swift -emit -ir

生成匯編語言:swiftc main.swift -emit-assembly
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末碑韵,一起剝皮案震驚了整個濱河市赡茸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌祝闻,老刑警劉巖占卧,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異联喘,居然都是意外死亡华蜒,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門豁遭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來叭喜,“玉大人,你說我怎么就攤上這事蓖谢∮蚶模” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵蜈抓,是天一觀的道長。 經(jīng)常有香客問我昂儒,道長沟使,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任渊跋,我火速辦了婚禮腊嗡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拾酝。我一直安慰自己燕少,他們只是感情好,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布蒿囤。 她就那樣靜靜地躺著客们,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上底挫,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天恒傻,我揣著相機與錄音,去河邊找鬼建邓。 笑死盈厘,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的官边。 我是一名探鬼主播沸手,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼注簿!你這毒婦竟也來了契吉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤滩援,失蹤者是張志新(化名)和其女友劉穎栅隐,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體玩徊,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡租悄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了恩袱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泣棋。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖畔塔,靈堂內(nèi)的尸體忽然破棺而出潭辈,到底是詐尸還是另有隱情,我是刑警寧澤澈吨,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布把敢,位于F島的核電站,受9級特大地震影響谅辣,放射性物質(zhì)發(fā)生泄漏修赞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一桑阶、第九天 我趴在偏房一處隱蔽的房頂上張望柏副。 院中可真熱鬧,春花似錦蚣录、人聲如沸割择。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荔泳。三九已至蕉饼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間换可,已是汗流浹背椎椰。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留沾鳄,地道東北人慨飘。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子呐芥,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容