美文网首页
xcodebuild+OCLint实践

xcodebuild+OCLint实践

作者: Frankxp | 来源:发表于2019-10-18 16:25 被阅读0次

    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}
    

    相关文章

      网友评论

          本文标题:xcodebuild+OCLint实践

          本文链接:https://www.haomeiwen.com/subject/vrxwmctx.html