第四十節(jié)—iOS用到的LLVM(一)

本文為L_Ares個人寫作篇裁,以任何形式轉(zhuǎn)載請表明原文出處菲饼。

LLVM

內(nèi)容較多,本文盡量不廢話远剩,看起來會有點刻板扣溺,但都是干貨,請各位先仔細并且充分的理解以下三個問題 :

  1. 為什么要了解LLVMClang?
  2. 什么是LLVM?
  3. 什么是Clang?

注 : 概念性的資料源于百科(維基百科LLVM官網(wǎng))瓜晤。

前言 : 為什么要了解LLVM?

因為Objective-CSwift語言都是編譯型語言锥余,所以需要編譯器對其轉(zhuǎn)換成機器語言才會被系統(tǒng)識別,而它們的編譯器都是基于LLVM體系開發(fā)的痢掠。

編譯器驱犹、編譯型語言有所遺忘的童鞋看這里

一足画、簡述什么是LLVM

前言

第一 :
本節(jié)的重點雖然是LLVM雄驹,但是主要還是以iOSer的角度來看的。

第二 :
要想深入學(xué)習(xí)LLVM的話淹辞,本節(jié)的這些內(nèi)容只能算是一個概念的大體簡述医舆,尤其主要是iOS的視角,所以想了解更多LLVM的同學(xué)桑涎,還需自行查看LLVM官網(wǎng)彬向。

第三 :
如果覺得LLVM官網(wǎng)真的很難懂,又全是英文攻冷,翻譯無法精準的話娃胆,那么可以看一下知乎上的藍色大大對于LLVM的講解,再配合LLVM官網(wǎng)進行學(xué)習(xí)等曼。

概念

這里的概念全部引自LLVM官網(wǎng)里烦。

LLVM現(xiàn)在已經(jīng)不是一個名稱的首字母縮寫了(最初還真是),而是一個項目名稱禁谦,是一個模塊化的胁黑、可重用的編譯器工具鏈技術(shù)的集合。

簡言之州泊,LLVM是架構(gòu)編輯器的框架系統(tǒng)丧蘸。

所謂工具鏈技術(shù)蒸走,舉個栗子 :

嵌入式Linux就提供了一套完整的工具鏈遭赂,它利用GNUgcc做編譯器,利用gdbxgdb做調(diào)試工具氯庆,可以很方便的實現(xiàn)從操作系統(tǒng)的內(nèi)核態(tài)到用戶態(tài)的應(yīng)用軟件各個級別的調(diào)試庙楚。

所謂框架系統(tǒng) :

就是說LLVM不僅僅是某一樣具體的事物膝擂,而是由很多模塊組合起來的框架亚斋。

所謂框架就是你可以基于它提供的功能開發(fā)自己的模塊,并且集成到LLVM系統(tǒng)上拂募,增加LLVM的功能庭猩。

或者你也可以利用LLVM作為一種底層支持,去完成自己的軟件開發(fā)陈症。

概述

LLVM曾是Low Level Virtual Machine(低等級虛擬機)的縮寫蔼水,現(xiàn)在它是一個項目體系、是一套框架系統(tǒng)录肯。

LLVM項目包括了非常多的子項目徙缴,包括iOS開發(fā)者常見的ClangLLDB嘁信,libc++libc++ ABI,這都是LLVM的主要子項目疏叨。

LLVM雖然包含了這么多編譯器作為子項目潘靖,但是它本身并不是編譯器,也不是編譯器后端蚤蔓。

它提供的是編譯器所需的一系列的庫卦溢。例如程序分析、代碼優(yōu)化秀又、機器代碼生成等单寂,并且提供了調(diào)用這些庫的相關(guān)工具。也為這些庫提供了方便簡單的吐辙、具備類型的宣决、與平臺無關(guān)的統(tǒng)一中間代碼語言——LLVM IR

LLVMC++編寫而成昏苏,用于優(yōu)化以任意程序語言編寫的 :

  • 編譯時間 (compile-time)

  • 鏈接時間 (link-time)

  • 運行時間 (run-time)

  • 空閑時間 (idle-time)

LLVM對開發(fā)者保持開放尊沸,并且兼容現(xiàn)有的腳本。

二贤惯、編譯器的設(shè)計

在探索LLVM的設(shè)計之前洼专,先看一下傳統(tǒng)的編譯器設(shè)計,來比較兩者的區(qū)別孵构,以探索LLVM的優(yōu)勢屁商。

