iOS开发 - OCLint自定义规则的编译与Xcode调试
OCLint的编译
基于版本 oclint version 0.15
OCLint
需要自定义规则的话需要自己编译,如果是简单的使用,参考 OCLint的使用
从Github
下拉代码:
git clone https://github.com/oclint/oclint
README.md
oclint-core
oclint-driver
oclint-metrics
oclint-reporters
oclint-rules
oclint-scripts
编译过程比较长,需要 富墙 才会快一点
过程中提示错误,这里需要提前安装 cmake
以及 Ninja
- 安装
cmake
-
官网下载CMake,传送门:https://cmake.org/download/
-
命令行输入
sudo "/Applications/CMake.app/Contents/bin/cmake-gui" --install
-
修改
~/.bash_profile
文件
export CMAKE_ROOT=/Applications/CMake.app/Contents/bin/
export PATH=$CMAKE_ROOT:$PATH
- 终端运行
source ~/.bash_profile
使修改生效
- 安装
Ninjia
ninja
需要依赖于re2c
,否则编译是会报错,re2c
是一款语法分析器
- 安装
re2c
http://re2c.org/index.html 下载 re2c
下载 re2c-1.3.tar
解压,然后
cd re2c-1.3
./configure
make
make install
- 安装ninjia
git clone git://github.com/ninja-build/ninja.git && cd ninja
./configure.py --bootstrap
//mac 10.14以上版本权限可能不够
cp ninja /usr/bin/
或者拷贝至 /Applications/CMake.app/Contents/bin/
- 编译OCLint
然后进入oclint-scripts
,执行./make
aaa@qq.com-Pro oclint-scripts % ./make
Cloning into 'oclint-json-compilation-database'...
remote: Enumerating objects: 88, done.
remote: Total 88 (delta 0), reused 0 (delta 0), pack-reused 88
Unpacking objects: 100% (88/88), done.
Cloning into 'oclint-xcodebuild'...
remote: Enumerating objects: 85, done.
remote: Total 85 (delta 0), reused 0 (delta 0), pack-reused 85
Unpacking objects: 100% (85/85), done.
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 657 100 657 0 0 503 0 0:00:01 0:00:01 --:--:-- 503
100 424M 100 424M 0 0 4238k 0 0:01:42 0:01:42 --:--:-- 4720k
...
...
-- The C compiler identification is Clang 10.0.0
-- The CXX compiler identification is Clang 10.0.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Volumes/CaiCai/OCLint/oclint/build/llvm-install/bin/clang - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Volumes/CaiCai/OCLint/oclint/build/llvm-install/bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
LLVM_ROOT: /Volumes/CaiCai/OCLint/oclint/build/llvm-install
-- Found LLVM LLVM_PACKAGE_VERSION: 10.0.0 - LLVM_VERSION_RELEASE: 10.0.0
-- Using LLVMConfig.cmake in: /Volumes/CaiCai/OCLint/oclint/build/llvm-install/lib/cmake/llvm
-- Configuring done
-- Generating done
-- Build files have been written to: /Volumes/CaiCai/OCLint/oclint/build/oclint-driver
[14/14] Linking CXX executable bin/oclint-0.15
到这里OCLint
算编译成功了,但是还无法使用,参考官方文档 installation 部分说明,我们采用直接添加进PATH
方式
修改 ~/.bash_profile
文件 ,加入以下内容
OCLINT_HOME=/Users/sheng/Documents/Caicai/OCLint/oclint/build/oclint-release
export PATH=$OCLINT_HOME/bin:$PATH
然后 source ~/.bash_profile
使得修改生效
命令行输入 oclint
进行验证
aaa@qq.com-Pro ~ % oclint
LLVM ERROR: CommonOptionsParser: failed to parse command-line arguments. [CommonOptionsParser]: oclint: Not enough positional command line arguments specified!
Must specify at least 1 positional argument: See: oclint --help
这样就算成功了
自定义规则
rule 添加
OCLint
提供了一个脚本程序,位于 oclint-scripts/scaffoldRule
通过他传入要生成的规则名,级别,类型,脚本就会在目录oclint-rules/rules/custom/
自动帮我们生成一个模板代码,并且加入编译路径中。举个例子:
//生成一个名为 CCRuleTest ,类型为 ASTVisitor 的规则模板
oclint-scripts/scaffoldRule CCRuleTest -t ASTVisitor
你可以查看 scaffoldRule
文件了解更多可配置的参数
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("class_name", help="class name of the rule")
arg_parser.add_argument("-t", "--type", dest='rule_type', choices=['Generic', 'SourceCodeReader', 'ASTVisitor', 'ASTMatcher'], default="Generic")
arg_parser.add_argument("-c", "--category", dest='rule_category', default="custom")
arg_parser.add_argument("-n", "--name", dest='rule_name', default="")
arg_parser.add_argument("-p", "--priority", type=int, dest='rule_priority', choices=[1, 2, 3], default=3)
arg_parser.add_argument( "--test", dest='generate_tests', action='store_true', help="Generate a test for the new rule (default)")
arg_parser.add_argument( "--no-test", dest='generate_tests', action='store_false', help="Do not generate a test for the new rule")
arg_parser.set_defaults(generate_tests=True)
args = arg_parser.parse_args()
这样就会在 oclint/oclint-rules/rules/custom
路劲下生成对应的文件
cpp
文件是逻辑实现,txt
文件是规则匹配
Xcode工程创建
我们通过生成xcode工程来直观的管理各个规则,包括我们新建的rule
,OCLint
工程使用CMakeLists
的方式维护各个文件的依赖关系,我们可以使用CMake
自带的功能将这些CMakeLists
生成一个xcodeproj
工程文件
-
OCLint
源码目录下建立一个文件夹,命名为oclint-xcoderules
并创建一个脚本 ./create-xcode-rules.sh
,键入内容如下:
#! /bin/sh -e
cmake -G Xcode -D CMAKE_CXX_COMPILER=../build/llvm-install/bin/clang++ -D CMAKE_C_COMPILER=../build/llvm-install/bin/clang -D OCLINT_BUILD_DIR=../build/oclint-core -D OCLINT_SOURCE_DIR=../oclint-core -D OCLINT_METRICS_SOURCE_DIR=../oclint-metrics -D OCLINT_METRICS_BUILD_DIR=../build/oclint-metrics -D LLVM_ROOT=../build/llvm-install/ ../oclint-rules
然后 sh create-xcode-rules.sh
运行脚本,就生成了我们的xcode
工程 OCLINT_RULES
打开工程我们可以发现创建的rule
在里面
如果使用brew安装,这个路径应该是 /usr/local/Cellar/oclint/0.15/lib/oclint/rules
编译会生成对应的dylib库
,那我们之后如何更新 OCLint
的规则呢
更新dylib
oclint/build/oclint-release
是最终编辑结果,当我们添加了自定义规则后,自然要将自定义规则添加到oclint-release
中,我们进入 oclint/build/oclint-release/lib/oclint/rules
,可以看到所有的规则dylib都放在这里,我们将编译后的dylib放进来,就可以了
这样命令行调用 oclint
命令就会应用该rule
,但是问题来了,我们如何调试呢,能够在Xcode
里面进行调试最好,不然每次编译,然后查看结果,要崩溃了。
Xcode调试
cd 进入 oclint-driver
目录下,参考之前的方式,创建 Xcode工程
- 创建 create-xcode-driver.sh
- 脚本内容如下
#! /bin/sh -e
cmake -G Xcode \
-D CMAKE_CXX_COMPILER=../build/llvm-install/bin/clang++ \
-D CMAKE_C_COMPILER=../build/llvm-install/bin/clang \
-D OCLINT_BUILD_DIR=../build/oclint-core \
-D OCLINT_SOURCE_DIR=../oclint-core \
-D OCLINT_METRICS_SOURCE_DIR=../oclint-metrics \
-D OCLINT_METRICS_BUILD_DIR=../build/oclint-metrics \
-D LLVM_ROOT=../build/llvm-install/ ../oclint-driver
你可以每个文件夹生成Xcode工程,修改最后一个参数
这里对 oclint-driver 生成Xcode工程
-
执行脚本
sh create-xcode-driver.sh
,生成Xcode工程
-
打开
Schemes
面板,配置 启动参数
-R=/Users/sheng/Documents/Caicai/OCLint/oclint/oclint-xcoderules/rules.dl/Debug -report-type html -o /Users/sheng/Documents/Caicai/OCLint/oclint/output/reporter.html /Users/sheng/Documents/Caicai/OCLint/oclint/demo/test.m -- -x objective-c -isystem /Users/sheng/Documents/Caicai/OCLint/oclint/build/oclint-release/lib/clang/10.0.0/include -iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks -isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include
-R
表示设置rule的路径,我们设置为rule工程的编译debug路径-report-type html -o
html
文件报告输出路径test.m
我们写一个本地变量未使用的rule检测
int main(void) {
int i=9;
return 0;
}
见下图:
- 拷贝
reporters
文件
设置运行后,终端打印错误
oclint: error: cannot find dynamic library for report type: html
Program ended with exit code: 2
搜索错误 cannot find dynamic library
断点查看 reportDirPath
值为
/Users/sheng/Documents/Caicai/OCLint/oclint/oclint-driver/bin/Debug/../lib/oclint/reporters
因为我们改了bin
的路径,它根据 bin路径/../lib/oclint/reporters
来查找 reporters
,这里直接将 oclint-release
下的 reporters
连父目录一起拷贝,构成这个路径
- 创建
reporter.html
再次运行提示错误
oclint: error: cannot open report output file /Users/sheng/Documents/Caicai/OCLint/oclint/output/reporter.html
Program ended with exit code: 4
这里是创建的 output
文件夹路径写错了,放置到上面所说的正确位置后运行正常
运行正常后,查看 reporter.html
然后进行断点 UnusedLocalVariableRule.cpp
来进行调试
成功断点,之后你就可以自行编写 rule
,并进行调试了
上一篇: Mac-Sonar系统执行代码分析
下一篇: iOS- Xcode配置OCLint