SonarQube安装及配置方法见 CentOS 8 安装 sonarqube 7.9.1 LTS
安装C语言插件
SonarQube的Community版本是不支持对C语言代码进行质量分析的,Developer及以上付费版本才支持。还好有一些开源的社区插件支持,比较著名的一个就是sonar-cxx。
在如下地址下载SonarQube开源C和C++的插件
C插件:sonar-c-plugin-1.3.1.1807.jar
https://github.com/SonarOpenCommunity/sonar-cxx/releases/download/cxx-1.3.1/sonar-c-plugin-1.3.1.1807.jar
C++插件:sonar-cxx-plugin-1.3.1.1807.jar
https://github.com/SonarOpenCommunity/sonar-cxx/releases/download/cxx-1.3.1/sonar-cxx-plugin-1.3.1.1807.jar
将下载下来的插件放到SonarQube的安装目录中的extensions/plugins中
1 2 3 4 5 6 7 8 9 | [sonar@localhost plugins]$ pwd # 写这个文档用的SonarQube环境的安装目录为/opt/sonarqube-7.9.1 /opt/sonarqube-7.9.1/extensions/plugins [sonar@localhost plugins]$ ls -lh total 103M -rw-r--r--. 1 sonar sonar 224 Jul 10 12:21 README.txt -rw-r--r--. 1 sonar sonar 8.1M Dec 9 17:45 sonar-c-plugin-1.3.1.1807.jar -rw-r--r--. 1 sonar sonar 8.1M Dec 9 17:46 sonar-cxx-plugin-1.3.1.1807.jar # 为了节省显示,省略掉了一些输出 |
安装完成后,使用安装目录下/bin/linux-x86-64/sonar.sh脚本重启SonarQube使安装生效。
1 2 3 4 5 6 7 8 9 10 | [sonar@localhost linux-x86-64]$ pwd /opt/sonarqube-7.9.1/bin/linux-x86-64 [sonar@localhost linux-x86-64]$ ./sonar.sh restart Gracefully stopping SonarQube... Waiting for SonarQube to exit... Waiting for SonarQube to exit... Stopped SonarQube. Starting SonarQube... Started SonarQube. [sonar@localhost linux-x86-64]$ |
重启完成后,登录SonarQube页面,在“质量配置”页面中可以看到增加了关于C和C++的质量配置(Profile),如下所示:
需要注意,因Sonar way为内建不可更改的质量规则,即使安装了C和C++的插件,关于C和C++的代码规则都还是0,需要新建C和C++的质量规则。另外,从右侧的侧栏可以看到安装完C和C++的插件后,新增了13K的未激活的规则。
设置C语言配置
在"质量配置"页面,点击右上角的“创建”按钮,创建新的C语言的配置,在弹出的对话框中输出配置名称,如C-Profile, 语言选择C(Community)。
创建完成后,在"质量配置"页面,可以看到新创建的C语言配置和已有的Sonar way配置,默认配置为Sonar way, 两个配置的规则数都为0。先将新建的C-Profile设置为默认配置:
设置完成后,在“质量配置”页面可以看到C语言的配置规则为C-Profile:
接下来需为为C-Profile填加规则。C-Profile右侧的设置按钮有”激活更多规则“命令,点击它。
在弹出的"代码规则"页面,使用"批量修改"命令里面的"活动..."在弹出的对话框里选择新创建的C-Profile,点击“应用”。
完成后,在“质量配置”页面,可以看到C-Profile的规则数的变化:
到此C语言的质量配置已经完成,可以创建项目对C语言工程进行质量检查了。
创建项目
在"项目"页面右上角的"+"按钮中有“创建新的项目”命令,如果没有创建过项目,在页面中间也有“创建新项目”按键,使用任一方法进行项目创建的页面:
在"创建新项目"页面输入"项目标识"和”显示名“点击“设置”按钮进入项目页面。
在项目页面,按照步骤提示,第1步需要创建项目的令牌。项目令牌用于项目分析中的认证,可以避免使用用户名和密码。
令牌创建完成后,第2步需要设置被分析代码的语言,有"Java", "C# 或 VB.NET", "其它(JS, Python, PHP ...)"三个选项,C语言项目选择 "其它(JS, Python, PHP ...)"。
然后选择代码分析工具运行的操作系统。SonarQube不要求代码分析与SonarQube服务器在同一个机器或系统上,可以在其它机器上使用sonar-scanner进行代码分析,sonar-scanner会自动将分析结果传到SonarQube服务器中。
接下来,如果没有扫描器,即sonar-scanner工具,需要先下载他,使用页面中的下载按钮即可下载。在下载页面有相应的安装说明,参考它安装即可。
最后,需要将执行sonar-scanner的命令复制下来,以便在进行代码分析时使用。
使用SonarQube进行代码分析
创建需要进行质量分析的代码,如果已有代码可以跳过这步。本文使用如下代码进行验证:
1 2 3 4 5 6 | [bfx@vFedora sonar-test]$ ls -lh 总用量 12K -rw-rw-r-- 1 bfx bfx 341 12月 2 14:22 example.c -rw-rw-r-- 1 bfx bfx 1.1K 12月 2 15:15 example-utest.c -rw-rw-r-- 1 bfx bfx 482 12月 2 14:59 SConstruct [bfx@vFedora sonar-test]$ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | /** * example.c * 测试示例代码 * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef UTEST extern void utest(); #endif /** * CUint单元测试被测示例函数 */ int func1(int a){ if (a > 200){ return 1; }else{ return 2; } } /** * SonarQube代码质量分析示例函数 * 返回临时变量的地址,用来检查SonarQube是否正常工作 */ char *func2(void){ char *name[256]; return name; } int main(){ printf("Hello "); #ifdef UTEST utest(); #endif return 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | /** * example-utest.c * 单元测试示例代码 * */ #include <stdio.h> #include <stdlib.h> #include <CUnit/CUnit.h> #include <CUnit/Automated.h> extern int func1(int a); /** * CUnit单元测试用例 */ void test_func1_case1(void){ CU_ASSERT(func1(0) == 1); } /** * CUnit单元测试用例 */ void test_func1_case2(void){ CU_ASSERT(func1(100) == 2); } /** * CUnit单元测试套件初始化函数 */ int suit_init(void){ return 0; } /** * CUnit单元测试套件退出函数 */ int suit_clean(void){ return 0; } /** * 单元测试入口 */ void utest(void){ CU_ErrorCode ret; CU_pSuite suit; CU_pTest test; /* 注册CUnit单元测试组件*/ ret = CU_initialize_registry(); if (ret != CUE_SUCCESS){ printf("Regist unit test failed! "); exit(-1); } /* 添加单元测试套件*/ suit = CU_add_suite("Sonar-Test", suit_init, suit_clean); if (suit == NULL){ printf("Add suit failed! "); exit(-1); } /* 添加单元测试用例*/ test = CU_add_test(suit, "Test Case1", test_func1_case1); if (test == NULL){ printf("Add test failed! "); exit(-1); } /* 添加单元测试用例*/ test = CU_add_test(suit, "Test Case2", test_func1_case2); if (test == NULL){ printf("Add test failed! "); exit(-1); } /* 设置单元测试用例结果输出到文件*/ CU_set_output_filename("CUnit-example.xml"); /* 将测试用例输出到文件*/ CU_list_tests_to_file(); /* 运行测试用例*/ CU_automated_run_tests(); return; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # SConstruct # 基于Scons的编译脚本 # 编译Release版本,用于程序正常发布 release = Environment() robj = release.Object("example-r", "example.c") rbin = release.Program("example", robj) # 默认编译Release版本 Default(rbin) # 编译单元测试版本,用于测试目的。 utest = Environment(LIBS = ['cunit'], CCFLAGS = ['-fprofile-arcs', '-ftest-coverage','-DUTEST'], LINKFLAGS = ['-fprofile-arcs', '-ftest-coverage'] ) utobj = utest.Object("example-ut", "example.c") utobj += utest.Object("example-utest.c") utbin = utest.Program("example-ut", utobj) |
说明:本文使用CUint单元测试的示例代码及scons编译脚本,仅是因为手头正好有一套这样的代码,SonarQube与CUnit和scons无任何关系
开源的SonarQube C和C++插件本身没有代码分析的功能,仅对分析结果进行解析及显示,需要使用cppcheck进行代码分析。另外,需要在项目中设置cppcheck结果的保存位置:
在“项目”->项目名称->“配置”->"(2) Code analysis"->"Cppcheck report(s)"中输出cppcheck检查结果的文件, 如cppcheck.xml, 保存。
在源代码目录运行cppcheck并将结果保存到XML文件中,如下:
1 2 3 4 5 6 7 | [bfx@vFedora sonar-test]$ cppcheck --enable=all --xml-version=2 ./ 2>cppcheck.xml Checking example-utest.c ... 1/2 files checked 75% done Checking example.c ... Checking example.c: UTEST... 2/2 files checked 100% done [bfx@vFedora sonar-test]$ |
在代码目录运行在项目创建时复制的sonar-scanner命令,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | [bfx@vFedora sonar-test]$ ls example.c example-utest.c SConstruct [bfx@vFedora sonar-test]$ sonar-scanner > -Dsonar.projectKey=C-Test > -Dsonar.sources=. > -Dsonar.host.url=http://172.17.7.166:9000 > -Dsonar.login=65d0fadd90121b65a8448dd03b7ea6abccb801c2 INFO: Scanner configuration file: /opt/sonar-scanner-4.2.0.1873-linux/conf/sonar-scanner.properties INFO: Project root configuration file: NONE # 为了节省显示,省略掉了一些输出 INFO: Load active rules (done) | time=9449ms WARN: SCM provider autodetection failed. Please use "sonar.scm.provider" to define SCM of your project, or disable the SCM Sensor in the project settings. INFO: Indexing files... INFO: Project configuration: INFO: ------------------------------------------------------------------------ INFO: EXECUTION FAILURE INFO: ------------------------------------------------------------------------ INFO: Total time: 13.845s INFO: Final Memory: 5M/20M INFO: ------------------------------------------------------------------------ ERROR: Error during SonarQube Scanner execution ERROR: Language of file 'example-utest.c' can not be decided as the file matches patterns of both sonar.lang.patterns.c++ : **/*.cxx,**/*.cpp,**/*.cc,**/*.c,**/*.hxx,**/*.hpp,**/*.hh,**/*.h and sonar.lang.patterns.c : **/*.c,**/*.h ERROR: ERROR: Re-run SonarQube Scanner using the -X switch to enable full debug logging. [bfx@vFedora sonar-test]$ |
运行到最后会报错,错误原因是不能决定使用sonar.lang.patterns.c++还是使用sonar.lang.patterns.c解析.c文件。这是因为前面安装的sonar-c-plugin和sonar-cxx-plugin插件都有对.c和.h扩展名的设置,因为我们分析的是C语言工程,可以将sonar-cxx-plugin的配置去掉,如下:
去掉后重新运行sonar-scanner命令如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | [bfx@vFedora sonar-test]$ sonar-scanner > -Dsonar.projectKey=C-Test > -Dsonar.sources=. > -Dsonar.host.url=http://172.17.7.166:9000 > -Dsonar.login=65d0fadd90121b65a8448dd03b7ea6abccb801c2 INFO: Scanner configuration file: /opt/sonar-scanner-4.2.0.1873-linux/conf/sonar-scanner.properties INFO: Project root configuration file: NONE INFO: SonarQube Scanner 4.2.0.1873 # 为了节省显示,省略掉了一些输出 INFO: Turn debug info on to get more details (sonar-scanner -X -Dsonar.verbose=true ...). INFO: Analysis total time: 14.121 s INFO: ------------------------------------------------------------------------ INFO: EXECUTION SUCCESS INFO: ------------------------------------------------------------------------ INFO: Total time: 16.078s INFO: Final Memory: 6M/30M INFO: ------------------------------------------------------------------------ [bfx@vFedora sonar-test]$ |
运行成功后,可以在SonarQube的"项目"页面查看运行的结果:
SonarQube C语言的代码覆盖率
从上面的运行结果可以看到项目的覆盖率为0%. 其实可以借助lconv和gconvr使SonarQube跟踪代码运行的覆盖率。
要生产覆盖率的数据,需要要编译和链接时进行如下设置:
编译时:增加-fprofile-arcs -ftest-coverage或–coverage,
链接时:增加 -fprofile-arcs 或者 –lgcov。
打开–g3 选项,去掉-O2以上级别的代码优化选项;否则编译器会对代码做一些优化,例如行合并,从而影响行覆盖率结果;
如在我们前面的示例代码的编译:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | [bfx@vFedora sonar-test]$ gcc -o example-ut -fprofile-arcs -ftest-coverage -DUTEST -g3 -lcunit example.c example-utest.c example.c: 在函数‘func2’中: example.c:30:12: 警告:returning ‘char **’ from a function with incompatible return type ‘char *’ [-Wincompatible-pointer-types] 30 | return name; | ^~~~ example.c:30:12: 警告:函数返回局部变量的地址 [-Wreturn-local-addr] [bfx@vFedora sonar-test]$ ls -lh 总用量 112K -rw-rw-r-- 1 bfx bfx 1.4K 12月 9 20:43 cppcheck.xml -rw-rw-r-- 1 bfx bfx 512 12月 9 20:13 example.c -rw-rw-r-- 1 bfx bfx 952 12月 10 10:52 example.gcno -rwxrwxr-x 1 bfx bfx 88K 12月 10 10:52 example-ut -rw-rw-r-- 1 bfx bfx 1.6K 12月 9 20:20 example-utest.c -rw-rw-r-- 1 bfx bfx 2.9K 12月 10 10:52 example-utest.gcno -rw-rw-r-- 1 bfx bfx 496 12月 9 20:24 SConstruct [bfx@vFedora sonar-test]$ |
可以看到编译生成的可执行文件及用户生成覆盖率数据的*.gcno文件。
运行./example-ut 测试程序,运行结束后,会针对所有的源代码文件产生相应的*.gcda文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | [bfx@vFedora sonar-test]$ ./example-ut Hello [bfx@vFedora sonar-test]$ ls -lh 总用量 128K -rw-rw-r-- 1 bfx bfx 1.4K 12月 9 20:43 cppcheck.xml -rw-rw-r-- 1 bfx bfx 1.8K 12月 10 10:57 CUnit-example.xml-Listing.xml -rw-rw-r-- 1 bfx bfx 1.8K 12月 10 10:57 CUnit-example.xml-Results.xml -rw-rw-r-- 1 bfx bfx 512 12月 9 20:13 example.c -rw-rw-r-- 1 bfx bfx 164 12月 10 10:57 example.gcda -rw-rw-r-- 1 bfx bfx 952 12月 10 10:52 example.gcno -rwxrwxr-x 1 bfx bfx 88K 12月 10 10:52 example-ut -rw-rw-r-- 1 bfx bfx 1.6K 12月 9 20:20 example-utest.c -rw-rw-r-- 1 bfx bfx 364 12月 10 10:57 example-utest.gcda -rw-rw-r-- 1 bfx bfx 2.9K 12月 10 10:52 example-utest.gcno -rw-rw-r-- 1 bfx bfx 496 12月 9 20:24 SConstruct [bfx@vFedora sonar-test]$ |
使用gconvr生成XML格式的覆盖率报告,开源SonarQube C语言插件sonar-c-plugin需要使用XML格式的覆盖率报告,这可能与付费版本的不同。
sonar-c-plugin关于覆盖率跟踪的WIKI描述如下,链接:https://github.com/SonarOpenCommunity/sonar-cxx/wiki/Coverage-tracers
SonarQube官方CFamily的设置如下,链接
https://docs.sonarqube.org/latest/analysis/coverage/
生成覆盖率报告:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | [bfx@vFedora sonar-test]$ gcovr -r ./ -x --object-directory=$(pwd) > report.xml [bfx@vFedora sonar-test]$ ls -lh 总用量 132K -rw-rw-r-- 1 bfx bfx 1.4K 12月 9 20:43 cppcheck.xml -rw-rw-r-- 1 bfx bfx 1.8K 12月 10 10:57 CUnit-example.xml-Listing.xml -rw-rw-r-- 1 bfx bfx 1.8K 12月 10 10:57 CUnit-example.xml-Results.xml -rw-rw-r-- 1 bfx bfx 512 12月 9 20:13 example.c -rw-rw-r-- 1 bfx bfx 164 12月 10 10:57 example.gcda -rw-rw-r-- 1 bfx bfx 952 12月 10 10:52 example.gcno -rwxrwxr-x 1 bfx bfx 88K 12月 10 10:52 example-ut -rw-rw-r-- 1 bfx bfx 1.6K 12月 9 20:20 example-utest.c -rw-rw-r-- 1 bfx bfx 364 12月 10 10:57 example-utest.gcda -rw-rw-r-- 1 bfx bfx 2.9K 12月 10 10:52 example-utest.gcno -rw-rw-r-- 1 bfx bfx 3.1K 12月 10 11:35 report.xml -rw-rw-r-- 1 bfx bfx 496 12月 9 20:24 SConstruct [bfx@vFedora sonar-test]$ |
设置SonarQube读取覆盖率报告:在"项目"->项目名称->"配置"->"C (Community)"->"(3) Testing & Coverage"->"Unit test coverage report(s)"中输入覆盖率报告的路径:
029 - sonar-coverage-setting.png
运行sonar-scanner工具进行代码分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [bfx@vFedora sonar-test]$ sonar-scanner > -Dsonar.projectKey=C-Test > -Dsonar.sources=. > -Dsonar.host.url=http://172.17.7.166:9000 > -Dsonar.login=65d0fadd90121b65a8448dd03b7ea6abccb801c2 INFO: Scanner configuration file: /opt/sonar-scanner-4.2.0.1873-linux/conf/sonar-scanner.properties INFO: Project root configuration file: NONE # 为了节省显示,省略了部分输出 INFO: Turn debug info on to get more details (sonar-scanner -X -Dsonar.verbose=true ...). INFO: Analysis total time: 14.160 s INFO: ------------------------------------------------------------------------ INFO: EXECUTION SUCCESS INFO: ------------------------------------------------------------------------ INFO: Total time: 16.597s INFO: Final Memory: 6M/30M INFO: ------------------------------------------------------------------------ [bfx@vFedora sonar-test]$ |
在SonarQube项目页面可以看到项目的覆盖率信息,也可以看到每行代码的覆盖率情况: