使用 LibTooling构建工具
创建 ClangTool
1.在 clang-llvm/clang-tools-extra下新建文件夹loop-convert
cd ~/clang-llvm
mkdir clang-tools-extra/loop-convert
2.在clang-tools-extra下的CMakeLists.txt中添加
add_subdirectory(loop-convert)
这是告诉编译器还有下级目录loop-convert
3.在loop-convert中新建CMakeLists.txt , 内容为:
set(LLVM_LINK_COMPONENTS support)
add_clang_executable(loop-convert
LoopConvert.cpp
)
target_link_libraries(loop-convert
PRIVATE
clangAST
clangASTMatchers
clangBasic
clangFrontend
clangSerialization
clangTooling
)
4.在loop-convert中新建LoopConvert.cpp , 内容为:
#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");
class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor> {
public:
MyASTVisitor(Rewriter &R) : TheRewriter(R) {}
bool VisitStmt(Stmt *s) {
if (isa<IfStmt>(s)) {
IfStmt *IfStatement = cast<IfStmt>(s);
Stmt *Then = IfStatement->getThen();
TheRewriter.InsertText(Then->getBeginLoc(), "// the 'if' part\n", true,
true);
Stmt *Else = IfStatement->getElse();
if (Else)
TheRewriter.InsertText(Else->getBeginLoc(), "// the 'else' part\n",
true, true);
}
return true;
}
private:
Rewriter &TheRewriter;
};
class MyASTConsumer : public ASTConsumer {
public:
MyASTConsumer(Rewriter &R) : Visitor(R) {}
bool HandleTopLevelDecl(DeclGroupRef DR) override {
for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
Visitor.TraverseDecl(*b);
(*b)->dump();
}
return true;
}
private:
MyASTVisitor Visitor;
};
class MyFrontendAction : public ASTFrontendAction {
public:
MyFrontendAction() {}
void EndSourceFileAction() override {
SourceManager &SM = TheRewriter.getSourceMgr();
llvm::errs() << "** EndSourceFileAction for: "
<< SM.getFileEntryForID(SM.getMainFileID())->getName() << "\n";
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 std::make_unique<MyASTConsumer>(TheRewriter);
}
private:
Rewriter TheRewriter;
};
int main(int argc, const char **argv) {
llvm::Expected<CommonOptionsParser> op=CommonOptionsParser::create(argc, argv, ToolingSampleCategory);
ClangTool Tool(op.get().getCompilations(), op.get().getSourcePathList());
return Tool.run(newFrontendActionFactory<MyFrontendAction>().get());
}
5.用ninja 来编译新工具 build目录
cd ~/clang-llvm/build
ninja
编译成功:
6.测试一下
在clang-llvm/build下新建 test.cpp ,内容为:
int foo(int a, int b, int *c) {
int ret = 0;
if (a > b) {
ret = a;
} else {
ret = b;
}
for (int temp = 0; temp < 100; ++temp) {
*c = (*c + temp);
}
return ret;
}
int main() {
int a = 1, b = 2;
int c = 0;
int d = foo(a, b, &c);
return 0;
}
运行工具
bin/loop-convert test.cpp --