原文地址后续会有更改,可能不会及时同步在这里
参考文章:
- Mac安装PostgreSQL
- Fastlane+OCLint+SonarQube
- OS Sonar集成流程详解
- SonarQube 的安装与使用
- sona-objective-c
背景
随着代码量的日益增加,以及团队的扩大,代码的质量需要有一定的保证,再加上目前有些功能需要oem给客户使用,一些KA用户会要求提供一些代码分析报告,所以本文将总结一下如何搭建iOS静态代码分析系统
本文涉及的工具及平台:
- xcodebuild
- oclint
- xcpretty
- sonarqube
- sonar-scanner
- sonar-server
- postgresql
大部分iOS平台静态分析基本是基于开源的oclint进行的,本文虽然使用sonarqube
,但免费的分析方案核心仍然是oclint
sonarqube
是一个开源的静态代码分析平台,提供免费的社区版,免费的社区版不支持oc,但github
有提供开源的插件,可以支持OC代码分析,付费的社区版plus有支持oc的分析插件SonarCFamily for C
无论免费方案还是付费方案,首先都是基于xcodebuid
过程中的日志来进行的,下面先总结下免费的开源方案配置流程(ps:付费版试用还没申请成功,成功后再总结一下与开源方案对比一下)
对于使用开源方案来说,本质流程如下
xcodebuild
iOS
核心工具,安装好Xcode
就会自带此工具,因为oclint
分析的核心是xcodebuild
在编译app
过程中的log
,所以需要xcodebuild
(build
失败也会对已经build
的日志进行分析,但尽量保证可以build
成功)
如果项目是在workspace
中需要指定-workspace
和对应的scheme
,可以通过xcodebuild -list
查看
$ xcodebuild -list
Information about project "HHTestOClint":
Targets:
HHTestOClint_Example
HHTestOClint_Tests
Build Configurations:
Debug
Release
If no build configuration is specified and -scheme is not passed then "Release" is used.
Schemes:
HHTestOClint-Example
//执行
$ xcodebuild -workspace HHTestOClint.xcworkspace -scheme HHTestOClint-Example
error: Signing for "HHTestOClint_Example" requires a development team. Select a development team in the Signing & Capabilities editor. (in target 'HHTestOClint_Example' from project 'HHTestOClint')
我们并不需要打出的包可以安装到手机上,只是需要build
过程中的日志而已,所以我们只需要打出模拟器包Debug
便可
$ xcodebuild -showsdks
iOS SDKs:
iOS 13.2 -sdk iphoneos13.2
iOS Simulator SDKs:
Simulator - iOS 13.2 -sdk iphonesimulator13.2
因为xcodebuild
会有缓存,所以我们每次执行前需要clean
xcodebuild -workspace HHTestOClint.xcworkspace -scheme -configuration Debug HHTestOClint-Example -sdk iphonesimulator13.2 clean build
能编译成功的话就可以进入下一步了
xcpretty
xcpretty is a fast and flexible formatter for xcodebuild. It does one thing, and it should do it well.
xcpretty
是一个格式化xcodebuild
输出的工具,安装
$ gem install xcpretty
[!] Usage: xcodebuild [options] | xcpretty
-t, --test Use RSpec style output
-s, --simple Use simple output (default)
-k, --knock Use knock output
--tap Use TAP output
-f, --formatter PATH Use formatter returned from evaluating the specified Ruby file
-c, --[no-]color Use colorized output. Default is auto
--[no-]utf Use unicode characters in output. Default is auto.
-r, --report FORMAT or PATH Run FORMAT or PATH reporter
Choices: junit, html, json-compilation-database
-o, --output PATH Write report output to PATH
--screenshots Collect screenshots in the HTML report
-h, --help Show this message
-v, --version Show version
-r, --report
指定生成的报告格式可选为junit, html, json-compilation-database
-o, --output
指定生成的文件名称
这里我们使用json-compilation-database
格式,输出文件名为compile_commands.json
(注意输出名称不能更改,否则后面oclint会报错,因为oclint源码中内置了校验名称,此处便是写死的解析文件名称的代码)
$ xcodebuild -workspace HHTestOClint.xcworkspace -scheme HHTestOClint-Example -sdk iphonesimulator13.2 clean build | xcpretty -r json-compilation-database -o compile_commands.json
OClint
OCLint is a static code analysis tool for improving quality and reducing defects by inspecting C, C++ and Objective-C code
OClint
是进行OC代码分析的核心工具,主要对上一步生成的compile_commands.json
进行分析,生成报告
$ oclint --help
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
OCLint options:
-disable-rule= - Disable rules
-list-enabled-rules - List enabled rules
-max-priority-1= - The max allowed number of priority 1 violations
-max-priority-2= - The max allowed number of priority 2 violations
-max-priority-3= - The max allowed number of priority 3 violations
-o= 输出文件路径
-p= 解析路径
-rc== 指定校验规则取值
-report-type= 生成报告类型
For more information, please visit http://oclint.org
其中我们主要使用oclint-json-compilation-database,Github源码
oclint-json-compilation-database
支持指定校验文件夹和过滤指定文件夹,本质上最终执行oclint -p
命令,可以通过附加-v
查看,同时还支持使用--
后面跟上oclint执行参数
// 此处--符号后的参数是传递给oclint的
oclint-json-compilation-database -v -e Pods -e xxxx -- -report-type html -o report.html
oclint
的-rc
选项可以自定义校验的参数值,如
oclint-json-compilation-database -v -e Pods -e xxxx -- -rc LONG_METHOD=60 -rc LONG_LINE=100
当我们需要自定义多个oclint
参数时,我们可以将配置写在.oclint
文件中
disable-rules: // 不使用的规则
- LongLine
rulePaths: // oclint校验规则所在的路径,Mac端默认在/usr/local/lib/oclint/rules,如果不需要自定义规则的话可以不配置此项
- /etc/rules
rule-configurations: // 自定义配置参数
- key: CYCLOMATIC_COMPLEXITY
value: 15
- key: NPATH_COMPLEXITY
value: 300
output: oclint.xml // 生成的报告
report-type: xml // 生成的报告格式支持html、xml、json等
max-priority-1: 20 // 级别1的问题最大个数,如果检测出的问题超过这个个数就会自动终止
max-priority-2: 40 // 级别2的问题最大个数
max-priority-3: 60 // 级别3的问题最大个数
enable-clang-static-analyzer: false //
以下是所有支持的Rule
,可以通过 -list-enabled-rules xxxx
查看
Enabled rules:
- TooManyMethods
- DestructorOfVirtualClass
- DeadCode
- EmptyForStatement
- AvoidDefaultArgumentsOnVirtualMethods
- ProblematicBaseClassDestructor
- MisplacedDefaultLabel
- EmptyFinallyStatement
- CallingProhibitedMethod
- RedundantIfStatement
- CollapsibleIfStatements
- UnnecessaryElseStatement
- ConstantConditionalOperator
- DeepNestedBlock
- AssignIvarOutsideAccessors
- UnnecessaryNullCheckForDealloc
- RedundantNilCheck
- RedundantLocalVariable
- EmptyDoWhileStatement
- UnusedMethodParameter
- BitwiseOperatorInConditional
- ReturnFromFinallyBlock
- MultipleUnaryOperator
- DoubleNegative
- MissingCallToBaseMethod
- EmptyWhileStatement
- ShortVariableName
- ParameterReassignment
- UselessParentheses
- ThrowExceptionFromFinallyBlock
- UnnecessaryDefaultStatement
- HighNcssMethod
- PreferEarlyExit
- MissingBreakInSwitchStatement
- TooManyParameters
- CallingProtectedMethod
- AvoidBranchingStatementAsLastInLoop
- MissingAbstractMethodImplementation
- MissingHashMethod
- MisplacedNullCheck
- MisplacedNilCheck
- UseContainerLiteral
- LongLine
- ForLoopShouldBeWhileLoop
- HighNPathComplexity
- LongMethod
- EmptySwitchStatement
- RedundantConditionalOperator
- EmptyTryStatement
- EmptyCatchStatement
- UseObjectSubscripting
- AvoidPrivateStaticMembers
- EmptyElseBlock
- InvertedLogic
- LongClass
- LongVariableName
- GotoStatement
- BrokenOddnessCheck
- UseNumberLiteral
- TooFewBranchesInSwitchStatement
- UseBoxedExpression
- JumbledIncrementer
- EmptyIfStatement
- MissingDefaultStatement
- HighCyclomaticComplexity
- NonCaseLabelInSwitchStatement
- ConstantIfExpression
- BrokenNullCheck
- BrokenNilCheck
- TooManyFields
- UnusedLocalVariable
我们将.oclint
放在与compile_commands.json
相同的路径下,并在该路径下执行
oclint-json-compilation-database -v -e Pods -e Example
最终会生成oclint.xml
(可以自己生成html格式,查看效果)
sonarqube
sonarqube
是一个提供代码静态分析的平台,提供了一套完整的静态分析方案,包括后端及前端页面,可以结合jenkins、gitlab
等平台来进行代码分析。
因为其底层源码为java
开发的,所以对java
代码支持比较完善,但是免费的社区版并不支持OC
,所以我们如果要借助此平台的话,有以下两种方式:
- 开源插件sonar-object-c
-
github
上开源的插件,目前作者已经停止迭代,上面是找了好久找到的能兼容sonarqube7.9
的版本 ,核心是使用oclint
检查,目前只有70+
规则,但是可以自定义规则
-
- 付费使用社区版plus,提供了
SonarCFamily for C
插件- 有官方提供技术支持,
250+
的rules可供选择,不可自定义规则
- 有官方提供技术支持,
前提准备
无论使用上面哪种方案,首先要将服务搭建好服务,搭建服务有两种方式
docker安装
下载安装包
下面主要总结使用安装包的配置流程:
安装包下载完成后,执行sonarqube-7.9.1/bin/macosx-universal-64/sonar.sh start
,此时http://localhost:9000/
应该已经可以访问了,默认账号为admin
密码为admin
,如果启动失败可以去sonarqube-7.9.1/logs
下查看日志,启动成功后我们在最下面会看到warning
此处建议我们自己配置数据库,下面我们就来配置数据库(mysql
后续将不再支持):这里我们使用的是PostgreSQL
,配置参考
$ brew install postgresql //安装
$ pg_ctl -D /usr/local/var/postgres start //启动
$ createdb //创建数据库
$ psql //登录控制台
数据库安装好后,我们需要提供一个数据库和账号供sonarqube
使用
CREATE USER sonarqube WITH PASSWORD 'sonarqube';//创建用户
CREATE DATABASE sonar OWNER sonarqube;//创建属于该用户的数据库
然后我们去sonarqube-7.9.1/conf
目录下编辑sonar.properties
,将数据库相应配置配置完成
sonar.jdbc.username=sonarqube
sonar.jdbc.password=sonarqube
sonar.jdbc.url=jdbc:postgresql://localhost/sonar
编辑完成后执行sonarqube-7.9.1/bin/macosx-universal-64/sonar.sh restart
,此时警告已经消除了
至此我们的sonarqube
的前端服务已经配置完成了
以下是配置过程中可能遇到的问题:
-
java.security.AccessControlException: access denied
- java版本问题不支持高版本13,(使用
docker
就没这个问题)
- java版本问题不支持高版本13,(使用
-
Sonarqube will not start due to elasticsearch being unable to write yml settings file
-
elasticsearch
不支持root用户启动,ls -la
检查报错文件夹是否归属为root
,如果为root
就使用修改所属用户
-
-
mysql
连接失败(换个数据库吧)- 7.9可能不支持mysql
- 低版本不支持mysql8
分析工具选择
- 开源插件sonar-object-c
- 下载jar包到
sonarqube-7.9.1/extensions/plugins
,然后重启服务器 - 下载sonar-scanner for cli
- 将
sonascanner
添加至环境变量export PATH=$PATH:/path/to/scanner/
(建议将此命令放到配置环境里,保证每个终端都包含此环境变量)
上述配置安装完成后,我们在需要检测的项目跟路径下创建sonar-project.properties
文件,下面是简单的内容
# Required metadata
sonar.projectKey=xxxx // 项目key 随便定义
sonar.projectName=xxxx // 项目名称一般与检测项目一致,显示在sonar的web页面上
sonar.projectVersion=xx // 项目版本
# Comma-separated paths to directories with sources
sonar.sources=xxxxx // 项目需要检测的源码路径
sonar.objc.file.suffixes=.h,.m // oc 文件前缀
sonar.sourceEncoding=UTF-8 // 编码
sonar.objectivec.oclint.report=oclint.xml
这里的核心便是在上面步骤中由OCLint生成的xml文件,另外注意这里有一个坑,oclint.xml必须放至sonar-reports
文件下,无论sonar.objectivec.oclint.report配置是什么,貌似都不生效
创建完成后,在sonar-project.properties
路径下执行sonar-scanner
,执行成功后,便可在sonar的前端页面看到对应的检测效果了
点击对应结果,可以查看详细信息,如果我们想过滤某些规则,或者自定义一些规则的取值,可以使用上面介绍的.oclint
文件进行自定义配置
总结
从上面可以看出,开源方案其实核心就是oclint
,只是借助了sonarqube提供的前端服务而已,所以如果有自定义需求,可以考虑自己搭建服务。
oclint
提供的rule只有70+,还有一些是不适用oc
的,但可以支持自定义规则,可定制性很高,所以如果不打算使用付费版的话,可以考虑自行定制规则。