手把手教你开发 clang 插件

2023-10-28

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

1、编译插件

1.1、代码下载

a.查看xcode对应的clang版本 https://trac.macports.org/wiki/XcodeVersionInfo

b.官网查询对应发布版本 https://opensource.apple.com/source/clang/
这里写图片描述

c.根据官网用的代码查找github查找对应分支并下载代码
https://github.com/llvm-mirror/llvm
这里写图片描述

1.2、添加插件代码

a.创建插件所在文件夹(示例代码见 demo)
这里写图片描述

b.编写cmakelists文件

这里写图片描述
c.添加插件代码
这里写图片描述

1.3、编译代码

有两种编译方式,一种使用cmake直接编译,一种使用IDE。这里介绍下使用xcode的编译方式。

a. 生成 xcodeproj 文件

cd /opt
sudo mkdir llvm
sudo chown `whoami` llvm
cd llvm
export LLVM_HOME=`pwd`

git clone -b release_39 git@github.com:llvm-mirror/llvm.git llvm
git clone -b release_39 git@github.com:llvm-mirror/clang.git llvm/tools/clang
git clone -b release_39 git@github.com:llvm-mirror/clang-tools-extra.git llvm/tools/clang/tools/extra
git clone -b release_39 git@github.com:llvm-mirror/compiler-rt.git llvm/projects/compiler-rt

mkdir llvm_build
cd llvm_build
cmake -G Xcode ../llvm -DCMAKE_BUILD_TYPE:STRING=MinSizeRel

备注:官网教程 http://llvm.org/docs/CMake.html

这里写图片描述

b. 选择自动生成 schmema
这里写图片描述
c. 编译 clang,myplugin 和 libclang

这里写图片描述

d. 最终效果

这里写图片描述

2、使用插件

2.1、hook xcode

a. 执行以下两个命令

sudo mv HackedClang.xcplugin `xcode-select -print-path`/../PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins
sudo mv HackedBuildSystem.xcspec `xcode-select -print-path`/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Specifications

如果自定义 clang 路径和展示的名称,则修改以下文件

这里写图片描述
b. Xcode 配置
这里写图片描述
c. 添加 other_flags

这里写图片描述

-Xclang -load -Xclang /opt/llvm/clangplugin/libONEExtractVCPlugin.dylib -Xclang -add-plugin -Xclang ONEExtractVCPlugin -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1

/opt/llvm/clangplugin/libMyPlugin.dylib:是动态库地址
MyPlugin:插件名称
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1:使用的c++库

2.2、命令行调用 clang 插件

直接替换红框的 clang 为自己编译的 clang 即可
这里写图片描述

2.2 常用 API 介绍

a. 注册插件

static clang::FrontendPluginRegistry::Add<my::MyASTAction>
X("MyPluginName", "MyPlugin description");

第一个参数是插件名称,第二个是插件描述

b. 传递参数到插件

bool MyASTAction::ParseArgs(const CompilerInstance &CI, const std::vector<std::string>& args) {
        size_t cnt = args.size();
        for(int i = 0;i < cnt;i++){
            cout<<"myparam:"<<args.at(i)<<endl;
        }
       return true;
}

编译的时候添加plugin对应的param就可以通过该方法将param获取到.例如在other_cflag除了上期配置外添加中添加-Xclang -plugin-arg-MyPlugin -Xclang $SRCROOT/..,就可以将srcroot的路径打印出来

  • ast 解析完成调用
    void MyASTConsumer::HandleTranslationUnit(ASTContext &context){}
  • 获取父类名称:interfDecl->getSuperClass()->>getNameAsString()
  • 是否是实现类:if(isa<ObjCImplDecl>(decl)){}

  • 是否是category: if(isa<ObjCCategoryDecl>(decl)){}

  • 是否是协议: if(isa<ObjCProtocolDecl>(decl)){}
  • 是否是 property:if(isa<ObjCPropertyDecl>(decl)){}

是否是实例变量:objcIsInstanceMethod = propertyDecl->isInstanceProperty();
property类型(修饰符例如NSString):propertyDecl->getType().getAsString();
getter方法名称:propertyDecl->getGetterName().getAsString()
setter方法名称:propertyDecl->getSetterName().getAsString()
是否只读:propertyDecl->isReadOnly()
是否是类property:propertyDecl->isClassProperty()
是否是原子性:propertyDecl->isAtomic()

b. 是否是成员变量 :if (isa<ObjCIvarDecl>(decl)) {}
成员变量名称:ivarDecl->getNameAsString()

c. 是否是参数 : if (isa<ObjCTypeParamDecl>(decl)){}

@interface NSDictionary<Key : id<NSCopying>, Value>@end
key,value就是paramter
  • 是否是方法 : if(isa<ObjCMethodDecl>(decl)){}
