- LLVM是模塊化但金、可重用的編譯器以及工具鏈技術(shù)的
- GCC铃在、LLVM、clang
- 傳統(tǒng)的編譯器架構(gòu):前端-優(yōu)化器(中間代碼)-后端->機器代碼
- 不同的前端后端使用統(tǒng)一的中間代碼LLVM Intermediate Representation(LLVM IR)
- 如果需要支持一種新的編程語言,只要實現(xiàn)一個新的前端
- 如果需要支持一種新的硬件設(shè)備翘单,只要實現(xiàn)一個新的后端
- 優(yōu)化階段使用統(tǒng)一的LLVM IR,不需要做修改
- GCC 前端后端耦合在一起蹦渣,需要每個都實現(xiàn)
- LLVM現(xiàn)在被作為實現(xiàn)各種靜態(tài)和運行時編譯語言的通用基礎(chǔ)架構(gòu)(GCC家族哄芜、Java、.Net柬唯、Python认臊、Ruby、Scheme锄奢、Haskell失晴、D等)
Clang
- LLVM項目的一個子項目
- 基于LLVM架構(gòu)的C/C++/Objective-C編譯
- 相比GCC剧腻,Clang編譯速度快(Debug模式下編譯OC速度比GCC快三倍)、占用內(nèi)存效(Clang生成的AST占用內(nèi)存是GCC的1/5)涂屁、模塊化設(shè)計(Clang基于庫的模塊化設(shè)計书在,易于IDE集成和其他用途的重用)、診斷信息可讀性強(在編譯過程種胯陋,Clang創(chuàng)建并保留了大量詳細(xì)的元數(shù)據(jù)(metaData)蕊温,有利于調(diào)試)
- clang代碼需要放在./llvm/tools下
Clang+LLVM
- 前端使用Clang進行詞法分析、語法分析遏乔、語義分析义矛、生成中間代碼
- 優(yōu)化器和后端使用LLVM
OC源文件的編譯過程
- 通過命令行查看編譯過程:$ clang -ccc-print-phases main.m
- 詞法分析,生成token:$ clang -fmodules -E -Xclang -dump-tokens main.m
- 生成語法樹-AST:$ clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
LLVM IR
LLVM IR有3種表現(xiàn)形式:
- text:文本格式盟萨,$ clang -S -emit-llvm main.m
- memory: 內(nèi)存格式
- bitcode:二進制格式凉翻,$ clang -C -emit-llvm main.m
LLVM IR語法:
- 注釋以分號;開頭
- 全局標(biāo)識符以@開頭,局部標(biāo)識符以%開頭
- alloca捻激,在當(dāng)前函數(shù)棧幀種分配內(nèi)存
- i32制轰,32bit
- align,內(nèi)存對齊
- load胞谭,讀取數(shù)據(jù)
- store垃杖,寫入數(shù)據(jù)
LLVM源碼編譯
- 安裝cmake和ninja,ninja可以直接從github下載解壓到bin目錄
brew install cmake
brew install ninja
- 編譯ninja模板:
cmake -G Ninja ../llvm -DCMAKE_INSTALL_PREFIX=LLVM的安裝路徑
- $ ninja
- $ ninja install
- 也可以生成xcode模板進行編譯
應(yīng)用與實踐
libclang丈屹、libTooling
- 官方參考:https://clang.llvm.org/docs/Tooling.html
- 應(yīng)用:語法樹分析调俘、語言轉(zhuǎn)換
clang插件開發(fā)
- https://clang.llvm.org/docs/ClangPlugins.html
- https://clang.llvm.org/docs/ExternalClangExamples.html
- https://clang.llvm.org/docs/RAVFrontendAction.html
- 應(yīng)用:代碼檢查(命令規(guī)范、代碼規(guī)范)
Pass開發(fā)
- https://clang.llvm.org/docs/WritingAnLLVMPass.html
- 應(yīng)用:代碼優(yōu)化旺垒、代碼混淆
開發(fā)新的編程語言
- https://llvm-tutorial-cn.readthedocs.io/en/latest/index.html
- https://kaleidoscope-llvm-tutorial-zh-cn.readthedocs.io/zh_CN/latest/
clang插件開發(fā)
- 在llvm源碼目錄下clang/tools目錄下開發(fā)彩库,新建目錄XXPlugin,在CMakeList.txt添加該目錄
- XXPlugin下新建一個cpp文件先蒋,新建一個txt骇钦,txt中添加這個cpp
add_llvm_loadable_module(XXPlugin XXPlugin.cpp)
//如果又多個Plugin,都放在括號中竞漾,逗號分割
- 在cpp中寫一個class XXAction繼承自PluginASTAction
- 注冊插件
static FrontendPluginRegistry::Add<XXPlugin::XXAction>
X("XXPlugin", "description");
- 重寫CreateASTConsumer和ParseArgs(直接返回true)兩個方法
- 定義一個Consumer類繼承自ASTConsumer
- 重寫HandleTranslationUnit方法眯搭,該方法當(dāng)Clang編譯完語法樹時調(diào)用
- 編譯完成后的dylb動態(tài)庫放在Xcode中,Build Settings中Other C Flags添加該動態(tài)庫路徑以及插件名稱业岁,同時Compiler需要改成自己編譯好的llvm編譯器(Default自帶編譯器不允許加載插件)鳞仙。如果重新編譯插件代碼生成dylb,使用這個插件的工程需要Clean重新加載插件叨襟。
- 需要對Xcode進行Hack,才能修改默認(rèn)編譯器幔荒。下載XcodeHacking.zip糊闽,修改HackedClang文件中的ExecPath的路徑為llvm本地路徑梳玫。然后在XcodeHacking目錄下執(zhí)行命令
$ 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
- 構(gòu)造一個Consumer,用來拋出警告或錯誤信息
- MatchFinder可以用來查找語法樹上下文
注:資料整理自MJ公開課右犹。