Using OCLint with xcodebuild
简介
作者在一家头部体育直播公司赛事直播业务,高度组件化带来便利的同时,有时候Xcode的抽风也是让人很是头疼,其中有一次就是写了一个带有返回值的函数,里面有多个case分支,有一个分支没有返回,也没注意到,Xcode竟然毫无报错甚至警告也没有。。review同事也没有很细致的注意到,导致最后灰度期间打tag报错浪费了很多不必要的时间,作者也很是尴尬。Xcode静态检查也没有报错提示。
所以笔者研究了一翻靠谱的方案,决定借助OCLint结合xcodebuild Release环境下全面检查下自己负责业务块儿的代码质量和规范问题
大家可以去OCLint详细了解下
OCLint是一个静态代码扫描分析工具,提高代码质量和减少潜在的缺陷,目前支持C,C++,Objective-C
主要功能:
1.可能的bugs - 空的if/else/try/catch/finally语句
2.未使用的代码段 - 未使用的局部变量和参数等
3.过于复杂的代码 - 圈逻辑复杂度、函数所有可能的执行路径的数量大小、有效代码行高低等
4.冗余的代码 - 比如冗余的if语句和无用的括号等
5.代码异味 (Code smells)
- 比如超长的方法和参数列表;如果一段代码是不稳定或者有一些潜在问题的,那么代码往往会包含一些明显的痕迹。
正如食物要腐坏之前,经常会发出一些异味一样。
6.错误的做法 - 比如反转逻辑,参数的重新分配
7. ...
安装OCLint
笔者通过brew来安装
brew tap oclint/formulae
brew install oclint
每次使用brew安装软件时,默认都会自动检查更新Homebrew,显示Updating Homebrew...,会浪费很多的时间,所以要关闭自动更新,在命令行执行如下命令即可在当前命令行会话关闭自动更新:
export HOMEBREW_NO_AUTO_UPDATE=true
如果想重启后依然生效,需要把上面这行加入到环境变量中去,编辑/etc/profile
sudo vim /etc/profile或者~/.base_profile
在末尾加上如下内容即可
export HOMEBREW_NO_AUTO_UPDATE=true
通过brew安装如果遇到问题:
/usr/local/include is not writable
尝试执行sudo chown -R $(whoami) /usr/local/
如果提示chown: /usr/local: Operation not permitted可能是更高Mac系统版本
试试执行sudo chown -R $(whoami) /usr/local/*
如果提示不行要看下是否是高版本mac兼容问题, /usr/local/下的include、include_old相关
其它安装方式参照官网OCLint安装
安装xcpretty
xcodebuild的输出阅读起来不是太直观,使用xcpretty可以解决这个问题,并且可以输出多种格式的日志信息
gem install xcpretty
xcodebuild编译并生成compile_commands.json
OCLint 结合 xcodebuild 的使用主要分为以下几个步骤
1. 使用 xcodebuild clean清理工程
2. 使用 xcodebuild 编译工程生成xcodebuild.log并且使用 xcpretty 输出编译报告为JSON Compilation Database format类型的compile_commands.json文件
3. oclint-json-compilation-database提取compile_commands.json文件信息并导出为指定格式的可视化编译分析报告
在我们xcodebuild之前最好先删除掉DerivedData下对应的编译索引缓存
下面以Demo为示例
xcodebuild clean
xcodebuild -workspace Demo.xcworkspace -scheme Demo -configuration Release | tee xcodebuild.log | xcpretty --report json-compilation-database --output compile_commands.json
笔者为pod组件工程,没有的话:
-workspace Demo.xcworkspace替换为-project Demo.xcodeproj
tee命令
如果我们既想把输出保存到文件中,又想在屏幕上看到输出内容,就可以使用tee命令了。以上就是把屏幕的输出同时也保存在xcodebuild.log中
xcpretty可以导出JSON Compilation Database format类型的compile_commands.json文件
输出编译分析结果
使用 oclint-json-compilation-database 指令来解析compile_commands.json。
oclint-json-compilation-database --help查看使用
usage: oclint-json-compilation-database [-h] [-v] [-debug] [-i INCLUDES]
[-e EXCLUDES] [-p build-path]
[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
-p build-path specify the directory containing compile_commands.json
ok接下来开始导出指定格式的分析报告
oclint-json-compilation-database -e Pods -- -report-type html -rc LONG_LINE=200 -rc LONG_VARIABLE_NAME=30 -disable-rule ShortVariableName -max-priority-1=10000 -max-priority-2=10000 -max-priority-3=10000 >> oclint_result.html
最终输出一个 HTML 类型的分析报告;当然也可以输出xml,pmd,xcode格式文件
-e Pods 忽略Pods文件夹(一些第三方库和其它私有库)。我们只关心我们自己的Framework工程的代码质量.
通常使用 -- 来分割 oclint-json-compilation-database 的参数与 oclint_args。oclint_args 就是 oclint 命令的参数
oclint --help来查看oclint指令支持的参数
USAGE: oclint [options] <source0> [... <sourceN>]
OPTIONS:
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:
-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
然后当前文件下多出来一个oclint_result.html文件
打开后部分显示:
build.png以下是shell脚本供参考:
#!/bin/bash
export LANG="zh_CN.UTF-8"
export LC_COLLATE="zh_CN.UTF-8"
export LC_CTYPE="zh_CN.UTF-8"
export LC_MESSAGES="zh_CN.UTF-8"
export LC_MONETARY="zh_CN.UTF-8"
export LC_NUMERIC="zh_CN.UTF-8"
export LC_TIME="zh_CN.UTF-8"
export LC_ALL=
function checkDepend () {
command -v xcpretty >/dev/null 2>&1 || {
echo >&2 "I require xcpretty but it's not installed. Install:gem install xcpretty";
exit
}
command -v oclint-json-compilation-database >/dev/null 2>&1 || {
echo >&2 "I require oclint-json-compilation-database but it's not installed. Install:brew install oclint";
exit
}
}
function oclintForProject () {
checkDepend
projectName=$1
scheme=$2
reportType=$3
REPORT_PMD="pmd"
REPORT_XCODE="xcode"
REPORT_HTML="html"
myworkspace=${projectName}
myscheme=${scheme}
echo "myworkspace是:${myworkspace}"
echo "myscheme是:${myscheme}"
echo "reportType为:${reportType}"
if [ -d ./build ]; then
rm -rf ./build
fi
xcodebuild clean
echo -e "\033[34m 【 🔨 开始编译... 】 \033[0m"
echo -e "\033[34m xcodebuild -workspace ${myworkspace}.xcworkspace -scheme ${myscheme} -sdk iphonesimulator -derivedDataPath ./build/derivedData -configuration Release COMPILER_INDEX_STORE_ENABLE=NO | xcpretty -r json-compilation-database -o compile_commands.json \033[0m"
xcodebuild -workspace ${myworkspace} -scheme ${myscheme} -sdk iphonesimulator -derivedDataPath ./build/derivedData -configuration Release COMPILER_INDEX_STORE_ENABLE=NO | xcpretty -r json-compilation-database -o compile_commands.json
if [ -f ./compile_commands.json ]
then
echo -e "\033[32m compile_commands.json已生成 \033[0m"
else
echo -e "\031[33m compile_commands.json生成失败 \033[0m"
return -1
fi
echo -e "\033[34m 开始分析,生成报告中...\033[0m"
exclude_files=("cardloan_js" "Pods")
exclude=""
for i in ${exclude_files[@]}; do
exclude=${exclude}"-e "${i}" "
done
echo "exclude dic:${exclude}"
if [[ ${reportType} =~ ${REPORT_PMD} ]]
then
nowReportType="-report-type pmd -o pmd.xml"
elif [[ ${reportType} =~ ${REPORT_HTML} ]]
then
nowReportType="-report-type html"
else
nowReportType="-report-type xcode"
fi
echo -e "\033[34m oclint-json-compilation-database ${exclude} -- ${nowReportType} -rc LONG_LINE=200 -disable-rule ShortVariableName -disable-rule ObjCAssignIvarOutsideAccessors -disable-rule AssignIvarOutsideAccessors -max-priority-1=100000 -max-priority-2=100000 -max-priority-3=100000 >> oclint_result.html \033[0m"
oclint-json-compilation-database ${exclude} -- \
${nowReportType} \
-rc LONG_LINE=200 \
-disable-rule ShortVariableName \
-disable-rule ObjCAssignIvarOutsideAccessors \
-disable-rule AssignIvarOutsideAccessors \
-max-priority-1=100000 \
-max-priority-2=100000 \
-max-priority-3=100000 >> oclint_result.html
# rm compile_commands.json
if [[ ${reportType} =~ ${REPORT_PMD} ]] && [ ! -f ./pmd.xml ]
then
echo -e "\033[31m 分析失败 \033[0m"
return -1
else
echo -e "\033[32m 👏👏👏 完毕 \033[0m"
return 0
fi
}
myworkspace="ABC.xcworkspace"
myscheme="ABC"
# html/xcode/pmd
reportType="html"
oclintForProject ${myworkspace} ${myscheme} ${reportType}
网友评论