OCLint 初探

文章结构:

1. 什么是 OCLint

OCLint 是针对于 C,C++,Objective-C 代码的静态分析工具,目的是提高软件质量并且减少代码中存在的潜在问题,OCLint 旨于分析以下潜在问题:

  • 可能出现的 bug:if/else/try/catch 等条件语句空的声明
  • 未使用的代码: 未使用的局部变量以及参数
  • 复杂的代码逻辑:高循环复杂度、NP 复杂度(懵)、 高 NCSS(懵)
  • 冗余代码:冗余的条件表达式以及无效的括号
  • 代码嗅觉:方法代码行过长或者参数过多
  • 不好的代码习惯:颠倒的逻辑和参数的错误分配
  • ...

静态代码分析工具是侦测编译器不可见的潜在缺陷的关键技术。OCLint 具有以下先进的代码检验特性:

  • 依靠源码的抽象语法树来提高分析的精确度以及效率,误报率低
  • 动态规则
  • 灵活可扩展的配置,确保用户可以自定义分析行为
  • 命令行式的调用使持续集成成为可能

2. OCLint 安装

下载 OCLint

2.1. Homebrew 安装

确保你已经安装了 Homebrew

$ brew install oclint

近些天使用 Homebrew 安装 OCLint 经常失败,遂放弃了这种安装方式。

2.2. 下载并设置下载目录为环境变量

添加以下代码到命令行启动文件中,默认启动文件是 .bashrc.bash_profile ,安装 oh-my-zsh 后是 .zshrc 文件。

$ OCLINT_HOME=path-to-oclint-release
$ export PATH=$OCLINT_HOME/bin:$PATH

解释path-to-oclint-release是 OCLint 安装包的路径

使用以下命令判断是否添加环境变量成功

echo $PATH

2.3. 下载并拷贝至系统环境变量中

也可以直接将 OCLint 的可执行文件拷贝至系统文件夹 /usr/local/bin。可以注意到 /usr/local/bin 也在 PATH 中。

