讓sonar帶著你的C++玩轉devops
來自專欄飛翔眼的小屋
最近一周一直在搞sonar。
越來越喜歡這個東東,眾所周知,sonar本來是Java寫的,對C++的支持一直是有限的。
上一篇文章,說了怎麼讓sonarcloud去聯動travis的C++工程。
但是光靜態檢查代碼實在是太low了。
我想使用它的更高級的功能,那就是代碼覆蓋率,以及對cppunit報告的聯動。
不得不說,這部分耗費了我一周的時間,谷歌上的資料也坑不少,sonar大部分都是Java的項目,C++的項目在github上的例子多數問題也很多。自己一步一個坑摸過來,確實也不容易。不過當一切完成的時候,感覺還是蠻有成就感的。
首先,要說明一下, sonarcloud只支持CFamily插件,額外的擴展插件是不支持的,默認情況下,如果你使用的是自己安裝的sonar伺服器,CFamily插件如果不是giuhub項目是要收費的。這裡推薦你可以使用另一個免費的sonar代碼檢查插件替換之。
這個插件的地址是:
SonarOpenCommunity/sonar-cxx在強調一次,這個插件,不能與sonarcloud聯動,只能安裝於sonar伺服器上,這個插件的好處是可以支持gcovr的xml報告提交,而且對cppunit更友好一些。最關鍵的它是免費的。
因為我的項目在travis上,所以這個東西不能用。
sonarcloud只支持4種格式的代碼覆蓋率報告。他們是gcov,llvm-gcov, Visual Studio Reports和Bullseye。
後三個需要單獨安裝工具,gcov是為了檢測linux的源代碼覆蓋率而原生的。不需要安裝任何其它的組件,一般linux都會默認安裝。
對應CFamily的組件功能介紹,看這裡。
SonarCFamily Coverage Results Import我直接使用的是gcov生成報告,但是有幾步之前的工作要做。
首先,你需要獨立寫一個make文件,無論是Cmake也好,或者mpc也好,甚至是直接自己寫的make也罷,你需要獨立一個makegov文件,不與你的程序編譯混淆,為什麼呢?因為gcov需要在g++編譯裡面擴展參數。這個參數會讓你的程序性能下降和內存變大(因為加入了樁),所以gcov不適合壓測環境和正常環境,所以獨立的一個make gcov很重要。
在你的make gcov編譯選項里添加:
-fprofile-arcs -ftest-coverage
這個選項是用來開啟gcov報告的。
當你的程序編譯完成的時候,你會發現你的.o(程序編譯中間文件)的目錄下,會對應每個.o多了一個.gcno文件。
如果你看到這個,說明第一步你已經成功了。
第二步,就是完整運行你的程序。
這裡注意,不能使用kill -9 或者類似的命令終止程序,一定要讓程序自然退出。如果強行終止程序的話,你的gcba文件是不會生成出來的。
這裡要多說一句,如果我寫的是一個伺服器程序,怎麼合理關閉呢,這裡你需要增加對信號量的抓取,也就是說,你可以用killall XXX的方式關閉你的程序,這時候你的程序會收到一個signal。你處理它讓你的程序合理的關閉即可。(優雅的關閉)
正常的關閉後,你會在你的.o文件夾上看到一些新的文件。這個文件是.gcba,注意,這個文件也是和你的.o一一對應的。
類似這樣:
ConnectClient.o ConnectClient.gcnoConnectClient.gcda
當你看到這些,gcov實際就成功了大半。我的理解是,編譯器生成gcno的文件是你的代碼中所有樁的位置,gcba是程序實際執行到關閉後的,所有的樁被調用的次數記錄。
剩下的,就是使用gcov指令生成對應的代碼覆蓋率報告了。gcov指令會合併gcno和gcba文件生成一個.gcov的文件報告。注意,這裡也是和.o一一對應的。
這裡要強調一點。
gcov指令,必須在你的程序運行目錄運行,在此之外運行都會報找不到文件的錯誤。也就是說,如果比較合理的配置,你的.o會在一個專門的目錄,你的cpp會在另一個專門的目錄。那麼你應該在你的程序運行目錄上運行gcov,切記。
類似這樣:
- gcov -r -o ./.obj ../*.cpp
這裡後面-o 的路徑,和最後源代碼的路徑,都必須是相對於你的可執行文件路徑的相對路徑。
那麼你也許會問,如果我的代碼會有一堆的子目錄(一般比較大的項目,代碼目錄都是嚴格區分的,不會混在一起的,怎麼辦?)
那麼你可以一一指定它們。
例如:
- gcov -r -o ./.obj ../*.cpp - gcov -r -o ./.obj ../Common/*.cpp - gcov -r -o ./.obj ../Console/*.cpp - gcov -r -o ./.obj ../FileTest/*.cpp - gcov -r -o ./.obj ../TinyXML/*.cpp - gcov -r -o ./.obj ../PacketParse/*.cpp - gcov -r -o ./.obj ../LogSystem/*.cpp - gcov -r -o ./.obj ../Message/*.cpp - gcov -r -o ./.obj ../Reactor/*.cpp - gcov -r -o ./.obj ../Mail/*.cpp
這裡要說明的是,我目前還沒有找到直接遍歷子目錄一句話的方式。
我目前使用的是這種比較笨的方式,因為*.cpp只能支持本級別的文件夾,所以有子文件夾的話,要額外指定出來。
好了,生成了所有的gcov文件。我們就需要sonarcloud去接收我們的文件了。
怎麼寫呢?
在你的sonar-project.properties 文件中添加如下行:
sonar.cfamily.gcov.reportsPath=./Linux_Bin
這裡注意,這個路徑是你的gcov文件所在的路徑。
這樣,sonarcloud就可以接收你的代碼覆蓋率報告並展現出來了。
類似這樣:
Loading...你可以點擊你的代碼覆蓋率,查看自己的代碼詳細覆蓋的情況。
那些代碼行在運行過程中,沒有被執行到。
或許你會問,我寫的是伺服器程序,沒法做到完整的全覆蓋呀。
其實這只是一個借口,想做到肯定是可以做到的,那麼下一講,我來說說,怎麼用cppunit來配合你的代碼覆蓋率檢查。
推薦閱讀:
※雲時代的來臨及各種自動化平台的湧現,運維工程師的工作還有價值嗎?
※大洋電機綜合運維監控項目經典案例
※面試時到底在面什麼?
※從 0 開始了解 Docker