是否是实例方法: methodDecl->isInstanceMethod()
selector名称: methodDecl->getSelector().getAsString()
返回值类型:methodDecl->getReturnType().getAsString()
参数:
for(ArrayRef<ParmVarDecl *>::iterator it = methodDecl->param_begin();it!=methodDecl->param_end();it++){
    cout<<"参数:"<<((*it)->getNameAsString())<<"参数类型:"<<(*it)->getType().getAsString()<<endl;
}

d. 是否是变量方法枚举等 if(isa<DeclRefExpr>(s)){}

声明的名称:callExpr->getDecl()->->getNameAsString()
是否是变量:isa<VarDecl>(decl)
是否是函数:isa<FunctionDecl>(decl)
是否是枚举:isa<EnumConstantDecl>(decl)

e. 向object-c对象发送消息 isa<ObjCMessageExpr>(s)

调用者:objcExpr->getSelector().getAsString() 
函数本身名称: objcExpr->getSelector().getAsString() 
接受消息类型:objcExpr->getReceiverType().getAsString()

3、获取编译命令

3.1、获取编译命令

xcodebuild clean
xcodebuild -workspace OneTravel.xcworkspace -scheme OneTravel CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -dry-run -configuration Release| ruby onepretty

解释:
CODE_SIGN_IDENTITY=”” CODE_SIGNING_REQUIRED=NO:表示不需要证书编译
-dry-run:只获取编译命令,执行

onepretty: 从xcpretty中抽取的工具,移除了无用代码,添加了复制头文件软连接功能

3.2、修改编译命令
针对 libtool 的命令适配,其他参数见链接

a.移除-gmodules: 这个命令会打包编译信息,自定义的libtool不支持,而且也没有用。

b.移除 -c和-o及其参数: 仅解析ast,这是无用参数

c.添加引用c++库(如果要解析一些.cpp和.mm文件): -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1

d.替换工具: 将 clang 替换成自己的工具,如onec -- -x --后面对应对应,双横线参见

示例如下(精简版):

/Users/xx/Documents/plugin/bin/bin/onec /Users/xx/Documents/conn_connection.cpp  -outdir=~/Desktop -- -x c++ -arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1

4、libtool 工具开发

4.1 添加代码和 CMake文件

这里写图片描述

E88D7FA1-A055-4AE1-A218-14100B54ABD1

进入 llvm_build 文件夹清空原来的文件,重新编译代码 cmake -G Xcode ../llvm -DCMAKE_BUILD_TYPE:STRING=MinSizeRel

4.2 一些模块的简介

一些clang组件的作用:
libclangLex:预处理、词法分析、宏处理、词元(token)、语法构造;
libclangAST:该库是用来建立、管理、遍历AST
libclangParse:语法分析,用来解析词法分析后的结果
libclangSema:语义分析
libclangCodeGen:目标相关的代码分析
libclangAnaylysis:用于进行静态分析用的
libclangRewrite:代码重新写入(不知道该怎么解释,稍后理解了再做解释)
libclangBasic:clang的基础杂项库

http://clang.llvm.org/docs/InternalsManual.html

5、 插件和 libtool 工具简单对比

插件 libtool
解析速度 稍快
包大小
获取编译命令 直接使用 xcodebuild 生成的命令
与 xcode 集成 可以

由于 libtool 和clang 插件的大部分api可以通用,因此实际工作用中选择哪个都可以,如果出现问题,两者的代码可以低成本的相互迁移。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

手把手教你开发 clang 插件 的相关文章