cd oclint
cp bin/oclint* /usr/local/bin/
cp -rp lib/* /usr/local/lib/

3. OCLint 工具的组成

OCLint 工具集由一下三部分组成

  • oclint
  • oclint-json-compilation-database
  • oclint-xcodebuild

具体的使用手册还是建议大家去阅读他们的官方文档,其功能可以简单概括为:

  • oclint 是 OCLint 工具集最主要的指令,主要作用是规则加载、编译分析选项以及生成分析报告
  • oclint-json-compilation-database 的作用是在 JSON Compilation Database format 类型的编译文件 compile_commands.json 中提取必要的信息。
  • oclint-xcodebuild 用于将 xcodebuild 生成的 log 文件 xcodebuild.log 转换为 JSON Compilation Database format 类型

可以使用时序图来概括我们使用这几个指令的场景:


oclint-sequence

4. OCLint 的使用

4.1. OCLint 结合 xcodebuild 的使用

xcodebuild 命令用来编译 Xcode 工程,xcodebuild 可以编译 Xcode 工程里面的一个或多个 target,也可以用来编译 Xcode workspace 或者 Xcode project 中的任意一个 scheme。

OCLint 结合 xcodebuild 的使用主要分为一下几个步骤

  1. 使用 xcodebuild clean 清理工程(可选)
  2. 使用 xcodebuild build 编译工程 并且使用 xcpretty 输出编译文件
  3. 使用 oclint-json-compilation-database 输出分析结果

4.1.1. 清理工程(可选)

假设一个源文件已经使用 xcodebuild 编译过了,并且没有被修改,那么下次编译的时候改源文件不参与编译,也就是说生成的 compile_commands.json 文件里面是不含有该源文件的内容的。如果你希望该源文件每次都编译,可以使用 xcodebuild clean 指令来清理编译缓存。

然而 clean 过后,编译过程会变得相当漫长,这种现象在大项目中表现最为明显。所以说如果你的项目文件没改动,工程的编译选项也未修改。使用上次的 xcodebuildcompile_commands.json 进行分析也是可取的。这里是否可以得出增量编译的条件下,项目中未变动代码的部分是不会出现在新的编译报告中的。

4.1.2. 编译工程,输出编译报告

使用 xcodebuild 命令编译工程,例如使用一下命令编译 OCLintDemo.xcworkspace 下的 OCLintDemo scheme。

xcodebuild -workspace       OCLintDemo.xcworkspace \
           -scheme          OCLintDemo \
           -configuration   Debug \
           -sdks            iphonesimulator10.3 \
           build

此时就有两种方式生成 compile_commands.json

方式一:使用 tee 指令获取输出结果为 xcodebuild.log ,使用 oclint-xcodebuild 将 xcodebuild.log 输出为 compile_commands.json 文件

xcodebuild -workspace       OCLintDemo.xcworkspace \
           -scheme          OCLintDemo \
           -configuration   Debug \
           -sdks            iphonesimulator10.3 \
           build | tee xcodebuild.log

oclint-xcodebuild

方式二:使用 xcpretty 直接将编译结果输出为 compile_commands.json

xcodebuild -workspace       OCLintDemo.xcworkspace \
           -scheme          OCLintDemo \
           -configuration   Debug \
           -sdks            iphonesimulator10.3 \
           build | xcpretty -r json-compilation-database -o compile_commands.json

推荐使用 xcpretty 的方式生成 json-compilation-database 类型的编译报告。

4.1.3. 输出分析结果

使用 oclint-json-compilation-database 指令来解析 json-compilation-database 类型的编译报告。

$ oclint-json-compilation-database --help
usage: oclint-json-compilation-database [-h] [-v] [-debug] [-i INCLUDES]
                                        [-e EXCLUDES]
                                        [oclint_args [oclint_args ...]]

OCLint for JSON Compilation Database (compile_commands.json)

positional arguments:
  oclint_args           arguments that are passed to OCLint invocation

optional arguments:
  -h, --help            show this help message and exit
  -v                    show invocation command with arguments
  -debug, --debug       invoke OCLint in debug mode
  -i INCLUDES, -include INCLUDES, --include INCLUDES
                        extract files matching pattern
  -e EXCLUDES, -exclude EXCLUDES, --exclude EXCLUDES
                        remove files matching pattern

从引导上来看,oclint-json-compilation-database 可以通过 -e 选项来忽略对制定路径文件的分析,对于使用 Cocoapods 来管理依赖的工程,我们往往会忽略 Pods 文件夹。

oclint-json-compilation-database -e Pods -- xxxx

通常使用 -- 来分割 oclint-json-compilation-database 的参数与 oclint_argsoclint_args 就是 oclint 命令的参数,接下来我们来看看 oclint 指令支持的参数。

$ oclint --help
USAGE: oclint [options] <source0> [... <sourceN>]

OPTIONS:

OCLint options:

  -R=<directory>                - Add directory to rule loading path
  -allow-duplicated-violations  - Allow duplicated violations in the OCLint report
  -disable-rule=<rule name>     - Disable rules
  -enable-clang-static-analyzer - Enable Clang Static Analyzer, and integrate results into OCLint report
  -enable-global-analysis       - Compile every source, and analyze across global contexts (depends on number of source files, could results in high memory load)
  -extra-arg=<string>           - Additional argument to append to the compiler command line
  -extra-arg-before=<string>    - Additional argument to prepend to the compiler command line
  -list-enabled-rules           - List enabled rules
  -max-priority-1=<threshold>   - The max allowed number of priority 1 violations
  -max-priority-2=<threshold>   - The max allowed number of priority 2 violations
  -max-priority-3=<threshold>   - The max allowed number of priority 3 violations
  -no-analytics                 - Disable the anonymous analytics
  -o=<path>                     - Write output to <path>
  -p=<string>                   - Build path
  -rc=<parameter>=<value>       - Override the default behavior of rules
  -report-type=<name>           - Change output report type
  -rule=<rule name>             - Explicitly pick rules

Generic Options:

  -help                         - Display available options (-help-hidden for more)
  -help-list                    - Display list of available options (-help-list-hidden for more)
  -version                      - Display the version of this program

-p <build-path> is used to read a compile command database.

    For example, it can be a CMake build directory in which a file named
    compile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
    CMake option to get this output). When no build path is specified,
    a search for compile_commands.json will be attempted through all
    parent paths of the first input file . See:
    http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an
    example of setting up Clang Tooling on a source tree.

<source0> ... specify the paths of source files. These paths are
    looked up in the compile command database. If the path of a file is
    absolute, it needs to point into CMake's source tree. If the path is
    relative, the current working directory needs to be in the CMake
    source tree and the file must be in a subdirectory of the current
    working directory. "./" prefixes in the relative files will be
    automatically removed, but the rest of a relative path must be a
    suffix of a path in the compile command database.

For more information, please visit http://oclint.org

如果想最终输出一个 HTML 类型的分析报告,一个完整的 oclint-json-compile-database 指令应该这么写

$ oclint-json-compilation-database -e Pods -- -o=report.html

4.2. 使用 OCLint 分析 Xcode 工程

Using OCLint with Xcode

5. OCLint 与持续集成

6. 遇到的问题

6.1. PCH 错误

Compiler Errors: (please be aware that these errors will prevent OCLint from analyzing this source code) :0:0: input is not a PCH file: '/xxx/PrefixHeader.pch.pch' :0:0: file '/xxx/PrefixHeader.pch.pch' is not a valid precompiled PCH file :0:0: input is not a PCH file: '/xxx/PrefixHeader.pch.pch' :0:0: file '/xxx/PrefixHeader.pch.pch' is not a valid precompiled PCH file OCLint Report Summary: TotalFiles=0 FilesWithViolations=0 P1=0 P2=0 P3=0 [OCLint (http://oclint.org) v0.12]

没找到问题原因,目前只知道将编译选项 Precompile prefix header 设置为 NO 可以解决问题。

6.2. oclint: error: violations exceed threshold

运行 oclint-json-compilation-databse 以下错误

$ oclint-json-compilation-database -e Pods -- -o=report.html
oclint: error: violations exceed threshold
P1=0[0] P2=1637[10] P3=53904[20]

出现这个的原因是项目中的 issue 超过了限制,使用以下 option 来约定最大的 issue 阈值。

-max-priority-1=9999 -max-priority-2=9999 -max-priority-3=9999

7. 引用文档

OCLint Documentation

Using OCLint with xcodebuild

Using OCLint with Xcode

oclint-json-compilation-database

json-compilation-database

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 写在前面 刚入职的时候,博哥交代给我一个任务,让我调研一款叫SonarQube的静态代码分析工具,我当时跪在了Ce...
    雨润听潮阅读 2,248评论 0 5
  • OCLint是一个强大的静态代码分析工具,可以用来提高代码质量,查找潜在的bug,主要针对c,c++和Object...
    刘应阅读 1,278评论 0 1
  • OCLint工具介绍 OCLint是一个静态代码扫描分析工具,可用于提高代码质量和减少潜在的缺陷,目前支持C,C+...
    Lojii阅读 5,947评论 5 5
  • 失去的那个人 是 一次曾誓死相知却遭到背弃 最后成为记忆中 永远 却无法再一次亲密的 那一个人 失去的那个人 和 ...
    因为爱所以执着阅读 462评论 0 1
  • 直接先把方法贴出来(参考了Stack Overflow) 下面解释下方法中用到的一些类型(参考MDN) Array...
    KimYYX阅读 16,424评论 4 6