1. 傳統(tǒng)編譯器的設(shè)計

如圖2.1.0所示

圖2.1.0

傳統(tǒng)的編譯器整體流程是 :

源碼 --> 編譯器前端 --> 優(yōu)化器 --> 編譯器后端/代碼生成器(CodeGenetator) --> 機器語言

1.1 編譯器前端(Frontend)

傳統(tǒng)的編譯器前端主要任務(wù)就是讀取源代碼,對讀取的源代碼做詞法分析颈墅、語法分析蜡镶、語義分析雾袱,通過這些分析來檢查源代碼是否存在錯誤,然后構(gòu)建語法樹 (Abstract Syntax Tree, AST)帽哑。

1.2 優(yōu)化器(Optimizer)

優(yōu)化器的責(zé)任就是各種優(yōu)化谜酒。改善代碼的運行時間,例如消除冗余計算等妻枕。

1.3 編譯器后端(Backend)/代碼生成器(CodeGenerator)

將代碼映射到目標指令集僻族,生成機器語言,并進行機器相關(guān)的代碼優(yōu)化屡谐。

后端或者說代碼生成器述么,最后生成的是對應(yīng)不同架構(gòu)的二進制文件,之所以需要生成不同的二進制文件愕掏,就是因為不同的架構(gòu)有不同的指令集度秘,不同的指令集對相同的二進制文件的指令識別是不同的,所以要將代碼映射到對應(yīng)的指令集饵撑。

2. iOS的編譯器架構(gòu)

所謂iOS的編譯器架構(gòu)其實就是LLVM編譯器架構(gòu)中的一部分剑梳。包括Objective-CC滑潘、C++在內(nèi)垢乙,它們使用的編譯器前端都是Clang。而Swift編譯器前端就是Swift语卤。它們的編譯器后端則全部都是LLVM Code Generator追逮。

Clang也只是整個LLVM架構(gòu)中的一個子項目,屬于編譯器前端粹舵。

來看iOS的編譯器架構(gòu)圖 :

圖2.2.0

很明顯钮孵,iOS的編譯器是通過Clang或者Swift來完成詞法分析、語法分析眼滤、語義分析的步驟巴席,來完成對源代碼的錯誤排查,然后生成抽象語法樹(AST)柠偶。

這里利用的就是LLVM的前端情妖,和傳統(tǒng)編譯器的不同點是,Clang不止做完了上述的排查诱担,還會生成一個非常重要的東西——IR毡证。

什么是IR?

LLVM的編譯器前端不僅會完成分析排查和生成抽象語法樹的工作,還會生成中間代碼蔫仙,這個中間代碼在LLVM中被稱作IR (intermediate representation)料睛。

那么用語言來描述iOS的編譯器架構(gòu)設(shè)計流程就是 :

  1. Clang/Swift讀取源代碼,檢查詞法、語法恤煞、語義的分析屎勘,排查錯誤,生成抽象語法樹(AST)居扒,并生成中間代碼IR概漱。

  2. 然后將IR給到LLVM的優(yōu)化器(Optimizer),改善代碼的運行時間喜喂,消除冗余計算等瓤摧。

  3. 最后將優(yōu)化過的IR再傳給后端或者說代碼生成器,由后端/代碼生成器完成將IR轉(zhuǎn)換成對應(yīng)不同架構(gòu)的二進制文件玉吁,完成機器代碼的相關(guān)優(yōu)化照弥。

3. LLVM的設(shè)計

LLVM的設(shè)計核心 : 中間代碼IR

LLVM的設(shè)計重點和優(yōu)勢 : 面對多種源語言(編譯器前端來做)进副,或者多種硬件架構(gòu)(編譯器后端來做)的情況時这揣,對比傳統(tǒng)的編譯器例如GCC,優(yōu)勢就是LLVMIR設(shè)計影斑。

由于GCC是以一個整體應(yīng)用程序設(shè)計的给赞,也就是說,如果你的前端源語言或者后端硬件架構(gòu)矫户,任一一個發(fā)生了變化的話塞俱,你需要重新設(shè)計一整套前端--優(yōu)化器--后端的編譯器。

LLVM的設(shè)計圖 :

