【C++】统计代码覆盖率(二)分析

虾米哥 阅读:119 2021-09-07 18:00:53 评论:0
本文章主要介绍了【C++】统计代码覆盖率(二),具有不错的的参考价值,希望对您有所帮助,如解说有误或未考虑完全的地方,请您留言指出,谢谢!

嗷嗷嗷!!!好激动,我好蠢。不过最后还是解决了。呜呜呜

有些都是东一块西一块查的,如果有侵权欢迎私信我,我注明出处。

一 gcov&CMake

昨天试了下测试代码和被测代码都是c++的情况,直接编译生成gcno文件,再一运行,生成gcda文件。脚本统计,blingbling生成了报表,简直漂亮!

不过我们的工程比较大= =。编译时也需要很多依赖文件。

因此使用场景为:在机器A目录编译,拷贝纯bin文件到B目录上运行。编译方式为CMake

1 修改编译脚本

  • 找到CMakeList.txt文件,添加如下内容:
  • # coverage option 
    OPTION (ENABLE_COVERAGE "Use gcov" OFF) 
    MESSAGE(STATUS ENABLE_COVERAGE=${ENABLE_COVERAGE}) 
    IF(ENABLE_COVERAGE) 
        SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") 
        SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
    # 其中
    -fprofile-arcs 用来生成 gcno 文件; -ftest-coverage 用来在统计时生成 gcda 文件
    # SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") ENDIF()
  • 编译时使用命令如下:
    cmake -DENABLE_COVERAGE=ON ..
  • 编译后查看文件目录:build一路向下
  • ******/build/CMakeFiles/ad_server.dir/src 
    $ll 
    -rw-rw-r-- 1 mobdev mobdev 1431748 Jun 22 18:24 A.cpp.gcno 
    -rw-rw-r-- 1 mobdev mobdev 2138256 Jun 22 18:24 A.cpp.o 
    -rw-rw-r-- 1 mobdev mobdev  314180 Jun 22 18:25 B.cpp.gcno 
    -rw-rw-r-- 1 mobdev mobdev  871944 Jun 22 18:25 B.cpp.o 
    -rw-rw-r-- 1 mobdev mobdev 2053332 Jun 22 18:25 C.cpp.gcno 
    -rw-rw-r-- 1 mobdev mobdev 3931584 Jun 22 18:25 C.cpp.o 
    -rw-rw-r-- 1 mobdev mobdev 1063036 Jun 22 18:24 D.cpp.gcno 
    -rw-rw-r-- 1 mobdev mobdev 3280472 Jun 22 18:24 D.cpp.o
  • 如上表示编译成功

2 拷贝bin文件到目录B,注意保持目录B与目录A的为同一次编译结果(我是检查md5文件)

   如果是从机器A到机器B,注意配置gcov_prefix交叉编译。

3 启动你的服务,按原方式执行测试用例。case执行完成后进入下一步

4 生成gcda文件。vim test.sh,内容如下:

  • #!/bin/sh 
    SERVER_NAME=$1 
     
    pid=`ps -ef | grep $SERVER_NAME | grep -v "grep" | awk '{print $2}'` 
    echo $pid 
    gdb -q attach $pid <<__EOF__ 
    p __gcov_flush() 
    __EOF__

    执行命令:sh test.sh your_servername

5 检查:因为这次我的编译和测试在同台机器的不同目录,因为gcda文件会生成到编译时的gcno同目录,检查其中已有gcda文件。如下:

  • ******/build/CMakeFiles/ad_server.dir/src 
    $ll 
    -rw-rw-r-- 1 mobdev mobdev   71772 Jun 22 18:55 A.cpp.gcda 
    -rw-rw-r-- 1 mobdev mobdev 1431748 Jun 22 18:24 A.cpp.gcno 
    -rw-rw-r-- 1 mobdev mobdev 2138256 Jun 22 18:24 A.cpp.o 
    -rw-rw-r-- 1 mobdev mobdev   18452 Jun 22 18:55 B.cpp.gcda 
    -rw-rw-r-- 1 mobdev mobdev  314180 Jun 22 18:25 B.cpp.gcno 
    -rw-rw-r-- 1 mobdev mobdev  871944 Jun 22 18:25 B.cpp.o   

二 生成html页面 

进入gcda和gcno文件所在目录,执行 
lcov -c -o result.info  -b . -d .    //生成info文件 
genhtml result.info -o Report   //生成html文件 
tar cvf Report.tar.gz Report     //压缩文件 
sz Report.tar.gz                      //下载到windows系统 
解压打开其中的index.html即可看到测试代码覆盖率

