1窄锅、引言
作為一名iOS開發(fā)芥驳,很難不從各種渠道聽說關于LLVM的消息僵腺,如早年編譯器從GCC過度到LLVM-GCC呵晚,然后由于GCC的開源協(xié)議改變瘩欺,讓Apple徹底拋棄GCC轉而投向目前正在使用的Clang必盖。比如之前微信團隊分享的編譯優(yōu)化。再如之后業(yè)內影響頗大的字節(jié)團隊分享的二進制重排提及的插裝所知的也是clang俱饿。在安全方面歌粥,對LLVM pass的開發(fā)也是主力軍等等。拍埠。失驶。
所以適當的了解LLVM對自己的知識廣度是有非常大的幫助的,最少在讀一篇有深度的文章的時候枣购,不至于摸不到門檻嬉探。
2、什么是LLVM棉圈,什么是Clang
LLVM 最早是底層虛擬機(Low Level Virtual Machine)的縮寫涩堤,但由于項目發(fā)展過快,底層虛擬機已經不足以介紹項目本身分瘾,而它已經發(fā)展成為一個包含前端胎围,優(yōu)化器和后端的完整編譯框架,并且全稱就叫LLVM德召,并非任何英文的簡稱了白魂。其主要由C++
編寫而成。
一上岗、什么是LLVM
傳統(tǒng)編譯器架構
傳統(tǒng)編譯器架構(如GCC)將前端福荸,優(yōu)化器,后端耦合在一起液茎,優(yōu)化難度大逞姿,對多架構兼容的也不太友好,需要做大量重復的工作捆等。
LLVM架構
LLVM架構三端(前端滞造,優(yōu)化器,后端)清晰
1栋烤、前端面向源碼谒养,將源碼轉化為同樣的LLVM Intermediate Representation (LLVM IR),
2、優(yōu)化器則針對LLVM IR進行一系列優(yōu)化买窟,如:無用代碼消除丰泊,內存優(yōu)化,甚至是代碼混淆等等始绍。瞳购。。
3亏推、后端則將IR轉化為對應的機器碼学赛。
從兩種架構的設計可以看得出來,LLVM最大的優(yōu)勢就在于三端分離吞杭,所以如果我們想編寫一門獨立的語言盏浇,只需要編寫相應的前端就可以兼容各大終端設備。如果以后多了一種終端設備芽狗,我們也只需要編寫一次后端绢掰,就可以兼容各大語言。
二童擎、什么是Clang
Clang是LLVM項目的一個子項目滴劲,基于LLVM架構的C/C++/Objective-C編譯器前端(Swift的前端是Swift)。
Apple早年從GCC切換到LLVM的時候顾复,開始用的是基于GCC庫寫的一套LLVM前端哑芹,但由于Apple對代碼優(yōu)化的要求更高,而GCC官方又遲遲不肯對針對性的更新捕透,所以衍生出GCC的一套分支LLVM-GCC聪姿,由Apple自己維護,導致Apple使用的GCC版本遠低于官方版本乙嘀,最后由于GCC的開源協(xié)議改變末购,讓Apple徹底拋棄GCC轉而投向自研的Clang。
相比于GCC虎谢,Clang具有如下優(yōu)點:
· 編譯速度快:在某些平臺上盟榴,Clang的編譯速度顯著的快過GCC(Debug模式下編譯OC速度比GGC快3倍)
· 占用內存小:Clang生成的AST所占用的內存是GCC的五分之一左右
· 模塊化設計:Clang采用基于庫的模塊化設計,易于 IDE 集成及其他用途的重用
· 診斷信息可讀性強:在編譯過程中婴噩,Clang 創(chuàng)建并保留了大量詳細的元數據 (metadata)擎场,有利于調試和錯誤報告
· 設計清晰簡單,容易理解几莽,易于擴展增強
3迅办、編譯過程
① 下載
找到一個自己方便的目錄,直接在github上下載(耗時根據網絡情況而定章蚣,包括git文件總大小大概3G):
> mkdir llvm_all && cd llvm_all
> git clone https://github.com/llvm/llvm-project.git
完成后你將會看到這樣一個目錄:
目前我們只需要關注其中兩個文件clang
和llvm
分別是clang
的源碼和llvm
的源碼
② 編譯
cmake -S llvm -B build -G <generator> [options]
官方介紹了4種編譯工具:
-
Ninja
--- for generating Ninja build files. Most llvm developers use Ninja. -
Unix Makefiles
--- for generating make-compatible parallel makefiles. -
Visual Studio
--- for generating Visual Studio projects and solutions. -
Xcode
--- for generating Xcode projects.
官方推薦使用Ninja
編譯站欺,因為其速度最快,筆者也親試,整個過程只需20分鐘左右即可完成矾策。但作為一名iOS開發(fā)磷账,還是習慣使用Xcode編譯,畢竟界面看起來親切贾虽,而且可在之后我們編寫插件的或者IR Pass
的時候也能或得良好的代碼提示逃糟,缺點就是慢一點。筆者使用Xcode編譯花了40分鐘左右蓬豁,這根據個人電腦配置而定履磨,配置稍微差一點,一個小時多也是正常的庆尘。
另外還有一些可選參數:
-
-DLLVM_ENABLE_PROJECTS='...'
--- 可選一些LLVM的子項目共同編譯,如clang
,clang-tools-extra
,libcxx
,libcxxabi
,libunwind
,lldb
,compiler-rt
,lld
,polly
, 或者cross-project-tests
例如巷送,如果要編譯包括Clang
,libcxx
, 和libcxxabi
的LLVM
, 可以增加-DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi"
-
-DCMAKE_INSTALL_PREFIX=directory
--- 指定一個絕對地址來存放編譯的結果驶忌,默認存放在/usr/local
. -
-DCMAKE_BUILD_TYPE=type
--- 這是編譯的類型,如Debug
,Release
,RelWithDebInfo
, 和MinSizeRel
. 默認的是Debug
. -
-DLLVM_ENABLE_ASSERTIONS=On
--- 在啟用斷言檢查的情況下編譯(對于Debug構建笑跛,默認值為Yes付魔,對于所有其他構建類型,默認值為No).
Ninja編譯
所以如果需要使用Ninja
編譯的話命令飞蹂,需要先創(chuàng)建Ninja
模板(大概5分鐘)几苍,然后再編譯:
// 創(chuàng)建ninja的目錄,并且進入其中
mkdir llvm_ninja && cd llvm_ninja
// 指定llvm源碼目錄陈哑,新建build目錄妻坝,創(chuàng)建ninja模板,增加子項目clang惊窖,并且模板之后編譯的結果放在llvm_release目錄下
cmake -S ../llvm-project/llvm -B build -G Ninja -DLLVM_ENABLE_PROJECTS="clang" -DCMAKE_INSTALL_PREFIX=/Volumes/ExDisk/LLVM/llvm_all/llvm_release
從上圖中可以看到刽宪,我們增加的clang
參與了編譯,而clang-tools-extra
沒有參與編譯界酒。
如果你看到下面這樣的結果圣拄,那么恭喜ninja
模板已經建好
然后進入模板目錄,輸入命令開始編譯
cd build
ninja && ninja install
完成后可以在指定的release目錄下看到所有的命令了
Xcode編譯
同樣的先在對應的目錄下毁欣,生成Xcode模板庇谆,但xcode就不指定對應的release目錄了,因為做iOS開發(fā)的應該都知道凭疮,Xcode的編譯產物有對應的product文件(大概10分鐘)
mkdir llvm_xcode && cd llvm_xcode
cmake -S ../llvm-project/llvm -B build -G Xcode -DLLVM_ENABLE_PROJECTS="clang"
同樣饭耳,結束后可以看到這樣的目錄
打開LLVM工程,回到了熟悉的畫面
選中Automatically Creat Schemes后执解,在選擇al_build哥攘,cmd+b即可開始編譯(大概40分鐘)。
在熟悉的地方可以看到對應的編譯產物
在同級目錄下,可以看到對應的命令行工具逝淹,比如我們下章需要講到的clang耕姊。
4、總結
為什么編譯單獨拿出來栅葡?LLVM就想一個含羞的蒙面女子茉兰,大多數人都是只可遠觀,而不敢褻玩欣簇,其實蒙面女子本身也是及其渴望有個勇士來揭開其面紗规脸,而編譯自己的LLVM就像是這么一步,只要自己邁出了這一步熊咽,那么就是個嶄新的世界莫鸭。
下一章,就會開始聊一些好玩的事情横殴,比如如何編譯自己的插件被因,如何開發(fā)自己混淆器,如何開發(fā)自己的一門開發(fā)語言衫仑。
參考
1梨与、 GCC,LLVM文狱,Clang編譯器對比
2粥鞋、 微信團隊分享的編譯優(yōu)化
3、 深入剖析 iOS 編譯 Clang LLVM
4瞄崇、 LLVM Github地址