欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

iOS开发 - OCLint自定义规则的编译与Xcode调试

程序员文章站 2022-07-13 21:52:43
...

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
  1. 官网下载CMake,传送门:https://cmake.org/download/

  2. 命令行输入 sudo "/Applications/CMake.app/Contents/bin/cmake-gui" --install

  3. 修改 ~/.bash_profile 文件

export CMAKE_ROOT=/Applications/CMake.app/Contents/bin/
 
export PATH=$CMAKE_ROOT:$PATH
  1. 终端运行source ~/.bash_profile使修改生效
  • 安装 Ninjia

ninja需要依赖于re2c,否则编译是会报错,re2c是一款语法分析器

  1. 安装re2c

http://re2c.org/index.html 下载 re2c

下载 re2c-1.3.tar 解压,然后

cd re2c-1.3
./configure
make 
make install
  1. 安装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 路劲下生成对应的文件

iOS开发 - OCLint自定义规则的编译与Xcode调试

cpp文件是逻辑实现,txt文件是规则匹配

Xcode工程创建

我们通过生成xcode工程来直观的管理各个规则,包括我们新建的ruleOCLint工程使用CMakeLists的方式维护各个文件的依赖关系,我们可以使用CMake自带的功能将这些CMakeLists生成一个xcodeproj工程文件

  • OCLint源码目录下建立一个文件夹,命名为oclint-xcoderules

iOS开发 - OCLint自定义规则的编译与Xcode调试

并创建一个脚本 ./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在里面

iOS开发 - OCLint自定义规则的编译与Xcode调试

如果使用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放进来,就可以了

iOS开发 - OCLint自定义规则的编译与Xcode调试
这样命令行调用 oclint 命令就会应用该rule,但是问题来了,我们如何调试呢,能够在Xcode里面进行调试最好,不然每次编译,然后查看结果,要崩溃了。

Xcode调试

cd 进入 oclint-driver 目录下,参考之前的方式,创建 Xcode工程

  1. 创建 create-xcode-driver.sh
  2. 脚本内容如下
#! /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工程

  1. 执行脚本 sh create-xcode-driver.sh,生成 Xcode工程

  2. 打开 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;
}


见下图:
iOS开发 - OCLint自定义规则的编译与Xcode调试

  • 拷贝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

iOS开发 - OCLint自定义规则的编译与Xcode调试

然后进行断点 UnusedLocalVariableRule.cpp 来进行调试

iOS开发 - OCLint自定义规则的编译与Xcode调试

成功断点,之后你就可以自行编写 rule,并进行调试了

参考文章: https://www.jianshu.com/p/84fa7b8fd8fe