三 生成xml报告

1 安装gcovr

cd /usr/local 
wget https://github.com/gcovr/gcovr/archive/3.2.tar.gz 
tar -xvf 3.2.tar.gz 
cd gcovr-3.2/scripts 
cp gcovr /usr/bin

2 在编译路径下执行 gcovr -r .即可查看覆盖率情况

3 为了使其生成Cobertura可用的xml文件,可以使用命令

gcovr -r .  --output yourdir/coverage.xml  -xml-pretty
vim coverage.xml即可看到xml报告

四 问题

1 描述:无法生成gcda文件

  原因如下:

  • 用户代码调用 exit 正常结束时,gcov_exit 函数得到调用,其继续调用 __gcov_flush 函数输出统计数据到 *.gcda 文件中
  • 若用户进程并非调用 exit 正常退出,覆盖率统计数据就无法输出,也就无从生成报告了。后台服务程序若非专门设计,一旦启动就很少主动退出,用 kill 杀死进程强制退出时就不会调用 exit,因此没有覆盖率统计结果产生。

  解决:执行(一)4步骤即可。

2 描述:无法组合gcda和gcno文件:"stamp mismatch with notes file"

   原因如下:

  • 网上找了好多答案,说是编译版本不一致,导致时间戳不一致,我一直没有理解。
  • 确认自己这儿是因为生成gcno文件的编译版本和生成gcda文件的版本不一致。
  • 我的操作: 
    1 编译二进制文件ad.server,生成了gcno文件 
    2 拷贝ad.server进测试环境,测试生成了gcda 
    3 中途又编译了一次ad.server,生成了新的gcno文件. 
    即gcno和gcda文件使用的ad.server并不是同一次编译的结果。 
    最后通过对比两个地方的ad.server的md5发现了不同,我好蠢= =

    解决:解决很简单,确保你的版本就ok了,可以对比二进制文件的md5.

    查看时间戳:hexdump -e '"%x\n"' -s8 -n4  A.cpp.gcno 可以看到时间戳。

                     hexdump -e '"%x\n"' -s8 -n4  A.cpp.gcda 可以看到时间戳

3 描述:想要让gcda文件生成在指定目录

   场景:有时候是在机器A编译,机器B运行,这种情况就会不能生成gcda文件,提示找不到目录

   解决:gcov的交叉编译 

   操作如下:

  • vim /etc/profile 进行配置
  • export GCOV_PREFIX="/data/ad_server/ad_server.dir"  //gcda的目标路径 
    export GCOV_PREFIX_STRIP=9  //向上数你的路径到需要配置的那个 
     
    比如我的编译路径是/data/code/adserver/6/5/4/3/2/*.gcno,我就设置了9,应该也可以设置export GCOV_PREFIX_STRIP=999等很大然后配置全路径,我没试
  • source /etc/profile  使其生效
  • 重启服务进程
  • 执行测试代码,exit()退出,查看profile的设置路径,已经有gcda文件
  • 拷贝gcno文件到gcda路径,统计代码覆盖率
  • blingbling的就大功告成了!

我的问题:配置了n久该路径一直不生效,最后要哭了。今天偶然发现需要重启进程,忧伤极了

4 描述:无法使用gcovr生成覆盖率--得到的覆盖率为0%

$gcovr -r . 
------------------------------------------------------------------------------ 
                           GCC Code Coverage Report 
Directory: . 
------------------------------------------------------------------------------ 
File                                       Lines    Exec  Cover   Missing 
------------------------------------------------------------------------------ 
------------------------------------------------------------------------------ 
TOTAL                                          0       0    --% 
------------------------------------------------------------------------------

  解决:执行gcovr -r .在编译的大路径下即可,或者在执行时指定source 路径 如 gcovr -r /home/test/mytest/XXXX/

        目录不对,只有gcda和gcno、cpp.o文件无法生成覆盖率,需要源码--猜测

5 描述:使用 --remove 后未在指定路径看到 -o 后的新的 info 文件

  解决:实际生成了,使用命令 find / -name "new_file.info" 发现在根目录下,不知道为什么会这样,使用时更新为 指定绝对路径 就 ok 了


标签:C++
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

发表评论
搜索
KIKK导航

KIKK导航

排行榜
关注我们

一个IT知识分享的公众号