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的意思是链接库文件
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_PATHS2.4修改c++编译flag
2.5导入c++库
libz2.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");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_CFLAGS3.部分工程可能要添加c++编译选项,增加c++编译设置
-I/applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 -mios-version-min=8.0编译demo工程即可看到打印的vc.
新闻热点
疑难解答