圖2.3.0
  1. 前端讀取源碼吏垮,經(jīng)過傳統(tǒng)步驟后,多增加一步生成中間代碼IR罐旗,然后輸出IR給優(yōu)化器膳汪。

  2. 優(yōu)化器讀取的是前端傳輸過來的IR,優(yōu)化的也是IR九秀,然后輸出的還是IR遗嗽。所以優(yōu)化器只需要對傳入過來的IR做優(yōu)化即可,無論前端是什么樣的源語言類型鼓蜒,都會被轉(zhuǎn)成IR痹换。

  3. 后端/代碼生成器處理的則是優(yōu)化器傳來的IR,也是只需要針對IR做處理都弹,不需要管前端到底是什么類型的源語言娇豫。

優(yōu)勢 :

  • 如果前端出現(xiàn)了新的源語言類型,LLVM只需要針對新語言適配一個IR轉(zhuǎn)換器即可畅厢,優(yōu)化器和后端都不需要進行大的改變冯痢,甚至不用改變。

  • 如果后端出現(xiàn)了新的硬件架構(gòu),LLVM只需要針對新的硬件架構(gòu)適配一個IR轉(zhuǎn)換器即可浦楣,優(yōu)化器和前端則不需要進行大的改變袖肥,甚至不用改變。

三振劳、關(guān)于Clang

1. 什么是Clang

內(nèi)容引自Clang官網(wǎng)椎组,個人翻譯,如有不準確的地方历恐,還請不吝賜教寸癌。

ClangLLVM原生的針對CC++夹供、Objective-C的編譯器灵份。

它的存在是為了提供一個平臺,Clang做到了 :

  • 非诚ⅲ快的編譯速度
  • 非常有用的error信息和warning警告
  • 可以構(gòu)建非常優(yōu)秀的源代碼

Clang Static AnalyzerClang -tidy都是可以自動發(fā)現(xiàn)你代碼里bug的工具填渠。它們都是Clang工具中很好的例子,它們可以將Clang編譯器前端作為一個庫去解析C/C++的代碼鸟辅。

2. Clang的概述

總的來說氛什,ClangLLVM的子項目,它是基于LLVM架構(gòu)的輕量級編譯器匪凉,誕生之初是為了替代GCC枪眉,因為GCC是傳統(tǒng)型的編譯器,雖然非常好用再层,但是GCC的源碼太長了贸铜,又晦澀難懂,而且編譯速度還可提升聂受。于是基于LLVM架構(gòu)的Clang就逐步的擴大了影響力蒿秦。

3. 一些LLVM或Clang中的名詞解釋

3.1 詞法分析

詞法分析是計算機科學(xué)中將字符序列轉(zhuǎn)換為單詞序列的過程。

詞法分析是整個編譯流程的第一個階段蛋济,是編譯的基礎(chǔ)棍鳖。詞法分析要做的是從左到右一個字符一個字符的讀入源程序,對構(gòu)成源程序的字符進行掃描碗旅,然后根據(jù)構(gòu)詞規(guī)則識別單詞(也稱單詞符號或符號渡处,英文叫做Token)。

所謂單詞就是一個字符串祟辟,是構(gòu)成源代碼的最小單位医瘫。

詞法分析一般都是經(jīng)過詞法分析的程序或者專門的函數(shù)來完成的,這種程序或者函數(shù)叫做詞法分析器旧困,也叫掃描器(Scanner)登下。

3.2 語法分析

語法分析是整個編譯流程中的一個邏輯階段茫孔。語法分析的任務(wù)是在詞法分析的基礎(chǔ)上,將單詞序列的組合成各種語法短語被芳,如程序缰贝、語句、表達式等畔濒。

語法分析是判斷源程序在語法的結(jié)構(gòu)上是否正確剩晴。它和詞法分析分別像英語中的語法和單詞,詞法分析標明了單詞的含義侵状,語法分析則判斷單詞組合成的語句是否符合語法規(guī)則赞弥。

3.3 語義分析

語義分析也是整個編譯流程中的一個邏輯階段。語義分析的任務(wù)是對結(jié)構(gòu)上正確的源程序的上下文進行有關(guān)性質(zhì)的檢查和類型檢查趣兄。

語義分析是檢查源程序有無語義錯誤绽左,為代碼生成階段收集類型信息。

語義分析檢查的是源程序是否符合規(guī)定的語言規(guī)范艇潭。

語義分析是編譯程序最實質(zhì)性的工作拼窥,它是第一次對源代碼做出解釋的階段,引起源程序的實質(zhì)變化蹋凝。

