2022-10-20

规则检查器-环境介绍及抽象语法树初步认识

本文主要简单介绍,llvm和clang环境搭建,抽象语法树及checker的简单认识

llvm/clang背景

- llvm介绍

llvm是一个模块化和可重用的编译器和工具链技术的集合。

LLVM最初是在2000年由伊利诺伊大学香槟分校(UUIC)的学生Chris Lattner及其硕士顾问Vikram Adve创建的研究项目,并在2003年发布第一个正式版本,目的是提供一种基于SSA的现代编译策略,这种策略能够支持任何编程语言的静态和动态编译。

LLVM是当今最流行的开源编译器框架项目,你可以使用它编写自己的编译器。

LLVM的命名最早源自于底层虚拟机(Low Level Virtual Machine)的首字母缩写,由于这个项目的范围并不局限于创建一个虚拟机,这个缩写导致了广泛的疑惑。LLVM开始成长之后,成为众多编译工具及低端工具技术的统称,使得这个名字变得更不贴切,开发者因而决定放弃这个缩写的意涵,现今LLVM已单纯成为一个品牌,适用于LLVM下的所有项目

- Clang介绍

Clang:是一个C、C++、Objective-C和Objective-C++编程语言的编译器前端。它采用了底层虚拟机(LLVM)作为其后端。它的目标是提供一个GNU编译器套装(GCC)的替代品。作者是克里斯·拉特纳(Chris Lattner),在苹果公司的赞助支持下进行开发,而源代码授权是使用类BSD的伊利诺伊大学厄巴纳-香槟分校开源码许可。Clang主要由C++编写。

Clang项目包括Clang前端和Clang静态分析器等。这个软件项目在2005年由苹果电脑发起,是LLVM(Low Level Virtual Machine)编译器工具集的前端(front-end),目的是输出代码对应的抽象语法树(Abstract Syntax Tree, AST),并将代码编译成LLVM Bitcode。接着在后端(back-end)使用LLVM编译成平台相关的机器语言。

Clang本身性能优异,其生成的AST所耗用掉的内存仅仅是GCC的20%左右。2014年1月发行的FreeBSD10.0版将Clang/LLVM作为默认编译器。

- Clang-Tidy介绍

clang-tidy是一个源码分析工具,用于检查  C、 C++和 Objective-C 程序的bugs.

该工具是完全开源的,并且是Clang项目的一部分. 和Clang其他部分一样,该工具作为C++库的方式实现,可以方便的集成于其他工具和程序.

什么是LLVM IR

- LLVM IR 是一门低级语言,语法类似于汇编,是编译中程序的间表示

- 任何高级编程语言(如C++)都可以用LLVM IR表示

- 基于LLVM IR可以很方便地进行代码优化

参考链接:https://www.cnblogs.com/Tu9oh0st/p/16358531.html


LLVM/CLANG 关系介绍

Clang为前端llvm架构前端

1.源代码通过clang的词法分析生成tokens

2.通过clang的语法分析生成了AST抽象语法树

3.通过clang的语义分析生成中间表示IR

Clang-tidy

LLVM后端

1.负责优化IR代码

2.负责生成目标程序

LLVM/CLANG 环境准备


1.查看环境依赖,升级低版本检查工具 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

- 进入解压目录,配置成功之后显示: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工程:

- 创建文件夹并下载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(小内存ninja -j2)

sudo ninja install 安装到系统

5.LLVM安装完成状态验证

通过执行clang-tidy -list-checks -checks=*命令,我们可以查看当前可用的所有check。

而如果想要执行某个检查,那就执行 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 - (打印未优化的llvm代码)

clang file.c -S -emit-llvm -o - -O3

clang file.c -S -O3 -o - (输出本地机器码)

运行测试套件:

make check-clang



抽象语法树

抽象语法树(Abstract Syntax Tree,AST)

Clang的AST非常类似于编写的C++代码和C++标准。AST中每一个节点都是一个Decl或者Stmt类的一个实例。

1. 声明类Decl

Decl用于表示在一个声明或者定义,包括变量、typedef定义、函数和结构体等。它是一个基类,不同的声明表达式都继承自它。如VarDecl类、 FunctionDecl类。

2.语句类Stmt

- Stmt用于表示在源代码中的语句,包括简单语句和复杂语句,程序中的函数都是由语句组成的。

3.Stmt也是一个基类,不同的语句都继承自它。

- 在C语言中最简单的语句形式是表达式。

- 大多数C语言语句是这类形式的,其他简单语句是跳转语句包括return、continue、goto.

-  复杂语句由简答语句组成,可分为两类:跳转语句和循环语句,跳转语句包括if/else、switch,循环语句包括while、do-while和for循环结构。

查看抽象语法树

系统提供一个内置的ast-dump方法,可以把整段代码按照AST结构翻译成人类可以读懂的格式。这种格式基于遍历整段代码,然后按照代码结构对AST节点进行相应层次结构的组合。

Demo:test.cc

int f(int x) {

int result=(x/42); 

return result;

默认情况下,Clang 是许多工具的前端;-Xclang 用于将选项直接传递给 C++的前端。

-fsyntax-only 只进行语法检查,不进行编译。

查看一下上面代码对应生成的抽象语法树AST:

clang -Xclang -ast-dump -fsyntax-only test.cc

 - 在一个翻译单元中的顶层声明始终是translation unitdeclaration

- 声明是一个“f”的函数,则f的主体是一个符合语句类型的节点(CompoundStmt),它的子节点则是声明语句(DeclStmt)节点,和返回语句(ReturnStmt)节点。

- Clang的AST节点是基于层级关系组合在一起的。


自定义检查器注册

注册接口介绍

1. 基于抽象语法树匹配的缺陷检测主要分为两个部分:

- 一部分是匹配机制的实现,由基于抽象语法树匹配器的注册组成。

- 一部分是匹配对象的实现,主要包括声明类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创建到misc类别,自定义为CcTestCheckCheck,用于测试

./add_new_check.py misc cc-test-check(会自动将cc-test-check生成对应的基础demo,主要修改CcTestCheckCheck.cpp实现功能)

使能自定义checker

- 编写checker后重新编译项目: 

cd <path of llvm>/build/

ninja开始编译

sudo ninja install安装到系统

- 安装后查看编写的 checker

clang-tidy --list-checks --checks=misc*


- 运用编写的checker

clang-tidy --checks=-*,misc-cc-test-check test.cc -- 


- Note:如果要dump内容包含引用头文件,建议加上-nostdinc++

clang -Xclang -ast-dump -nostdinc++ -fsyntax-only CcTestCheckCheck.cpp

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容