iOS工程自動(dòng)化 - OCLint

為什么要使用 OCLint

做為一個(gè)靜態(tài)代碼分析工具,我們引入 OCLint 的目的主要是為了提高我們的代碼質(zhì)量信不。通常我們提高代碼質(zhì)量的方式是通過(guò) CodeReview嘲叔,但是這個(gè)過(guò)程耗費(fèi)的人工和時(shí)間往往較大,所以我們想通過(guò) OCLint 的一些規(guī)則抽活,讓機(jī)器幫我們完成一部分代碼質(zhì)量的檢測(cè)硫戈,從而提高我們的工作效率。

安裝 OCLint

OCLint 的安裝方式有很多中下硕,這里我們選擇最簡(jiǎn)單的方式:通過(guò) Homebrew 安裝丁逝。

安裝 Homebrew

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

安裝 OCLint

brew tap oclint/formulae
brew install oclint

命令行指令

OCLint 包含三個(gè)命令行指令:

  • oclint:基礎(chǔ)指令汁胆。通過(guò)這個(gè)指令可以指定加載驗(yàn)證規(guī)則、編譯代碼霜幼、分析代碼和生成報(bào)告嫩码。

  • oclint-json-compilation-database:高級(jí)指令。通過(guò)這個(gè)指令可以從 compile_commands.json
    文件中讀取配置信息并執(zhí)行 oclint罪既。

  • oclint-xcodebuild:通過(guò)這個(gè)指令可以從 Xcode 的 xcodebuild.log
    文件導(dǎo)出編譯選項(xiàng)并保存成 JSON Compilation Database 格式铸题。然后把保存到compile_commands.json文件中。

然后我們來(lái)看一下每個(gè)指令的選項(xiàng)和功能:

oclint

規(guī)則加載選項(xiàng)

  • -R <目錄>:指定規(guī)則加載的目錄萝衩』赝欤可以是多個(gè)目錄,用空格隔開猩谊,默認(rèn)情況下會(huì)搜索 $(oclint 可執(zhí)行文件目錄)/../lib/oclint/rules千劈。

  • -disable-rule <規(guī)則名> 通過(guò)規(guī)則名使某些驗(yàn)證規(guī)則失效。

  • -rc <參數(shù)>=<值> 修改某些閾值牌捷。

下面是一個(gè)簡(jiǎn)單的示例:

oclint -R /path/to/rules -disable-rule GotoStatement

表示從/path/to/rules加載規(guī)則墙牌,然后使 GotoStatement這個(gè)驗(yàn)證規(guī)則失效。
然后來(lái)看一下閾值暗甥,下面是 OCLint 里面一些常見的閾值:

名稱 描述 默認(rèn)值
CYCLOMATIC_COMPLEXITY 循環(huán)嵌套數(shù)限制 10
LONG_CLASS 類行數(shù)限制 1000
LONG_LINE 每行的字符限制 100
LONG_METHOD 方法行數(shù)限制 50
LONG_VARIABLE_NAME 參數(shù)名字符限制 20
MAXIMUM_IF_LENGTH if 的行數(shù)限制 15
MINIMUM_CASES_IN_SWITCH switch case 的最小數(shù)目 3
NPATH_COMPLEXITY 通過(guò)該方法的非循環(huán)執(zhí)行路徑數(shù)量限制 200
NCSS_METHOD 連續(xù)未注釋行數(shù)限制 30
NESTED_BLOCK_DEPTH block 嵌套層數(shù)限制 5
SHORT_VARIABLE_NAME 變量名的最小字符數(shù)限制 3
TOO_MANY_FIELDS 類成員限制 20
TOO_MANY_METHODS 類方法數(shù)限制 30
TOO_MANY_PARAMETERS 參數(shù)個(gè)數(shù)限制 10

我們也可以把這些閾值配置到項(xiàng)目的 .oclint 文件下喜滨,比如:

rule-configurations:

- key: CYCLOMATIC_COMPLEXITY

value: 15

- key: LONG_LINE

value: 50

編譯選項(xiàng)

可以通過(guò)-- 的方式在指令的最后添加編譯選項(xiàng)。
比如我們通過(guò)下面的clang指令編譯一個(gè)文件:

clang -x objective-c -arch armv7 -std=gnu99 -fobjc-arc -O0 -isysroot /Developer/SDKs/iPhoneOS6.0.sdk -g -I./Pods/Headers -c RPActivityIndicatorManager.m

在 OCLint 里面就可以這么寫:

oclint [oclint options] RPActivityIndicatorManager.m -- -x objective-c -arch armv7 -std=gnu99 -fobjc-arc -O0 -isysroot /Developer/SDKs/iPhoneOS6.0.sdk -g -I./Pods/Headers -c

編譯數(shù)據(jù)庫(kù)選項(xiàng)

-p <構(gòu)建目錄>:選擇一個(gè)包含compile_commands.json文件的目錄作為構(gòu)建目錄撤防。如果沒(méi)有指定構(gòu)建目錄虽风,oclint 指令會(huì)查找第一個(gè)輸入文件的所有父目錄來(lái)找到compile_commands.json文件。

生成報(bào)告選項(xiàng)

  • -o <目錄>:指定報(bào)告的輸出目標(biāo)寄月。

  • -report-type <類型名>:指定報(bào)告輸出的類型辜膝。默認(rèn)是普通文本。

報(bào)告輸出的類型有如下幾種:

  • Plain Text Report(text)

  • HTML Report(html)

  • XML Report(xml)

  • JSON Reporter (json)

  • PMD Reporter (pmd):這種類型主要提供給 CI 系統(tǒng)使用漾肮,在 CI 系統(tǒng)的展示會(huì)更友好厂抖。

  • Xcode Reporter (xcode):主要提供給 Xcode 內(nèi)查看。

同樣克懊,我們也可以把這個(gè)配置加入到 .oclint 文件中:

report-type: html
output: oclint.html

退出狀態(tài)選項(xiàng)

  • -max-priority-1 <閾值>

  • -max-priority-2 <閾值>

  • -max-priority-3 <閾值>

首先我們來(lái)看一下 OCLint 會(huì)返回的 5 種退出 Code:

  • 0 - SUCCESS:成功忱辅。

  • 1 - RULE_NOT_FOUND:沒(méi)有找到驗(yàn)證規(guī)則。

  • 2 - REPORTER_NOT_FOUND:沒(méi)有指定報(bào)告輸出地址谭溉。

  • 3 - ERROR_WHILE_PROCESSING:驗(yàn)證過(guò)程中出錯(cuò)墙懂。

  • 4 - ERROR_WHILE_REPORTING:生成報(bào)告時(shí)出錯(cuò)。

  • 5 - VIOLATIONS_EXCEED_THRESHOLD:違反規(guī)則的次數(shù)超出閾值扮念。

然后我們來(lái)看一下各個(gè)優(yōu)先級(jí)默認(rèn)的閾值:優(yōu)先級(jí) 3 的閾值為 20损搬;優(yōu)先級(jí) 2 的閾值為 10;優(yōu)先級(jí) 1 的閾值為 0。如果超過(guò)了其中任意一個(gè)閾值场躯,就表示你的代碼質(zhì)量是不達(dá)標(biāo)的,然后 OCLint 會(huì)返回 VIOLATIONS_EXCEED_THRESHOLD旅挤。

全局分析選項(xiàng)

-enable-global-analysis

開啟這個(gè)選項(xiàng)可以得到更準(zhǔn)確的分析結(jié)果踢关,但是相對(duì)耗時(shí)比較長(zhǎng),一般不采用粘茄。

Clang 靜態(tài)分析選項(xiàng)

-enable-clang-static-analyzer

如果開啟這個(gè)選項(xiàng)签舞,OCLint 會(huì) hook Clang 的編譯過(guò)程,然后收集編譯信息然后添加到報(bào)告中柒瓣。需要注意的是:這也會(huì)增加分析的時(shí)間儒搭。

Debug 選項(xiàng)

-debug

開啟這個(gè)選項(xiàng)會(huì)給出更詳細(xì)的信息。但是這個(gè)選項(xiàng)只有在 OCLint 的 debug 標(biāo)示開啟的時(shí)候才有效芙贫。

oclint-json-compilation-database

過(guò)濾選項(xiàng)

  • -i INCLUDES, -include INCLUDES, –include INCLUDES:

  • -e EXCLUDES, -exclude EXCLUDES, –exclude EXCLUDES:

這兩個(gè)選項(xiàng)是指在 compile_commands.json 文件中配置的基礎(chǔ)上添加一些文件/目錄來(lái)執(zhí)行 oclint搂鲫,或者讓一些文件/目錄不執(zhí)行 oclint。

這兩個(gè)選項(xiàng)支持正則匹配磺平,因?yàn)檫@個(gè)命令是用 Python 寫的魂仍,所以正則的格式以 Python 正則表達(dá)式語(yǔ)法 為準(zhǔn)。