随机推荐

  • 网络基础-应用层:E-mail应用:SMTP协议,POP协议,IMAP协议

    Email应用的构成 邮件客户端 邮件服务器 SMTP协议 只支持文本 邮件服务器 邮箱 存储发给该用户的Email 消息队列 存储等待发送的Email SMTP协议 邮件服务器之间传递消息所使用的协议 客户端 发送消息的服务器 服务器 接
  • js实用方法记录-js动态加载css、js脚本文件

    js实用方法记录 动态加载css js 附送一个加载iframe h5打开app代码 1 动态加载js文件到head标签并执行回调 方法调用 dynamicLoadJs http www yimo link static js main m
  • 双向链表实现简单的增删查改

    前言 上次分享了单向链表的增删查改 这次要介绍双向链表的增删查改 其实双向链表也有多种 这次主要介绍结构最复杂但是实现起功能反而最简单的带头双向循环链表 希望我的分享对各位有些许帮助 学习这篇文章的内容最好有这篇文章的基础 目录 一 双向链
  • VBA常用语法(一)

    VBA语句 一 VBA语句 1 宏程序语句 运行后可 以完成一个功能 给单元格a1赋值 Sub test 开始语句 Range a1 10 程序主体 End Sub 结束语句 2 函数程序语句 运行后可以返回一个值 Function shc
  • 阿里云数据库 MongoDB 版Python 连接示例

    安装pymongo import uuid from pymongo import MongoClient 两地址 CONN ADDR1 demotest 1 mongodb tbc3 newtest rdstest aliyun inc
  • 即将开班「中国图象图形学学会」前沿讲习班第2期——智能驾驶与机器视觉

    CSIG图像图形学科前沿讲习班第2期 主题 智能驾驶与机器视觉 2017年7月15日 17日 清华大学 智能驾驶无疑开启了交通运输行业的新时代 随着传感器和人工智能技术的逐渐成熟 智能驾驶已经从 概念化 进入 落地实用化 的关键窗口期 越来
  • 高精度地图定位在高速公路自动驾驶系统中的应用

    摘要 自动驾驶已经成为全球汽车产业的战略发展方向 其中L3 级高速公路自动驾驶是最有可能率先落地的自动驾驶系统 高精度地图和定位系统是自动驾驶系统的关键一部分 近年来发展迅速 已经达到可量产状态 文章首先分析了自动驾驶和高精度地图定位的发展
  • 运动目标检测代码(帧差、高斯混合、vibe代码实现)

    主要介绍四种运动目标检测的算法代码 每段代码博主实测可运行 当前主流的混合高斯背景模型 VIBE算法代码转载自他处 另外GMG算法 KNN算法在朱伟的书中也有讲 opencv3 0中 有专门的背景模型类BackgroundSubtracto
  • Java学习笔记29——字节流2

    字节流读数据 字节流读数据 一次读一个字节的数据 一次读一个字节数组的数据 字节流复制图片 字节流读数据 一次读一个字节的数据 FileInputStream 从文件系统中的文件获取输入字节 public class FileInputSt
  • 数据结构-第1章 概述

    第1章 概述 第2章 线性表 第3章 栈和队列 第4章 串 矩阵和广义表 第5章 树和二叉树 第6章 图 第7章 查找 第8章 排序 一 第1章 概述 1 数据 所有能被计算机识别 存储和处理的符号的集合 包括数字 字符 声音 图像等信息
  • 如何强制性管控代码质量

    一 背景 在之前的文章中 我们已经描述了jenkins和sonarqube是如何集成起来的 今天我们在该篇文章中描述下 如何使用gerrit jenkins sonar进行代码质量管控 主要是利用sonarqube分析代码的能力来管控 一般
  • ajax后台返回数据中文乱码_透彻分析和解决一切javaWeb项目乱码问题

    前言 乱码是我们在程序开发中经常碰到且让人头疼的一件事 尤其是我们在做javaweb开发 如果我们没有清楚乱码产生的原理 碰到乱码问题了就容易摸不着头脑 无从下手 乱码主要出现在两部分 如下 第一 浏览器通过表单提交到后台 如果表单内容有中
  • 近期面试总结

    最近两个月大大小小的面试已经不下十来场了 一共面了5 6个公司 大的有蚂蚁金服 小的有初创公司 也有做直播的等等 但是面试都是大同小异 因此来记录一下自己的不足之处以及需要加强的地方 项目 个人的项目经验其实非常重要 很多面试官往往会从项目
  • xprop

    xprop 使用说明 名字 xprop X的属性显示器 概要 xprop help grammar id id root name name frame font font display display len n notype fs f
  • UVM中的phase机制

    5 1 phase机制 5 1 1 task phase与function phase UVM中的phase 按照其是否消耗仿真时间 time打印出的时间 的特性 可以分成两大类 一类是function phase 如build phase
  • 被魔改md5加密坑了?某网站魔改md5加密逆向还原 (多种语言还原)

    大家好 我是TheWeiJun 最近由于工作太忙好久没有更新了 静下心来 突然很想念各位读者朋友 所以晚上抽空更新一篇 今天分享一篇关于魔改md5实现的加密算法逆向分析 本文将用多种语言还原加密算法 解决不同语言还原加密算法的难题 希望各位
  • Linux命令行操作:使用“more“命令进行分页显示

    文章目录 1 引言 1 1 介绍Linux操作系统和命令行界面 什么是Linux操作系统 为什么命令行界面在Linux中如此重要 1 2 介绍Linux中的分页显示命令 分页显示命令的作用与意义 不同分页显示命令的比较 2 more 命令的
  • Spring3学习笔记之(spring core之DI配置使用2)

    上一章节已经介绍了注入常量 集合等基本数据类型和集合数据类型 本小节将介绍注入依赖Bean及注入内部Bean 引用其他Bean的步骤与注入常量的步骤一样 可以通过构造器注入及setter注入引用其他Bean 只是引用其他Bean的注入配置稍
  • 5.6.1_浮点数的表示

    文章目录 一 引子 二 定点数的局限性 三 从科学计数法理解浮点数 1 十进制 2 二进制 1 定点数 2 浮点数 浮点数的表示 补充 练习 四 浮点数尾数的规格化 1 左规 1 十进制 2 二进制 2 右规 1 规则 2 例子 五 规格化
  • 手把手教你开发 clang 插件

    Clang是llvm的编译器前端 非常适合进行源码分析 目前开源的oclint就是基于clang进行的代码静态检查 工作中遇到了一些问题需要进行代码分析 所以学习了插件的开发流程 既然开发插件就要有合适的IDE Mac上最合适的无疑是xco