前言
今天是舉國同慶的國慶假期的第一天杖爽,早上看到莊嚴的升旗激動壞了葫松,中午都沒睡覺粹排,刷著朋友圈看著大家都在玩著使碾,心想要不沒事就寫點東西吧蜜徽。有個小伙伴寫文章后都會發(fā)給我看一下(挑剔的我祝懂,開始給挑毛病)娜汁,還鼓勵我繼續(xù)寫技術(shù)文檔嫂易,說實話好久沒寫了,有點亂掐禁,湊合著看吧怜械,歡迎扔磚頭。最后祝大家國慶假期快樂傅事,玩的開心喲~~~
很久前學了點關(guān)于LLVM的東西缕允,一直沒有時間整理,現(xiàn)在抽時間來總結(jié)一下蹭越,廢話不多說障本,現(xiàn)在開始正經(jīng)起來。
LLVM
一响鹃、簡介
1驾霜、什么是LLVM
官網(wǎng):https://llvm.org/
LLVM項目是模塊化、可重用的編譯器以及工具鏈技術(shù)的集合买置。曾在2012年獲得軟件系統(tǒng)獎項粪糙。
有些文章把LLVM當做Low Level Virtual Machine(低級虛擬機)的縮寫簡稱,官方描述如下:
The name "LLVM" itself is not an acronym; it is the full name of the project.
“LLVM”這個名稱本身不是首字母縮略詞忿项,它是項目的全名
2蓉冈、創(chuàng)始人
Chris Lattner,看到這個名字有沒有很熟悉轩触?對了寞酿!他就是Swift之父
3、編譯器的架構(gòu)
A脱柱、傳統(tǒng)的編譯器架構(gòu)
Frontend:前端
詞法分析伐弹、語法分析、語義分析榨为、生成中間代碼
Optimizer:優(yōu)化器
中間代碼優(yōu)化
Backend:后端
生成機器碼
B掸茅、LLVM架構(gòu)
不同的前端后端使用統(tǒng)一的中間代碼LLVM Intermediate Representation(LLVM IR)
如果需要支持一種新的變成語言,那么只需要實現(xiàn)一個新的前端
如果需要支持一種新的硬件設備柠逞,那么只需要實現(xiàn)一個新的后端
優(yōu)化階段是一個通用的階段昧狮,它針對的是統(tǒng)一的LLVM IR,不論是支持新的編程語言板壮,還是只是新的硬件設備都不需要對優(yōu)化階段做修改
相比之下逗鸣,GCC的前端和后端沒分的太開,前端后端耦合在一起,所以GCC為了支持一門新的語言或者為了支持一個新的目標平臺就變得特別困難
LLVM現(xiàn)在被作為實現(xiàn)各種靜態(tài)和運行時編譯語言的通用基礎結(jié)構(gòu)(GCC家族撒璧、Java寒波、? ?.NET腻暮、Python、Ruby、Schem风纠、Haskell蓖救、D等)
Clang
1舅桩、什么是Clang
LLVM項目的一個子項目
基于LLVM架構(gòu)的C/C++/Objective-C編譯器前端
2颗搂、相比于GCC,Clang具有的優(yōu)點有以下幾點:
編譯速度快:在某些平臺上蹄胰,Clang的編譯速度顯著的快過GCC(Debug模式下編譯OC速度比GCC快3倍)
占用內(nèi)存性酪!:Clang生成的AST所占用的內(nèi)存是GCC的五分之一左右
模塊化設計:Clang采用基于庫的模塊化設計,易于IDE集成及其他用途的重用
診斷信息可讀性強:在編譯過程中裕寨,Clang穿件并保留了大量詳細的元數(shù)據(jù)(metadata)浩蓉,有利于調(diào)試和錯誤報告
設計清晰簡單,容易理解宾袜,易于擴展增強
Clang與LLVM
OC源文件的編譯過程
命令行查看編譯的過程:
$ clang -ccc-print-phases main.m
查看preprocessor(預處理)的結(jié)果:
$ clang -E main.m
詞法分析捻艳,生成Token:
$ clang -fmodules -E -Xclang -dump-tokens main.m
語法分析庆猫,生成語法樹(AST讯泣,Abstract Syntax Tree):?
$ clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
LLVM IR
LLVM IR有3種表示形式:
1阅悍、text:便于閱讀的文本格式,類似于匯編語言昨稼,拓展名 .||
$ clang -S -emit-llvm main.m
2节视、memory:內(nèi)存格式
3、bitcode:二進制格式假栓,拓展名 .bc
$ clang -c -emit-llvm main.m
源碼下載
1寻行、下載LLVM
$ git clone https://git.llvm.org/git/llvm.git/
2、下載Clang
$ cd llvm/tools
$ git clone https://git.llvm.org/git/clang.git/
源碼編譯
安裝cmake和ninja(先安裝brew匾荆,https://brew.sh/)
$ brew install cmake
$ brew install ninja
ninja如果安裝失敗拌蜘,可以直接從github獲取release版放入【/usr/local/bin】中
https://github.com/ninja-build/ninja/releases
在LLVM源碼同級目錄下新建一個【llvm_build】目錄(最終會在【llvm_build】目錄下生成【build。ninja】)
$ cd llvm_build
$ cmake -G Ninja ../llvm -DCMAKE_INSTALL_PREFIX=LLVM的安裝路徑
依次執(zhí)行編譯牙丽、安裝指令
$ ninja
$ ninja install
也可以生成Xcode項目再進行編譯简卧,但是速度很慢(可能需要1個多小時)
在llvm同級目錄下新建一個【llvm_xcode】目錄
$ cd llvm_xcode
$ cmake -G Xcode ../llvm
Clang插件開發(fā)
1 -- 插件目錄
在【clang/tools】源碼目錄下新建一個插件目錄,假設叫做【mj-plugin】
在【clang/tools/CMakeLists.txt】最后加入內(nèi)容: add_clang_subdirectory(mj-plugin)烤芦,小括號里是插件目錄名
2 -- 插件必要文件
在【mj-plugin】目錄下新建一個【CMakeLists.txt】举娩,文件內(nèi)容是:add_llvm_loadable_module(MJPlugin MJPlugin.cpp)
MJPlugin是插件名,MJPlugin.cpp是源代碼文件
3 -- 編寫插件源碼
4 -- 編譯插件
利用cmake生成的Xcode項目來編譯插件(第一次編寫完插件,需要利用cmake重新生成一下Xcode項目)
插件源代碼在【Sources/Loadable modules】目錄下可以找到铜涉,這樣就可以直接在Xcode里編寫插件代碼
選擇MJPlugin這個target進行編譯智玻,編譯完會生成一個動態(tài)庫文件
5 -- 加載插件
在Xcode項目中指定加載插件動態(tài)庫:BuildSettings > OTHER_CFLAGS
-Xclang -load -Xclang 動態(tài)庫路徑 -Xclang -add-plugin -Xclang 插件名稱
6 -- Hack Xcode
首先要對Xcode進行Hack,才能修改默認的編譯器
下載【XcodeHacking.zip】芙代,解壓吊奢,修改【HackedClang.xcplugin/Contents/Resources/HackedClang.xcspec】的內(nèi)容,設置一下自己編譯好的clang的路徑
然后在XcodeHacking目錄下進行命令行纹烹,將XcodeHacking的內(nèi)容剪切到Xcode內(nèi)部
$ sudo mv HackedClang.xcplugin `xcode-select -print path`/../PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins
$ sudo mv HackedBuildSystem.xcspec `xcode-select -print path`/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Specifications
7 -- 修改Xcode的編譯器
8 -- 編譯項目
編譯項目后页滚,會在編譯日志看到MJPlugin插件的打印信息(如果插件更新了,最好先Clean一下項目)
9 -- 更多
關(guān)于AST的資料
https://clang.llvm.org/doxygen/namespaceclang.htmlp??
https://clang.llvm.org/doxygen/classclang_1_1Decl.htmlp
https://clang.llvm.org/doxygen/classclang_1_1Stmt.html
10 -- 應用結(jié)果
以上就是該階段的全部內(nèi)容了滔韵,雖然在自己操作的過程中因為電腦內(nèi)存太小而導致沒有全部完成逻谦,有點小遺憾,希望閱讀該文章的小伙伴們能夠成功喲~加油~
感謝MJ大神陪蜻,歡迎點贊邦马,打賞喲~~~