iOS开发端代码检查
iOS开发端代码检查
背景:一直以来,代码质量都是一个痛心疾首的问题,特别是有新人进来团队的时候,每个人都需要相当长的磨合时间。传统上,我们都是在提测集成阶段进行代码质量检查,但是经常会忽略单个bug的修复以及无法落地整个团队的代码规范。针对这一系列的情况,决定利用开发端的资源,把日常代码质量检查融入到每个开发环节中。
ps:收藏一下,受益终生 ^_^
一、git hook
基本概念:git作为代码管理工具,目前应该是大家使用最多的了,git的最大的特点是增量记录,除了这个特点,今天还要说一下ta的另外一个特性git hook,其实就是针对git操作过程中每一个步骤进行监控,既包括客户端的,也包括服务端的。
目标:今天我们只学习客户端的监控,以达到开发端监控代码质量的目的
1、git的管理知识
(1)首先要了解git管理文件的一个概念,什么是工作区、版本库中的暂存区、版本库,如下图:
工作区:就是咱们平时文件存放的地方
版本库中的暂存区:就是文件的索引(index)文件,index会指向对应的objects
版本库:就是每次真正提交后存放的位置
所以,如果我们使用的是sourcetree,那么平时未暂存的文件,就是属于工作区,暂存的文件就是暂存区,提交动作之后的就是进入版本库。
(2)对应的命令
工作区,通过add命令会进入暂存区;暂存区,通过commit命令进度版本库,checkout 命令返回工作区;版本库,通过checkout命令进入工作区,通过reset命令进入暂存区;
2、开发端的git hook可用的有哪些?
平时我们直接git clone别人的库是看不到git hook的相关文件的,那么我们如何去创建这些hook程序呢?答案是在终端输入以下代码。
git init
没错,就是这么简单。
调完这个命令之后,就会创建出如下图的隐藏文件:
可以看到,hook文件夹下面多了很多sample,没错,这些就是支持的hook了。
3、使用git hook的例子
这次我们只使用pre-commit这个例子,而我的项目里面也暂时只需要使用这个。要让这个hook生效很简单,只需要pre-commit.sample把后缀去掉。
然后打开pre-commit文件,码下以下代码看看是否生效了:
echo "测试"
exit 1
你会发现commit再也提不上去了,还报了红色的“测试”两个大字。恭喜你hook成功了!
其实我们要对比代码,检查变更代码里面的问题,只需要用到git diff --staged命令,这样就可以获取到变更信息的字符串,剩下的工作就是规则、算法、判断、提示的工作了,这里我就不细说了。
4、无痕落地到开发项目以及日常更新
关于这个,我这边只说以下大致方案,其实没什么难点。
方案如下:
1、xcode建立script的target,然后执行脚本,在脚本中注入hook相关资源,可以让其他开发都能直接从0-1安装hook。
2、脚本还需增加版本管理,这样,可以判断是否版本更新了,以执行新脚本替换。
只要实现上面两步方案,开发基本就是,从分支里拉代码,build就完成更新操作,方便又实用。
二、clang插件
先看看效果,如下:
基本概念:LLVM全称 Low Level Virtual Machine,最开始设计是为虚拟机,现在已经是各种开发语言的编译解决方案,里面包含了多个工具:clang、clang-tools-extra、compiler-rt、libcxx、lld、lldb、llvm、llgo、openmp等等。
目标:这章节,我们主要是针对clang这个工具进行讲解,实战。
1、开源LLVM的选择
(1)LLVM源码
官方网站:https://www.llvm.org
官方github:https://github.com/llvm/llvm-project
工具拆分github:https://github.com/llvm-mirror
苹果专用:https://github.com/apple/llvm-project
(2)区别
【1】官方网站和官方github:下载的源码是一致的,无论是版本号,还是代码结构;
【2】工具拆分github:是可以根据使用者的需求单独下载对应工具模块,这样可以减少开发者下载等待的时间,毕竟一个完整的llvm包要差不多2g,里面有很多工具我们也不一定会用到;代码结构与其他源码不一致。
【3】苹果专用:就像字面一样,里面包含了很多苹果定制化的功能,比如-index-store-path的使用,还有modulemap等等。
(3)选择
因为我们要解决的是iOS的编译问题,当然是选择苹果专用的,不要问我为什么这么选择,我不会告诉你我踩过多少坑。
2、LLVM的编译
(1)了解苹果专用的LLVM目录结构,如下:
(2)CMake编译准备
【1】LLVM是用CMake来进行项目管理的,有图有真相,如下:
【2】CMake安装
CMake可以去https://cmake.org/下载,ta其实是一个应用程序,里面包含了cmake的工具命令。
CMake程序界面:
CMake程序命令的位置:/Applications/CMake.app/Contents/bin/cmake,如果自己要在终端上使用,可以把这个命令的路径加到$PATH变量里面。
到这里你终于可以用CMake生成编译配置了。
【3】CMake 编译配置生成,终端命令如下
cd 进入llvm源码根目录
mkdir build
cd build
cmake -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;libcxx;libcxxabi;compiler-rt;" -DCLANG_DEFAULT_CXX_STDLIB=libc++ -DCMAKE_BUILD_TYPE=Release ../llvm
如果生成成功会这样显示:
同样,你可以用CMake的app进行生成,这里我就不详细介绍了。
(3)终端编译
make -j`sysctl -n hw.logicalcpu`
如果没有安装make命令的只需要安装 xcode并且安装command Line Tools。
如果已经安装了, 只需要静等30-60分钟就可以编译完成。
(4)部分编译选项的作用
在这个过程里面,最重要的就是CMake的设置,上面代码的大体意思是,-G代表Generators,里面有多种选项,比如unix makefiles项目、Xcode项目、Ninja项目等,我们这里使用unix makefiles,因为用着舒服。
编译的项目“LLVM_ENABLE_PROJECTS”有“clang;clang-tools-extra;libcxx;libcxxabi;compiler-rt;”,这些库是经过我多次尝试选择后的最优开发模块,如果你们要用自己ld或者lldb,那你可以引入相关的项目进行编译。
“CLANG_DEFAULT_CXX_STDLIB”顾名思义是默认c++的标准库,支持c++11标准以后要改成用libc++库。
“CMAKE_BUILD_TYPE”编译模式为release模式,当然可以是debug模式,debug模式的程序要比release模式的程序大4倍,除非有特殊需求,不然建议直接release
源码路径是“../llvm”。
关于CMake的选项设置,更详细的可以通过命令:cmake --help查看,官方文档可以看:http://llvm.org/docs/CMake.html
3、项目接入自编译的clang
(1)clang接入的两步骤
【1】xcode->build settings->User-Defined添加CC、CXX,如下图:
【2】xcode->build settings->other link flags添加-lstdc++,如下图:
到这里恭喜你,你已经顺利接入自己编译的clang了^_^
题外话:为什么我会想自己编译clang呢?我估计有很多同学都会带着这样的疑问在看这边文章。其实最本质的原因就是,只有自己编译的clang才能放开插件功能,苹果默认的clang是不开放插件功能的。
(2)AST语法树的认识
【1】知识介绍
抽象语法树(abstract syntax code,AST)是源代码的抽象语法结构的树状表示,树上的每个节点都表示源代码中的一种结构,之所以说是抽象的,是因为抽象语法树并不会表示出真实语法出现的每一个细节,比如说,嵌套括号被隐含在树的结构中,并没有以节点的形式呈现。抽象语法树并不依赖于源语言的语法,也就是说语法分析阶段所采用的上下文无文文法,因为在写文法时,经常会对文法进行等价的转换(消除左递归,回溯,二义性等),这样会给文法分析引入一些多余的成分,对后续阶段造成不利影响,甚至会使整个阶段变得混乱。因此,很多编译器经常要独立地构造语法分析树,为前端,后端建立一个清晰的接口。抽象语法树在很多领域有广泛的应用,比如浏览器,智能编辑器,编译器。
引用外部一个对AST的理解的文章:https://blog.csdn.net/weixin_39408343/article/details/95984062,虽然里面不是OC相关语法树的例子,但是,抽象语法树是通用的,无论针对什么语言。
【2】如何查看AST树
在终端下输入以下代码,当然,ViewController.m你要自己写,或者是用xcode新建一个项目,直接用里面的文件直接替换
clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk -Xclang -ast-dump -fsyntax-only ViewController.m
例子
源码:
AST树:
【3】树节点例子说明
从上图可以看出,这个AST树主体分为两大部分:
第一部分ObjCInterfaceDecl
ObjCInterfaceDecl是OC类的声明,在这个例子是otherclass,同级的ObjCImplementationDecl是otherclass的实现部分。
ObjCInterfaceDecl后面super那一行,意思是otherclass继承NSObject;
ObjCImplementation表示实现的名字也是otherclass;
ObjCProtocol表示类实现了NSCoding协议;
ObjCPropertyDecl表示属性定义了aaa、bbb都是NSString*类型,拥有的特性readwrite nonatomic strong
ObjCMethodDecl表示定义了方法aaa、bbb、setAaa入参是NSString、setBbb入参是NSString,其实就是对应属性的get、set方法
第二部分ObjCImplementationDecl
ObjCImplementationDecl是otherclass的实现部分。
ObjCMethodDecl表示方法dealloc,和第一部分不一样的是,这部分的方法声明还包含实现部分。
ImplicitParamDecl 表示方法参数 ,像delloc这个有两个默认参数,self、_cmd,self是当前实例,_cmd是当前方法名
CompoundStmt可以简单认为是{}里面包含各种数据结构
CallExpr调用方法返回类型为void
ImplicitCastExpr返回值指针转换
DeclRefExpr方法名以及类型
ObjCStringLiteral参数类型
StringLiteral参数值
ObjCMessageExpr要调用的OC方法removeObserver
ObjCMessageExpr要调用的OC方法[NSNotificationCenter defaultCenter]
ImplicitCastExpr入参otherclass * self
详细定义说明请查看《AST语法树关键字解析》
4、编写clang插件demo
通过上面章节,我们基本完成对开发环境的搭建,以及对基础知识的了解,下面我们来进行实战,创建一个clang插件。
(1)项目配置
项目结构如下图:
【1】从图中可以看出,我们也是选择用CMake的方式构建项目,因此咱们先来看看CMakeLists.txt的文件结构,如下:
cmake_minimum_required (VERSION 2.6)#要求最低版本
project (XXClangPlugin)#项目名字
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )#设置build后输出的文件路径
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )#设置build后输出的文件路径
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )#设置build后输出的文件路径
set( LLVM_HOME /opt/llvm-apple )#设置内部变量的值,根目录
set( LLVM_SRC_DIR ${LLVM_HOME}/llvm-project201911/llvm )#llvm源码目录
set( CLANG_SRC_DIR ${LLVM_HOME}/llvm-project201911/clang )#clang源码目录
set( LLVM_BUILD_DIR ${LLVM_HOME}/llvm-project201911/build )#llvm编译目录
set( CLANG_BUILD_DIR ${LLVM_HOME}/llvm-project201911/build/tools/clang)#clang编译目录
add_definitions (-D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS)#项目增加宏
add_definitions (-D_GNU_SOURCE -DHAVE_CLANG_CONFIG_H)#项目增加宏
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -fno-common -Woverloaded-virtual -Wcast-qual -fno-strict-aliasing -pedantic -Wno-long-long -Wall -Wno-unused-parameter -Wwrite-strings -fno-exceptions -fno-rtti -stdlib=libc++ -std=c++14 -fPIC -w")#cmake项目的选项
set (CMAKE_MODULE_LINKER_FLAGS "-Wl,-flat_namespace -Wl,-undefined -Wl,suppress")#cmake项目的选项
set (LLVM_LIBS LLVMMCJIT LLVMX86CodeGen LLVMX86AsmParser LLVMX86Disassembler LLVMExecutionEngine LLVMAsmPrinter LLVMSelectionDAG LLVMX86Info LLVMMCParser LLVMCodeGen LLVMX86Utils LLVMScalarOpts LLVMInstCombine LLVMTransformUtils LLVMAnalysis LLVMTarget LLVMCore LLVMMC LLVMSupport LLVMBitReader LLVMOption LLVMDemangle LLVMBitstreamReader LLVMProfileData LLVMBinaryFormat LLVMRemarks) #项目需要加载的库
macro(add_clang_plugin name) #内部方法定义
set (srcs ${ARGN})#设置内部参数
include_directories( "${LLVM_SRC_DIR}/include" "${CLANG_SRC_DIR}/include" "${LLVM_BUILD_DIR}/include" "${CLANG_BUILD_DIR}/include" ) #设置包含的头文件目录
link_directories( "${LLVM_BUILD_DIR}/lib" ) #链接的库位置
add_library( ${name} SHARED ${srcs} ) #设置为动态库
if (SYMBOL_FILE)
set_target_properties( ${name} PROPERTIES LINK_FlAGS "-exported_symbols_list ${SYMBOL_FILE}")
endif()
foreach (clang_lib ${CLANG_LIBS})
target_link_libraries( ${name} ${clang_lib} ) #动态加入clang依赖的库
endforeach()
foreach (llvm_lib ${LLVM_LIBS})
target_link_libraries( ${name} ${llvm_lib} ) #动态加入llvm依赖的库
endforeach()
foreach (user_lib ${USER_LIBS})
target_link_libraries( ${name} ${user_lib} ) #动态加入用户自己想引入的库
endforeach()
endmacro(add_clang_plugin)
set(SYMBOL_FILE XXClangPlugin.exports) #设置变量
set (CLANG_LIBS clang clangFrontend clangAST clangAnalysis clangBasic clangCodeGen clangDriver clangFrontendTool clangLex clangParse clangSema clangEdit clangSerialization clangStaticAnalyzerCheckers clangStaticAnalyzerCore clangStaticAnalyzerFrontend clangAPINotes)#设置变量
set (USER_LIBS pthread curses z)#设置变量
add_clang_plugin(XXClangPlugin XXClangPlugin.cpp)#调用内部方法
set_target_properties(XXClangPlugin PROPERTIES LINKER_LANGUAGE CXX PREFIX "")
可以开始生成编译项目了,如下:
进入插件源码目录
mkdir build;
cd build
cmake -G Xcode ..
(2)编写代码
上面我们生成了xcode项目,可以直接xcode打开了,下面接着编写源码,如下:
static clang::FrontendPluginRegistry::Add<XXClangPlugin::XXASTAction>X("XXClangPlugin", "XX Clang Plugin");//入口代码就一句,注册一个插件类
////最简单的插件类
#include <zlib.h>
#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"
using namespace clang;
namespace XXClangPlugin{
class XXClassVisitor : public RecursiveASTVisitor<XXClassVisitor>
{
private:
CompilerInstance &Instance; //当前检查变量
ASTContext *context; ///是否需要检查的类
public:
XXClassVisitor (CompilerInstance &Instance) :Instance(Instance)
{ }
void setContext(ASTContext &context) { this->context = &context; }
///类声明
bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *declaration)
{
printf("进来了");
return true;
}
}
class XXConsumer : public ASTConsumer
{
CompilerInstance &Instance;
std::set<std::string> ParsedTemplates;
public:
XXConsumer(CompilerInstance &Instance, std::set<std::string> ParsedTemplates) : Instance(Instance), ParsedTemplates(ParsedTemplates), visitor(Instance) { }
void HandleTranslationUnit(ASTContext &context)
{
visitor.setContext(context);
visitor.TraverseAST(context);
}
private:
XXClassVisitor visitor;
};
class XXASTAction : public PluginASTAction
{
std::set<std::string> ParsedTemplates;
public:
virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler, llvm::StringRef InFile)
{
printf("编译文件:%s\n", InFile);
return std::make_unique<XXConsumer>(Compiler, ParsedTemplates);
}
bool ParseArgs(const CompilerInstance &CI, const std::vector<std::string>& args)
{
for (int i = 0; i < args.size(); i++) {
printf("参数:%s\n", args[i].c_str());
}
return true;
}
};
}
到此,基础的插件源码文件已经写完,编译通过后会生成XXClangPlugin.lib,这个就是咱们要引进项目的插件了。ps:可以看到,上面的代码是用C++编写的,所以你要学习一下C++。
(3)调试
说起调试,这个真的是一个巨大的坑,翻遍百度和google都没找到相关资料。幸好,后来找到一个很有用的信息,就是clang的编译每次都是一个独立的进程。有了这个信息,终于可以愉快调试了。。。以下是相关调试方法:
【1】注意点
clang必须使用自己编译出来的,找找编译目录,能找到,不然编译报错提示加载插件失败。
必须要加载对应的系统库,不然你连uikit都识别不了
必须要开arc模式,不然等着各种报错。
【2】终端代码
/xxx/llvm-project201911/build/bin/clang -Xclang -load -Xclang /Path/to/XXClangPlugin.dylib -Xclang -add-plugin -Xclang XXClangPlugin -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk -fsyntax-only -fobjc-arc -v /Users/XXXX/Desktop/test/test/ViewController.m
这一步的目标虽然可以看到插件的返回内容,但是并不是真正的调试。目标是要找到以下这段代码:
"/xxx/llvm-project201911/build/bin/clang-10" -cc1 -triple x86_64-apple-ios13.2.0-simulator -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -fsyntax-only -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ViewController.m -mrelocation-model pic -pic-level 2 -mthread-model posix -mframe-pointer=all -masm-verbose -munwind-tables -target-sdk-version=13.2 -target-cpu core2 -dwarf-column-info -debugger-tuning=lldb -target-linker-version 530 -v -resource-dir /xxx/llvm-project201911/build/lib/clang/10.0.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/local/include -internal-isystem /xxx/llvm-project201911/build/lib/clang/10.0.0/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include -fdebug-compilation-dir /xxx/XXClangPlugin/build/lib/Debug -ferror-limit 19 -fmessage-length 111 -stack-protector 1 -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fobjc-runtime=ios-13.2.0 -fobjc-arc -fobjc-exceptions -fexceptions -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -load XXClangPlugin.dylib -add-plugin XXClangPlugin -x objective-c /Users/XXXX/Desktop/test/test/ViewController.m
接着,调试肯定是LLDB
lldb "/xxx/llvm-project201911/build/bin/clang-10"
会进入如下状态:
lldb后,还是要继续码代码,如下:
process launch -- -cc1 -triple x86_64-apple-ios13.2.0-simulator -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -fsyntax-only -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ViewController.m -mrelocation-model pic -pic-level 2 -mthread-model posix -mframe-pointer=all -masm-verbose -munwind-tables -target-sdk-version=13.2 -target-cpu core2 -dwarf-column-info -debugger-tuning=lldb -target-linker-version 530 -v -resource-dir /xxx/llvm-project201911/build/lib/clang/10.0.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/local/include -internal-isystem /opt/llvm-apple/llvm-project201911/build/lib/clang/10.0.0/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include -fdebug-compilation-dir /xxx/XXClangPlugin/build/lib/Debug -ferror-limit 19 -fmessage-length 111 -stack-protector 1 -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fobjc-runtime=ios-13.2.0 -fobjc-arc -fobjc-exceptions -fexceptions -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -load XXClangPlugin.dylib -add-plugin XXClangPlugin -x objective-c /Users/XXXX/Desktop/test/test/ViewController.m
恭喜你!!到这里是真的可以调试了,你会发现执行完上面的代码后,一样能达到之前直接执行终端命令的效果。为啥没有中断呢?那是因为没有设置断点。。
break set --name XXClangPlugin::XXClassVisitor::VisitObjCInterfaceDecl
好了,你再次执行process launch就可以完美进入断点了。
【3】调试技巧
打印c++对象要用p命令,用po啥都看不到
c命令,就是跳到下个断点
n命令,是下一步
s 进去
exit 退出lldb
其他命令都可以网上查到,慢慢玩耍
5、项目引入插件
项目接入插件比较简单。
(1)把编译好的clang及相关头文件都要复制到想使用的项目的根目录,当然目录可以自己定,如下:
里面的文件都是经过千辛万苦裁减过的,是独立编译的最小包了,大概是200M。
(2)buildsetting->other c flag和other c++ flag都要加上如下代码:
-Xclang -load -Xclang $(SRCROOT)/Path/to/XXClangPlugin.dylib -Xclang -add-plugin -Xclang XXClangPlugin
恭喜,到这里终于可以在项目里面使用自己的插件了!!!!!
6、pod如何使用插件
现在项目大部分都用pod来进行管理,所以咱们也要把pod环境兼容了。这里有很多坑,后面在Q&A环节一一解答。
pod的兼容其实基本和主工程才不多,只是要把相关工作放在podfile上去操作而已,代码如下:
config.build_settings['CC'] = ['$(SRCROOT)/../clang-apple/bin/clang']
config.build_settings['CXX'] = ['$(SRCROOT)/../clang-apple/bin/clang++'] config.build_settings['OTHER_LDFLAGS'] = ['$(inherited)','-lstdc++'];
config.build_settings['OTHER_CFLAGS'] = ['-Xclang -load -Xclang $(SRCROOT)/../clang-apple/FXClangPlugin.dylib -Xclang -add-plugin -Xclang FXClangPlugin']
config.build_settings['OTHER_CPLUSPLUSFLAGS'] = ['$(OTHER_CFLAGS)']
只要根据需要,把需要特别处理的项目加入上面代码相关的配置,就可以加载自己编译的插件实现章节开始最上面的效果。
三、Q&A
1、Q:为什么不能用其他版本的LLVM?
A:因为苹果自己做了定制化的内容,改了一些,如果使用其他版本的LLVM新项目是可以编译通过的,没有那么多限制,但是老项目就可能使用了很多苹果的特性功能,所以会导致各种问题。比如:index-store-path问题,modulemap问题,import重复加载问题等等。
2、Q:llvm的clang版本和xcode自带clang的版本如何对上?
A:确实基本是对不上的,llvm官网上面最新版本才9.01,但是你用命令去查xcode的clang版本会发现是11。所以才会导致我最后找到苹果的开源代码,看上面的代码可以看出,我编译出来的版本是clang-10,但是其实已经是很新的clang版本了。目前发现的版本就是看日期,尽量使用最接近xcode发布时间的release版本。
3、Q:使用clang插件的优缺点?
A:
优点:(1)依赖编译检查(2)可以中断编译(3)可以深度控制AST检查(4)可以实现代码补全
缺点:(1)依赖整个clang编译环境 (2)不能完全控制clang,包括映射虚拟内存文件(3)不可以单独检查部分变更文件
4、等待同学提出及时补充更新
四、总结
知识的沉淀很重要,在最开始学习llvm时,没有前辈的系统知识和文章,只能不停的尝试,现在把这些尝试后的宝贵经验留下,为了让以后的人少走弯路。