乐趣区

关于clang:DeepRoute-Lab-Clang-新手教程来啦

长话短说!

这篇老手教程会让你弄清楚什么是 clang、clang AST、clang plugins 和 clang tools 等等,让你大略晓得 clang 能够解决什么问题,而且小白也是能够用 clang libraries 来开发工具的 :)

01 Clang

是什么 Clang 是一个以 LLVM 为后端的编译前端。编译前端次要负责 parse 源码、查看谬误,并生成形象语法树 Abstract Syntax Tree (AST)。相较于其余编译器生成的 AST,clang 生成的 AST 更加靠近 C ++ 源码,所以咱们能够更加精确地在源码中进行查找和定位。并且,clang 还提供了丰盛的库和 API,让咱们能在 AST 上很不便地做遍历,搜寻和批改等操作。咱们在 vscode 上用的代码主动补全工具 clangd(或 vim 的 YouCompleteMe)就是用 clang 来实现的。

(点击查看大图)Ref:https://jonasdevlieghere.com/…

02 什么时候会用到 Clang

‣ 须要基于编译器的 AST 对源码做准确的编辑 
‣ 主动纠正不合乎 coding style 的源码
‣ 须要引入自定义的编译谬误和正告   
‣ 禁止用裸指针创立共享指针   
‣ 申明了变量然而没有应用
‣ 基于 C /C++  源码的代码生成(code generation)   
‣ 主动生成数据结构的序列化办法,反射办法

03Clang AST 是什么

‣ Clang AST 的节点是由几种没有独特基类的类来组成(建模)的
Clang’s AST nodes are modeled on a class hierarchy that does not have a common ancestor.  —《Introduction to the Clang AST》(https://clang.llvm.org/docs/I…)   
‣ 其中比拟罕用的四种 class 是 Type,Decl ,  DeclContext ,  Stmt 
‣ 每种节点都有专门的遍历函数来获取子节点
‣ ASTContext 里能够获取 AST 的额定信息,比方源码的地址
‣ 例子:上面是一段简略的 c ++ 源码,咱们能够看一下这段源码对应的 AST

(点击查看大图)

运行后果:先疏忽掉下面的(一堆看不懂而且很吓人的货色 TranslationUnitDecl),咱们能够看到咱们定义的两个函数在 AST 的节点类型是 FunctionDecl  (也就是 Decl 的子类)。另外,CompoundStmt  是函数体的节点类型。其余的节点类型如果咱们对照着源码来看的话,其实还是很难看懂的,比方 VarDecl 是变量申明,IntegerLiteral 是整数文字。

(点击查看大图)Ref:https://clang.llvm.org/docs/I…

04 Clang APIs

‣ Clang 提供 C 和 C ++ API   
‣ C API (libClang) 稳固然而不残缺   
‣ C++ API(LibTooling)残缺然而不稳固‣ LibTooling 次要用于开发 standalone 工具,并且 plugins 只能应用 LibTooling 开发上面的教程都是对于 C ++ API —— LibTooling 的 Ref:https://clang.llvm.org/docs/T…

什么是 Clang plugins 和 Clang tools

用 LibTooling 能够开发两种模式的 clang 工具:plugins (clang 插件) 或 standalone tools (不依赖 clang 运行的独立工具)。
Clang plugins 会在编译时对 AST 进行一些额定的查看或操作。plugin 是动静库(.so),在运行时由编译器(也就是 clang)加载,所以能够很容易地集成到编译环境中。
Clang tools 是独立的 (standalone) 可执行程序,比方 clang-check,clang-format,clang-tidy 这些 llvm project 官网提供的 standalone tools。
有时候两种模式的工具都能解决问题。例如上面是一个叫 LAComment 的工具,提供了两种工具模式:

(点击查看大图)

这时候咱们能够思考上面的问题,来决定是开发 plugin 还 standlone 工具:
‣ 能不能抉择用哪个编译器?clang / gcc?
‣ 需不需要 make 或者 break build
‣ Clang 6.0 写的 plugin Clang 7.0 不肯定能用(API 不稳固!)
‣ 部署环境(如 CI pipeline)应用哪种工具用户接入老本更低?

RecursiveASTVisitor v.s. ASTMatcher

下面提到的 LibTooling 库有两种 API framework: RecursiveASTVisitor 和 ASTMatcher:‣ RecursiveASTVisitor 为大多数的 AST 节点提供拜访节点的 hook  bool VisitNodeType(NodeType *) ;
‣ ASTMatcher 是一套用来匹配和遍历 AST 的 DSL;‣ 两种 framework 的抉择并不互斥,必要时能够一起应用来解决比较复杂的问题!例子:https://github.com/banach-spa…
‣ 倡议优先思考用 ASTMatcher,因为能够用 clang-query 来验证 DSL 是否正确。

感兴趣的同学能够尝试运行上面的命令,用 clang-query 查看 test.cc 里的函数节点。

(点击查看大图)
Ref:https://clang.llvm.org/docs/L…

05 如何写一个 Clang 工具

1. 想分明目标。这应该是最值得花工夫,也有可能是最难的一步。因为当咱们分析分明目标之后,咱们可能会发现咱们要做的事件其实能够用比 clang 更简略的工具来实现。而且,如果咱们肯定要用 clang,只有当目标足够清晰,咱们能力晓得要在 AST 上查找哪种类型的节点,并对其进行操作;

  1. 写一些最小的测试用例源码并用 clang -Xclang -ast-dump 来察看生成的 AST;
  2. 找到想要匹配的 AST 节点;
  3. 应用 clang-query 来在测试用例上测验 ASTMatcher;
  4. 将 ASTMatcher 的 DSL 集成到 clang LibTooling 的脚手架里。

06 怎么创立 Clang 工具我的项目

Llvm 的官网教程是用 in tree 的办法来创立工具的(即在 clang-llvm 的目录内退出工具代码)。In tree 尽管 setup 会比较简单,然而不便于做代码治理。https://clang.llvm.org/docs/L…

所以如果我想要有更好的版本治理,甚至是接入 CI/CD,就应该用 Out of tree 的形式来创立工具(即在 clang-llvm 目录外创立工具代码)。Out of tree 创立形式上面的开源教程十分具体,感兴趣的同学能够参考一下:
https://github.com/banach-spa…

退出移动版