比如拣挪,我們一般不對(duì)第三方庫(kù)執(zhí)行 oclint 擦酌,這個(gè)時(shí)候可以用下面的指令來(lái)把 Pods 目錄排除:

oclint-json-compilation-database -e Pods

oclint 的選項(xiàng)

可以通過(guò) --的方式在指令的最后 oclint 選項(xiàng)。比如:

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

在最后添加了一個(gè) oclint 的 -o 選項(xiàng)菠劝,表示將報(bào)告輸出到當(dāng)前目錄的 report.html 文件中赊舶。

調(diào)試選項(xiàng)

  • -v:通過(guò)這個(gè)選項(xiàng)可以輸出最終執(zhí)行的 oclint 指令。

  • -debug:開啟這個(gè)選項(xiàng)會(huì)給出更詳細(xì)的信息赶诊。但是同樣這個(gè)選項(xiàng)只有在 OCLint 的 debug 標(biāo)示開啟的時(shí)候才有效笼平。

oclint-xcodebuild

這個(gè)命令是給使用 Xcode 的用戶提供的。主要用于分析 xcodebuild.log 文件甫何,然后快速生成 compile_commands.json 文件出吹。

這貨已經(jīng)被 oclint 拋棄了,改用 xcpretty辙喂。

安裝 xcpretty

其實(shí)只需要執(zhí)行下面指令即可:

gem install xcpretty

使用 xcpretty 生成compile_commands.json文件

通過(guò)下面的指令即可生成 compile_commands.json文件:

xcodebuild [flags] | xcpretty -r json-compilation-database -o compile_commands.json

如果想保存 xcodebuild.log捶牢,可以換成下面的指令:

xcodebuild [flags] | tee xcodebuild.log | xcpretty -r json-compilation-database -o compile_commands.json

然后就可以執(zhí)行 oclint-json-compilation-database來(lái)進(jìn)行驗(yàn)證了。

與其他工具配合

xcodebuild

因?yàn)?oclint-xcodebuild 已經(jīng)被 oclint 拋棄了,所以跟 xcodebuild 的配合可以直接忽略亮元。

xctool

了解到 xctool 在 Xcode 8 以后已經(jīng)不再支持 build恼琼,而是變成了 xcbuild 指令,所以我們換成 xcbuild 來(lái)生成 compile_commands.json
文件灸蟆。

安裝 xcbuild

首先從 github 下載源碼:

git clone https://github.com/facebook/xcbuild
cd xcbuild
git submodule update --init

然后執(zhí)行如下指令:

make

這里需要用到 cmake 和 ninja,所以我們通過(guò)下面的指令安裝:

brew install cmake ninja

使用 xcbuild 生成 compile_commands.json文件

使用如下指令即可生成 compile_commands.json文件

xcbuild [flags] | xcpretty -r json-compilation-database -o compile_commands.json

事實(shí)上 xcbuild 和 xcodebuild 的指令是完全兼容的…

Xcode IDE

oclint 可以和 Xcode IDE 結(jié)合亲族,把錯(cuò)誤直接在 IDE 中顯示出來(lái)炒考。
首先可缚,我們?cè)陧?xiàng)目中創(chuàng)建一個(gè)新的 target,然后選擇 Aggregate 作為模板斋枢。


然后給這個(gè) target 命名帘靡,注意我們可以建立多個(gè) target,然后分別關(guān)注代碼分析的多個(gè)方面瓤帚。
然后在 Build Phases 選項(xiàng)卡中選擇 Add Run Script描姚。

關(guān)于腳本的編寫我們?nèi)匀贿x擇最簡(jiǎn)單的方式,即 xcodebuild + xcpretty + oclint-json-compilation-database 的方式來(lái)做 oclint戈次。腳本如下:

source ~/.bash_profilecd

${PROJECT_DIR}

xcodebuild clean

xcodebuild -workspace LPDLogger.xcworkspace -configuration Debug -scheme LPDLogger-Example build | xcpretty -r json-compilation-database -o compile_commands.json

oclint-json-compilation-database -- -report-type xcode

然后我們就可以開始執(zhí)行分析了轩勘,因?yàn)檫@里我們選擇的 report-type 是 xcode,這時(shí) oclint 發(fā)現(xiàn)的錯(cuò)誤會(huì)直接在 IDE 中標(biāo)示出來(lái)怯邪,方便我們對(duì)代碼進(jìn)行改進(jìn)绊寻。


