規(guī)則檢查器-環(huán)境介紹及抽象語法樹初步認(rèn)識
本文主要簡單介紹芬萍,llvm和clang環(huán)境搭建柬祠,抽象語法樹及checker的簡單認(rèn)識
llvm/clang背景
- llvm介紹
llvm是一個模塊化和可重用的編譯器和工具鏈技術(shù)的集合负芋。
LLVM最初是在2000年由伊利諾伊大學(xué)香檳分校(UUIC)的學(xué)生Chris Lattner及其碩士顧問Vikram Adve創(chuàng)建的研究項目惩猫,并在2003年發(fā)布第一個正式版本,目的是提供一種基于SSA的現(xiàn)代編譯策略,這種策略能夠支持任何編程語言的靜態(tài)和動態(tài)編譯迟赃。
LLVM是當(dāng)今最流行的開源編譯器框架項目左刽,你可以使用它編寫自己的編譯器欠痴。
LLVM的命名最早源自于底層虛擬機(jī)(Low Level Virtual Machine)的首字母縮寫喇辽,由于這個項目的范圍并不局限于創(chuàng)建一個虛擬機(jī)菩咨,這個縮寫導(dǎo)致了廣泛的疑惑特占。LLVM開始成長之后是目,成為眾多編譯工具及低端工具技術(shù)的統(tǒng)稱,使得這個名字變得更不貼切长踊,開發(fā)者因而決定放棄這個縮寫的意涵,現(xiàn)今LLVM已單純成為一個品牌阱佛,適用于LLVM下的所有項目
- Clang介紹
Clang:是一個C凑术、C++、Objective-C和Objective-C++編程語言的編譯器前端泄鹏。它采用了底層虛擬機(jī)(LLVM)作為其后端。它的目標(biāo)是提供一個GNU編譯器套裝(GCC)的替代品车猬。作者是克里斯·拉特納(Chris Lattner)韩脏,在蘋果公司的贊助支持下進(jìn)行開發(fā)赡矢,而源代碼授權(quán)是使用類BSD的伊利諾伊大學(xué)厄巴納-香檳分校開源碼許可。Clang主要由C++編寫空民。
Clang項目包括Clang前端和Clang靜態(tài)分析器等。這個軟件項目在2005年由蘋果電腦發(fā)起浊猾,是LLVM(Low Level Virtual Machine)編譯器工具集的前端(front-end),目的是輸出代碼對應(yīng)的抽象語法樹(Abstract Syntax Tree, AST)偷办,并將代碼編譯成LLVM Bitcode。接著在后端(back-end)使用LLVM編譯成平臺相關(guān)的機(jī)器語言逐工。
Clang本身性能優(yōu)異棕硫,其生成的AST所耗用掉的內(nèi)存僅僅是GCC的20%左右纬纪。2014年1月發(fā)行的FreeBSD10.0版將Clang/LLVM作為默認(rèn)編譯器摘仅。
- Clang-Tidy介紹
clang-tidy是一個源碼分析工具,用于檢查? C矾端、 C++和 Objective-C 程序的bugs.
該工具是完全開源的,并且是Clang項目的一部分. 和Clang其他部分一樣,該工具作為C++庫的方式實現(xiàn)滚粟,可以方便的集成于其他工具和程序.
什么是LLVM IR
- LLVM IR 是一門低級語言,語法類似于匯編,是編譯中程序的間表示
- 任何高級編程語言(如C++)都可以用LLVM IR表示
- 基于LLVM IR可以很方便地進(jìn)行代碼優(yōu)化
參考鏈接:https://www.cnblogs.com/Tu9oh0st/p/16358531.html
LLVM/CLANG 關(guān)系介紹
Clang為前端llvm架構(gòu)前端
1.源代碼通過clang的詞法分析生成tokens
2.通過clang的語法分析生成了AST抽象語法樹
3.通過clang的語義分析生成中間表示IR
Clang-tidy
LLVM后端
1.負(fù)責(zé)優(yōu)化IR代碼
2.負(fù)責(zé)生成目標(biāo)程序
LLVM/CLANG 環(huán)境準(zhǔn)備
1.查看環(huán)境依賴钢坦,升級低版本檢查工具?Getting Started with the LLVM System - Requirements
2. cmake版本過低:
去https://cmake.org/files/下載所需版本的源碼。也可以使用wget下載,例如:
wget https://cmake.org/files/v3.22/cmake-3.22.1.tar.gz
- 解壓:tar -xvzf cmake-3.22.1.tar.gz
- 進(jìn)入解壓目錄颗管,配置成功之后顯示:CMake has bootstrapped. Now run make.
chmod 777 ./configure
./configure
- 配置完成后,編譯:make
- 編譯完成后比吭,安裝: sudo make install
- 最后使用新安裝的cmake替換舊版本绣溜,其中/usr/local/bin/cmake為新安裝的cmake目錄底哗。
sudo update-alternatives --install /usr/bin/cmake cmake /usr/local/bin/cmake 1 --force
3.下載ninja和gcc
sudo apt install ninja-build
sudo apt install gcc g++
4.下載 LLVM工程:
- 創(chuàng)建文件夾并下載llvm工程:git clone https://github.com/llvm/llvm-project.git
- 編譯 LLVM 和 Clang:
cd llvm-project
mkdir build?(in-tree build is not supported)
cd build
- 下方命令會同時以release模式編譯 LLVM前标、Clang以及Clang-tidy:
方式一:cmake -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" ../llvm
make (等的花都謝了音比,編的好慢盎纭!)
方式二:以ninja方式編譯:
cmake -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" -DCMAKE_BUILD_TYPE=Release -G "Ninja" ../llvm
ninja(小內(nèi)存ninja -j2)
sudo ninja install 安裝到系統(tǒng)
5.LLVM安裝完成狀態(tài)驗證
通過執(zhí)行clang-tidy -list-checks -checks=*命令秫舌,我們可以查看當(dāng)前可用的所有check娇未。
而如果想要執(zhí)行某個檢查,那就執(zhí)行?clang-tidy --checks='check名字' 被測文件
- 添加 llvm/build/bin 到path:
export PATH=/XXXl/llvm-project/build/bin/:$PATH
clang --help
clang file.c -fsyntax-only?(正確性檢查)
clang file.c -S -emit-llvm -o -?(打印未優(yōu)化的llvm代碼)
clang file.c -S -emit-llvm -o - -O3
clang file.c -S -O3 -o -?(輸出本地機(jī)器碼)
運行測試套件:
make check-clang
抽象語法樹
抽象語法樹(Abstract Syntax Tree卸亮,AST)
Clang的AST非常類似于編寫的C++代碼和C++標(biāo)準(zhǔn)段直。AST中每一個節(jié)點都是一個Decl或者Stmt類的一個實例螺垢。
1. 聲明類Decl
Decl用于表示在一個聲明或者定義功茴,包括變量墨林、typedef定義酌呆、函數(shù)和結(jié)構(gòu)體等。它是一個基類,不同的聲明表達(dá)式都繼承自它。如VarDecl類、 FunctionDecl類电湘。
2.語句類Stmt
- Stmt用于表示在源代碼中的語句胡桨,包括簡單語句和復(fù)雜語句呢诬,程序中的函數(shù)都是由語句組成的尚镰。
3.Stmt也是一個基類阀圾,不同的語句都繼承自它。
- 在C語言中最簡單的語句形式是表達(dá)式狗唉。
- 大多數(shù)C語言語句是這類形式的初烘,其他簡單語句是跳轉(zhuǎn)語句包括return、continue分俯、goto.
-? 復(fù)雜語句由簡答語句組成肾筐,可分為兩類:跳轉(zhuǎn)語句和循環(huán)語句,跳轉(zhuǎn)語句包括if/else缸剪、switch吗铐,循環(huán)語句包括while、do-while和for循環(huán)結(jié)構(gòu)杏节。
查看抽象語法樹
系統(tǒng)提供一個內(nèi)置的ast-dump方法唬渗,可以把整段代碼按照AST結(jié)構(gòu)翻譯成人類可以讀懂的格式典阵。這種格式基于遍歷整段代碼,然后按照代碼結(jié)構(gòu)對AST節(jié)點進(jìn)行相應(yīng)層次結(jié)構(gòu)的組合镊逝。
Demo:test.cc
int f(int x) {
int result=(x/42);?
return result;
默認(rèn)情況下壮啊,Clang 是許多工具的前端;-Xclang 用于將選項直接傳遞給 C++的前端。
-fsyntax-only 只進(jìn)行語法檢查蹋半,不進(jìn)行編譯他巨。
查看一下上面代碼對應(yīng)生成的抽象語法樹AST:
clang -Xclang -ast-dump -fsyntax-only test.cc
?- 在一個翻譯單元中的頂層聲明始終是translation unitdeclaration
- 聲明是一個“f”的函數(shù),則f的主體是一個符合語句類型的節(jié)點(CompoundStmt)减江,它的子節(jié)點則是聲明語句(DeclStmt)節(jié)點,和返回語句(ReturnStmt)節(jié)點捻爷。
- Clang的AST節(jié)點是基于層級關(guān)系組合在一起的辈灼。
自定義檢查器注冊
注冊接口介紹
1. 基于抽象語法樹匹配的缺陷檢測主要分為兩個部分:
- 一部分是匹配機(jī)制的實現(xiàn),由基于抽象語法樹匹配器的注冊組成也榄。
- 一部分是匹配對象的實現(xiàn)巡莹,主要包括聲明類Decl、語句類Stmt甜紫。
void registerMatchers(ast matchers::MatchFinder*Finder)override
void check(const ast matchers::MatchFinder::MatchResult &Result)override;
2.通過add_new_check.py腳本添加自定義check
此處為check創(chuàng)建到misc類別降宅,自定義為CcTestCheckCheck,用于測試
./add_new_check.py misc cc-test-check(會自動將cc-test-check生成對應(yīng)的基礎(chǔ)demo囚霸,主要修改CcTestCheckCheck.cpp實現(xiàn)功能)
使能自定義checker
- 編寫checker后重新編譯項目:?
cd <path of llvm>/build/
ninja開始編譯
sudo ninja install安裝到系統(tǒng)
- 安裝后查看編寫的 checker
clang-tidy --list-checks --checks=misc*
- 運用編寫的checker
clang-tidy --checks=-*,misc-cc-test-check test.cc --?
- Note:如果要dump內(nèi)容包含引用頭文件腰根,建議加上-nostdinc++
clang -Xclang -ast-dump -nostdinc++ -fsyntax-only CcTestCheckCheck.cpp