Clang教程之实现源源变化
clang教程之实现源源变化
声明:本教程来自于Eli Bendersky's website
原文地址:http://eli.thegreenplace.net/2014/05/01/modern-source-to-source-transformation-with-clang-and-libtooling/
众所周知,LLVM是一个自由软件项目,它是一种编译器基础设施,以C++写成。其发端源于2000年伊利诺伊大学厄巴纳-香槟分校(UIUC)的维克拉姆·艾夫(Vikram Adve)与其第一个博士生克里斯·拉特纳(Chris Lattner)的研究,彼时他们想要为所有静态及动态语言创造出动态的编译技术。现在使用LLVM来作为中端(middle-end)优化和后端目标代码生成的人很多,开源中也有很多基于LLVM进行二次开发的工具,比如之前NVIDIA贡献的nvptx的code-generator和klee。而llvm的前端,在llvm3(具体版本忘记了)之前使用的是GCC,之后使用的是clang。clang这个前端提供了很多sema静态分析工具,可以说已经超出了一般的编译器前端的范畴。
clang的功能如此强大,但是却很少发现有人对这部分知识进行介绍。我这里选取了Eli Bendersky的博客进行翻译介绍,作者现在是Google TensorFlow组的工程师,中间添加了我自己的理解,如果有错误,望大家指出。
首先介绍一下效果,输入是这样的一段带if的代码
1 void foo(int* a, int *b) { 2 if (a[0] > 1) { 3 b[0] = 2; 4 } 5 }
经过自己做的工具后,完成以下两部分的功能:
1. 识别if的true-body和false-body,并添加相应的注释
2. 识别函数入口和函数出口,添加注释
介绍一下主要的实现思路:
1. 创建ClangTool,也就是使用libTooling的方式,解析输入的参数,将第1个参数作为源码文件进行读取
2. 将源码送到ASTConsumer中,进行解析
3. ASTConsumer中,重载HandleTopLevelDecl识别所有的函数声明
4. 调用MyASTVisitor这个类(继承至TheWriter)中的VisitStmt函数,对所有的语句进行遍历,调用VisitFunctionDecl函数,对函数声明进行处理
5. 在遍历中识别是否是IfStmt,然后对ture-body和false-body进行识别,并添加注释
6. 将修改完的送回TheRewriter,进行写回
现在粘一下源码LoopConvert.cpp
//------------------------------------------------------------------------------ // Tooling sample. Demonstrates: // // * How to write a simple source tool using libTooling. // * How to use RecursiveASTVisitor to find interesting AST nodes. // * How to use the Rewriter API to rewrite the source code. // // Eli Bendersky (eliben@gmail.com) // This code is in the public domain //------------------------------------------------------------------------------ #include <sstream> #include <string>#include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Frontend/ASTConsumers.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Rewrite/Core/Rewriter.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/raw_ostream.h"using namespace clang; using namespace clang::driver; using namespace clang::tooling;static llvm::cl::OptionCategory ToolingSampleCategory("Tooling Sample");// By implementing RecursiveASTVisitor, we can specify which AST nodes // we're interested in by overriding relevant methods. class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor> { public:MyASTVisitor(Rewriter &R) : TheRewriter(R) {}bool VisitStmt(Stmt *s) {// Only care about If statements.if (isa<IfStmt>(s)) {IfStmt *IfStatement = cast<IfStmt>(s);Stmt *Then = IfStatement->getThen();TheRewriter.InsertText(Then->getLocStart(), "// the 'if' part\n", true,true);Stmt *Else = IfStatement->getElse();if (Else)TheRewriter.InsertText(Else->getLocStart(), "// the 'else' part\n",true, true);}return true;}bool VisitFunctionDecl(FunctionDecl *f) {// Only function definitions (with bodies), not declarations.if (f->hasBody()) {Stmt *FuncBody = f->getBody();// Type name as stringQualType QT = f->getReturnType();std::string TypeStr = QT.getAsString();// Function nameDeclarationName DeclName = f->getNameInfo().getName();std::string FuncName = DeclName.getAsString();// Add comment before std::stringstream SSBefore;SSBefore << "// Begin function " << FuncName << " returning " << TypeStr<< "\n";SourceLocation ST = f->getSourceRange().getBegin();TheRewriter.InsertText(ST, SSBefore.str(), true, true);// And after std::stringstream SSAfter;SSAfter << "\n// End function " << FuncName;ST = FuncBody->getLocEnd().getLocWithOffset(1);TheRewriter.InsertText(ST, SSAfter.str(), true, true);}return true;}private:Rewriter &TheRewriter; };// Implementation of the ASTConsumer interface for reading an AST produced // by the Clang parser. class MyASTConsumer : public ASTConsumer { public:MyASTConsumer(Rewriter &R) : Visitor(R) {}// Override the method that gets called for each parsed top-level// declaration.bool HandleTopLevelDecl(DeclGroupRef DR) override {for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {// Traverse the declaration using our AST visitor.Visitor.TraverseDecl(*b);(*b)->dump();}return true;}private:MyASTVisitor Visitor; };// For each source file provided to the tool, a new FrontendAction is created. class MyFrontendAction : public ASTFrontendAction { public:MyFrontendAction() {}void EndSourceFileAction() override {SourceManager &SM = TheRewriter.getSourceMgr();llvm::errs() << "** EndSourceFileAction for: "<< SM.getFileEntryForID(SM.getMainFileID())->getName() << "\n";// Now emit the rewritten buffer. TheRewriter.getEditBuffer(SM.getMainFileID()).write(llvm::outs());}std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,StringRef file) override {llvm::errs() << "** Creating AST consumer for: " << file << "\n";TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());return llvm::make_unique<MyASTConsumer>(TheRewriter);}private:Rewriter TheRewriter; };int main(int argc, const char **argv) {CommonOptionsParser op(argc, argv, ToolingSampleCategory);ClangTool Tool(op.getCompilations(), op.getSourcePathList());// ClangTool::run accepts a FrontendActionFactory, which is then used to// create new objects implementing the FrontendAction interface. Here we use// the helper newFrontendActionFactory to create a default factory that will// return a new MyFrontendAction object every time.// To further customize this, we could create our own factory class.return Tool.run(newFrontendActionFactory<MyFrontendAction>().get()); }
View Code
源码介绍到这里,现在说一下编译,这种项目编译起来比较麻烦……
我选择的环境是Ubuntu16.04+LLVM4.0+Clang4.0 的环境,我已经发过一个使用binary进行安装llvm教程,当然,那个教程不适用于这里,我改天会再发一个教程,如何使用源码进行编译
这里假设大家和我使用的是相同的环境,因为LLVM4.0到5.0经历了比较大的改动,4.0的代码在5.0上正常编译时非常正常的。
1. 在源码的clang/tools文件夹下(大概是~/llvm-src/llvm-4.0.0.src/tools/clang/tools/下),新建文件夹extra
在文件夹内新建CMakeLists.txt,写入
add_subdirectory(loop-convert)
这里是告诉cmake工具,下边还有一级目录,叫做loop-convert
2. 再在extra中新建loop-convert文件夹
3. 在loop-convert中新建CMakeLists.txt,写入
set(LLVM_LINK_COMPONENTS support)add_clang_executable(loop-convertLoopConvert.cpp) target_link_libraries(loop-convertclangToolingclangBasicclangASTMatchers)
大概意思是添加LLVM的支持,使用 LoopConvert.cpp来编译出一个叫loop-convert的程序,然后将loop-convert和 clangTooling clangBasic clangASTMatchers链接在一起,这几个都是clang的库
现在loop-convert文件夹中应该有CMakeLists.txt LoopConvert.cpp两个文件
现在的目录结构如下
clang/tools ->extra -> loop-convert ->CMakeLists.txt
... CMakeLists.txt LoopConvert.cpp
4. 现在,重新使用cmake生成Makefile文件,make后就能得到loop-convert了
loop-convert在 where_you_build/bin/下边(我是~/llvm-src/build/bin)
现在进行测试
首先编辑一个带if的程序(不推荐包含头文件,因为AST打印的时候,会把头文件也打印出来,不方便查看)
我使用的test.cpp如下
void foo(int* a, int *b) {if (a[0] > 1) {b[0] = 2;}}
使用./loop-convert test.cpp -- 命令进行测试, --表示没有特别的参数
转载于:https://www.cnblogs.com/jourluohua/p/9526663.html
Clang教程之实现源源变化相关推荐
- centos安装llvm_Linux CentOS上编译并安装Clang教程
如何在Linux CentOS上编译并安装Clang?下面小编为大家具体的介绍一下,解决你在安装Clang遇到的一系列问题. 一.Minimal版CentOS安装Clang前的环境准备 1,安装gcc ...
- 安装LLVM+Clang教程
目录 前言 一.LLVM简介 二.LLVM+Clang的安装 前言 最近可能要学习编译器相关的知识,因此总结一下LLVM的安装方法,以防忘记如何安装. 接下来就是正式的安装过程了... ------- ...
- 敬伟PS教程:新版PS变化篇D
D01 起始页 文件/最近打开的文件/清除最近的文件列表. D02 新建文档 ctrl+K,常规,可勾选使用旧版"新建文档"界面. D03 多画板 新建文档,勾选画板. 选中当前画 ...
- 基于Eclipse的TI集成开发环境IDE-CCSv5使用教程
TI嵌入式处理器的集成开发环境(IDE)包括调试器,编译器,编辑器,DSP/BIOS操作系统等等,现在最新的CCSv5 IDE基于Eclipse开源软件框架(v4+)并融合了TI设备的支持与功能,适用 ...
- duilib 子窗口位置_duilib入门简明教程 -- 界面布局(9)
上一个教程实现的标题栏代码中,并没有看到处理自适应窗口大小的代码,但是窗口大小变化后,按钮的位置会跟着变化,这是因为我们将按钮放到了HorizontalLayout.VerticalLayout,这样 ...
- duilib教程之duilib入门简明教程9.界面布局
上一个教程实现的标题栏代码中,并没有看到处理自适应窗口大小的代码,但是窗口大小变化后,按钮的位置会跟着变化,这是因为我们将按钮放到了HorizontalLayout.VerticalLayout,这样 ...
- duilib教程之duilib入门简明教程 -- 界面布局(9)
上一个教程实现的标题栏代码中,并没有看到处理自适应窗口大小的代码,但是窗口大小变化后,按钮的位置会跟着变化,这是因为我们将按钮放到了HorizontalLayout.VerticalLayout,这样 ...
- 2013 duilib入门简明教程 -- 界面布局(9)
上一个教程实现的标题栏代码中,并没有看到处理自适应窗口大小的代码,但是窗口大小变化后,按钮的位置会跟着变化,这是因为我们将按钮放到了HorizontalLayout.VerticalLayout,这样 ...
- WWDC 2013 Session笔记 - Xcode5和ObjC新特性
这是我的WWDC2013系列笔记中的一篇,完整的笔记列表请参看这篇总览.本文仅作为个人记录使用,也欢迎在许可协议范围内转载或使用,但是还烦请保留原文链接,谢谢您的理解合作.如果您觉得本站对您能有帮助, ...
最新文章
- 51NOD 1773:A国的贸易——题解
- Windows和Ubuntu系统之间文件相互复制粘贴
- angularjs解决方案之 递归模板
- js操作改变原数组的解决方法
- ASMCMD 命令详解
- Dynamips和Vmware完成CCVP试验(2)
- http的“无连接”指的是_http协议无状态中的 quot;状态quot; 到底指的是什么?...
- c++ 访问控制与封装
- 转载自《读者》--您也吻我一下好吗
- 北京国企软件开发公司有哪些?哪家比较好呢
- CMOS和TTL电路区别
- Excel中,编制卡方分布临界值表
- elasticsearch 使用
- 宇宙生命进化的八大密度
- cs ss ds es
- JavaMail发送邮件手机客户端图片无法显示
- 计算机数据表示和运算
- 【AI TOP 10】扎克伯格要整顿Facebook;LeCun飙脏话批机器人Sophia;北京站加装人脸识别检票机...
- SaaS-初识SaaS
- 个人近期日常工作计划