Travis CI

Travis CI 大家應(yīng)該都很熟悉,它的配置也很簡(jiǎn)單擎颖,在工程目錄下添加 .travis.yml文件即可榛斯。
所以我們?cè)?.travis.yml
中配置如下的內(nèi)容即可:

language: objective-c

osx_image: xcode8.0

before_install:

- brew cask uninstall oclint

- brew tap oclint/formulae

- brew install oclint

script:

- xcodebuild -workspace LPDLogger.xcworkspace -configuration Debug -scheme LPDLogger-Example build | xcpretty -r json-compilation-database -o compile_commands.json

- oclint-json-compilation-database

我們對(duì)這個(gè)文件做一下分析:

  • 首先,language 設(shè)置為 objective-c 搂捧,osx_image 設(shè)置為 xcode8.0

  • 然后before_install 所做的事情就是安裝 oclint驮俗。

  • 最后 script 所做的事情就是對(duì)代碼做 oclint。

Jenkins CI

相比 Travis CI允跑,Jenkins CI 提供了更友好的界面來(lái)進(jìn)行 oclint 的配置和報(bào)告展示王凑。

 注:這個(gè)部分筆者還沒(méi)有親自實(shí)踐,所以主要還是把官方的英文文檔用中文的方式表述一遍聋丝。

建立持續(xù)集成的工程

首先索烹,創(chuàng)建一個(gè) free-style 的項(xiàng)目:


設(shè)置持續(xù)集成項(xiàng)目所需要的一些步驟:


配置 OCLint 和 PMD 插件

新建一個(gè)類型為 Execute shell 的 build step:



然后配置 oclint 的指令,這里有幾個(gè)注意點(diǎn):

  • 先添加生成 compile_commands.json 指令弱睦。

  • 在某些情況下百姓,oclint 指令比 oclint-json-compilation-database 指令好用。

  • 設(shè)置 report-type 為 pmd况木。

  • 設(shè)置輸出文件名垒拢,接下來(lái)我們還需要用到這個(gè)名字。

新建一個(gè)類型為 Publish PMD analysis results的 post-build action火惊。


然后輸入剛才輸出的文件名求类。

執(zhí)行分析

然后我們就可以開始進(jìn)行分析了,分析結(jié)束之后我們就可以通過(guò) PMD Warnings
來(lái)查看各個(gè)規(guī)則相應(yīng)的報(bào)錯(cuò)數(shù)了屹耐。


結(jié)語(yǔ)

至此 OCLint 的介紹以及集成都已經(jīng)完成了尸疆,大家有興趣的話也可以在自己的開源項(xiàng)目中實(shí)踐一下,總的來(lái)說(shuō)還是比較簡(jiǎn)單的。下一篇文章應(yīng)該是 Cocoapods 庫(kù)發(fā)布相關(guān)的一些內(nèi)容寿弱,敬請(qǐng)期待……

參考資料

官方文檔:oclint-docs.readthedocs.io/en/stable/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末犯眠,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子症革,更是在濱河造成了極大的恐慌阔逼,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件地沮,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡羡亩,警方通過(guò)查閱死者的電腦和手機(jī)摩疑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)畏铆,“玉大人雷袋,你說(shuō)我怎么就攤上這事〈蔷樱” “怎么了楷怒?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)瓦灶。 經(jīng)常有香客問(wèn)我鸠删,道長(zhǎng),這世上最難降的妖魔是什么贼陶? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任刃泡,我火速辦了婚禮,結(jié)果婚禮上碉怔,老公的妹妹穿的比我還像新娘烘贴。我一直安慰自己,他們只是感情好撮胧,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布桨踪。 她就那樣靜靜地躺著,像睡著了一般芹啥。 火紅的嫁衣襯著肌膚如雪锻离。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天叁征,我揣著相機(jī)與錄音纳账,去河邊找鬼。 笑死捺疼,一個(gè)胖子當(dāng)著我的面吹牛疏虫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼卧秘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼呢袱!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起翅敌,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤羞福,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后蚯涮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體治专,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年遭顶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了张峰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡棒旗,死狀恐怖喘批,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情铣揉,我是刑警寧澤饶深,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站逛拱,受9級(jí)特大地震影響敌厘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜朽合,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一额湘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧旁舰,春花似錦锋华、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至磺樱,卻和暖如春纳猫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背竹捉。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工芜辕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人块差。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓侵续,卻偏偏與公主長(zhǎng)得像倔丈,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子状蜗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容