首页 > 学院 > 开发设计 > 正文

Clang插件学习 xcode开发Clang插件入门

2019-11-07 22:54:54
字体:
来源:转载
供稿:网友

一.背景

Clang是llvm的编译器前端,非常适合进行源码分析.目前开源的oclint就是基于clang进行的代码静态检查.工作中遇到了一些问题需要进行代码分析,所以学习了插件的开发流程.既然开发插件就要有合适的IDE,Mac上最合适的无疑是xcode了.本文将讲述如何使用xcode开发clang插件,在此之前请先了解clang的相关知识. 滴滴王康的clang插件入门.本文将假设您已按文中的描述做了xcodehook

二.开发流程

1.创建工程 * 创建一个空的xcode workspace,之所以使用workspace是为了代码组织方便. * 点击左下角的new PRoject增加一个ios的demo工程,这个工程用于插件的测试 * 在增加一个macOS library工程,生成的未dylib结尾的动态包.这个工程用于实际的插件开发

2.工程设置

2.1修改生成插件的位置

这个位置就是后面demo加载插件的位置

2.2修改编译选项

因为修改xcode other linker flags,使其能够找到llvm等相应的库.-l的意思是链接库文件

OTHER_LDFLAGS = -dynamiclib -Wl,-headerpad_max_install_names -lclang -lclangFrontend -lclangAST -lclangAnalysis -lclangBasic -lclangCodeGen -lclangDriver -lclangFrontendTool -lclangLex -lclangParse -lclangSema -lclangEdit -lclangSerialization -lclangStaticAnalyzerCheckers -lclangStaticAnalyzerCore -lclangStaticAnalyzerFrontend -lLLVMX86CodeGen -lLLVMX86AsmParser -lLLVMX86Disassembler -lLLVMExecutionEngine -lLLVMAsmPrinter -lLLVMSelectionDAG -lLLVMX86AsmPrinter -lLLVMX86Info -lLLVMMCParser -lLLVMCodeGen -lLLVMX86Utils -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMAnalysis -lLLVMTarget -lLLVMCore -lLLVMMC -lLLVMSupport -lLLVMBitReader -lLLVMOption -lLLVMProfileData -lpthread -lcurses//:configuration = ReleaseOTHER_LDFLAGS = -dynamiclib -Wl,-headerpad_max_install_names -lclang -lclangFrontend -lclangAST -lclangAnalysis -lclangBasic -lclangCodeGen -lclangDriver -lclangFrontendTool -lclangLex -lclangParse -lclangSema -lclangEdit -lclangSerialization -lclangStaticAnalyzerCheckers -lclangStaticAnalyzerCore -lclangStaticAnalyzerFrontend -lLLVMX86CodeGen -lLLVMX86AsmParser -lLLVMX86Disassembler -lLLVMExecutionEngine -lLLVMAsmPrinter -lLLVMSelectionDAG -lLLVMX86AsmPrinter -lLLVMX86Info -lLLVMMCParser -lLLVMCodeGen -lLLVMX86Utils -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMAnalysis -lLLVMTarget -lLLVMCore -lLLVMMC -lLLVMSupport -lLLVMBitReader -lLLVMOption -lLLVMProfileData -lpthread -lcurses//:completeSettings = someOTHER_LDFLAGS可以直接将上面的文字粘贴进去

2.3添加头llvm文件搜索路径

对应下面的配置,可直接粘贴

//:configuration = DebugHEADER_SEARCH_PATHS = /opt/llvm/llvm/include /opt/llvm/llvm/tools/clang/include /opt/llvm/llvm_build/tools/clang/include /opt/llvm/llvm_build/include//:configuration = ReleaseHEADER_SEARCH_PATHS = /opt/llvm/llvm/include /opt/llvm/llvm/tools/clang/include /opt/llvm/llvm_build/tools/clang/include /opt/llvm/llvm_build/include//:completeSettings = someHEADER_SEARCH_PATHS添加library搜索路径//:configuration = DebugLIBRARY_SEARCH_PATHS = /opt/llvm/llvm_build/lib//:configuration = ReleaseLIBRARY_SEARCH_PATHS = /opt/llvm/llvm_build/lib//:completeSettings = someLIBRARY_SEARCH_PATHS

2.4修改c++编译flag 这里写图片描述

//:configuration = DebugOTHER_CPLUSPLUSFLAGS = -fPIC -fno-common -Woverloaded-virtual -Wcast-qual -fno-strict-aliasing -pedantic -Wno-long-long -Wall -Wno-unused-parameter -Wwrite-strings -fno-rtti -fPIC//:configuration = ReleaseOTHER_CPLUSPLUSFLAGS = -fPIC -fno-common -Woverloaded-virtual -Wcast-qual -fno-strict-aliasing -pedantic -Wno-long-long -Wall -Wno-unused-parameter -Wwrite-strings -fno-rtti -fPIC//:completeSettings = someOTHER_CPLUSPLUSFLAGS