語義和語法的區(qū)別鲁纠,我舉個例子,方便大家理解鳍寂。比如 : 我學(xué)習(xí)編程和編程學(xué)習(xí)我改含。兩者的語法都是沒有問題的,符合語法的規(guī)范——主謂賓迄汛。但是后者并不符合語義規(guī)范捍壤,后者的語言意義是一種空泛的表達。

3.4 抽象語法樹

這是源代碼的語法結(jié)構(gòu)的一種抽象表示鞍爱。所謂抽象語法白群,是指不會表示出所有細節(jié)的語法。

4. iOS中可能遇到的Clang常用指令

這里只說一些iOS中可能常用的Clang指令硬霍,如果想要全部的Clang指令集,可以在terminal終端中輸入clang --help查看笼裳。

如果認為上面的命令查看不方便的唯卖,這里還有github版本,內(nèi)容就是copy的clang --help躬柬。

或者可以直接在LLVM官網(wǎng)的Clang Document查詢拜轨。

Clang命令 釋義
-ccc-print-phases 打印源碼的編譯階段,得到的打印結(jié)果就是整個源碼到機器代碼的整體流程步驟允青。
-rewrite-objc 將OC源碼編譯成C++源碼
-E 查看預(yù)處理階段詳細步驟(在terminal中查看橄碾,也可以生成一個新文件 : clang -E main.m >> new_main.m) 。>>就是文件重定向。
-c 必須在-E之后才可以使用法牲,例如clang -E main.m -c史汗。只進行預(yù)處理,編譯拒垃,匯編步驟停撞,不進行鏈接步驟。執(zhí)行完成后生成的是.o鏈接文件悼瓮。
-S 只進行預(yù)處理和編譯步驟戈毒,不進行匯編,鏈接等后續(xù)步驟横堡。執(zhí)行完成后埋市,生成的是.s匯編代碼文件。
-o <file> 完成預(yù)編譯-->編譯-->匯編-->鏈接后命贴,生成可執(zhí)行文件到<file>文件道宅。
-g 在生成的可執(zhí)行文件中,包含標準的調(diào)試信息套么。
-i <路徑>(應(yīng)該是大寫i最標準) 在頭文件中的搜索路徑中添加<路徑>培己。
-fmodules 啟用模塊化語言特性。
-fsyntax-only 編譯器并不生成代碼胚泌,后續(xù)的操作只是語法級別的修改省咨。
-Xclang <arg> clang編譯器傳遞參數(shù)<arg>
-dump-tokens 運行預(yù)處理器玷室,將源碼內(nèi)部拆分成各種單詞(Token)零蓉。
-ast-dump 構(gòu)建抽象語法樹AST,然后對其進行拆解和調(diào)試穷缤。
-fobjc-arc 生成Objective-C指針的retainrelease的調(diào)用敌蜂。
-emit-llvm 對匯編文件和目標文件生成LLVM IR代碼。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末津肛,一起剝皮案震驚了整個濱河市章喉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌身坐,老刑警劉巖秸脱,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異部蛇,居然都是意外死亡摊唇,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門涯鲁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來巷查,“玉大人有序,你說我怎么就攤上這事〉呵耄” “怎么了旭寿?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長髓需。 經(jīng)常有香客問我许师,道長,這世上最難降的妖魔是什么僚匆? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任微渠,我火速辦了婚禮,結(jié)果婚禮上咧擂,老公的妹妹穿的比我還像新娘逞盆。我一直安慰自己,他們只是感情好松申,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布云芦。 她就那樣靜靜地躺著,像睡著了一般贸桶。 火紅的嫁衣襯著肌膚如雪舅逸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天皇筛,我揣著相機與錄音琉历,去河邊找鬼。 笑死水醋,一個胖子當著我的面吹牛旗笔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拄踪,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼蝇恶,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了惶桐?” 一聲冷哼從身側(cè)響起撮弧,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎姚糊,沒想到半個月后贿衍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡叛拷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了岂却。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忿薇。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡裙椭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出署浩,到底是詐尸還是另有隱情揉燃,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布筋栋,位于F島的核電站炊汤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏弊攘。R本人自食惡果不足惜抢腐,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望襟交。 院中可真熱鬧迈倍,春花似錦、人聲如沸捣域。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽焕梅。三九已至迹鹅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贞言,已是汗流浹背斜棚。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蜗字,地道東北人打肝。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像挪捕,于是被迫代替她去往敵國和親粗梭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

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