2.5导入c++库

libz

2.6添加示例代码 以下头文件和代码可以打印出所有工程所有的vc

// ONEExtractVCPlugin.hpp// ONEExtractVCPlugin////#ifndef ONEExtractVCPlugin_hpp#define ONEExtractVCPlugin_hpp#include <stdio.h>#include <stdio.h>#include <iostream>#include <sstream>#include <typeinfo>#include "clang/Frontend/FrontendPluginRegistry.h"#include "clang/AST/AST.h"#include "clang/AST/ASTConsumer.h"#include "clang/Frontend/CompilerInstance.h"#include "clang/AST/RecursiveASTVisitor.h"#include "ONEFileUtils.hpp"//#pragma GCC visibility push(default)using namespace clang;using namespace std;using namespace llvm;namespace one{ class ONEASTVisitor : public RecursiveASTVisitor<ONEASTVisitor> { private: ASTContext *context; public: void setContext(ASTContext &context); bool VisitDecl(Decl *decl); bool VisitStmt(Stmt *s); }; class ONEASTConsumer : public ASTConsumer { private: ONEASTVisitor visitor; void HandleTranslationUnit(ASTContext &context); }; class ONEASTAction : public PluginASTAction { public: // this gets called by Clang when it invokes our Plugin unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,llvm::StringRef InFile); // implement this function if you want to parse custom cmd-line args bool ParseArgs(const CompilerInstance &CI, const std::vector<std::string>& args); };}//#pragma GCC visibility pop#endif /* ONEExtractVCPlugin_hpp */#include "ONEExtractVCPlugin.hpp"#include <iostream>#include <streambuf>#include <string>#include<algorithm>#include <functional>#include <string>#include <fstream>#include <vector>namespace one { //设置上下文 void myASTVisitor::setContext(ASTContext &context) { this->context = &context; } //VisitDecl(Decl/*decl)和VisitStmt(Stmt/*stmt)的重载函数里,相关的decl有ObjCMethodDecl(方法声明),stmt有ObjCMessageExpr(消息表达式) bool myASTVisitor::VisitDecl(Decl *decl) { if(isa<ObjCInterfaceDecl>(decl)) { ObjCInterfaceDecl *interDecl = (ObjCInterfaceDecl*)decl; if (interDecl->getSuperClass()) { cout<<"[SLL]Class intergation"<<interDecl->getNameAsString(); cout<<" superClass:"<<interDecl->getSuperClass()->getNameAsString() <<endl; string curFilename = context->getSourceManager().getFilename(interDecl->getSourceRange().getBegin()).str(); //文件路径 cout<<curFilename<<endl; myFileUtils::appendContentToFile(interDecl->getNameAsString(), interDecl->getSuperClass()->getNameAsString(),curFilename); } } return true; } bool myASTVisitor::VisitStmt(Stmt *s) { return true; } //ast解析完成后调用 void myASTConsumer::HandleTranslationUnit(ASTContext &context){ visitor.setContext(context); visitor.TraverseDecl(context.getTranslationUnitDecl());// cout<<"[SLL]解析完成"<<endl; } //处理命令行参数 bool myASTAction::ParseArgs(const CompilerInstance &CI, const vector<string> &args) { return true; } //生成处理ast的类 unique_ptr<ASTConsumer> myASTAction::CreateASTConsumer(CompilerInstance &Compiler,llvm::StringRef InFile) { return unique_ptr<myASTConsumer>(new myASTConsumer); }}//注册插件static clang::FrontendPluginRegistry::Add<my::myASTAction>X("myExtractVCPlugin", "descripton:extract viewController class");

三.demo工程使用

1.compiler for c/c++选中llvm trunck

2.otherflag添加插件编译选项 libMyPlugin2.dylib是上面生成的插件的路径,MyPlugin2是插件的名称

OTHER_CFLAGS = -Xclang -load -Xclang /opt/llvm/clangplugin/libMyPlugin2.dylib -Xclang -add-plugin -Xclang MyPlugin2//:configuration = ReleaseOTHER_CFLAGS = -Xclang -load -Xclang /opt/llvm/clangplugin/libMyPlugin2.dylib -Xclang -add-plugin -Xclang MyPlugin2//:completeSettings = someOTHER_CFLAGS

3.部分工程可能要添加c++编译选项,增加c++编译设置

-I/applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 -mios-version-min=8.0

编译demo工程即可看到打印的vc.


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表