背景
gcov是gcc中的一个附带工具,配合GCC编译进行覆盖测试使用
在gcc编译时,使用-fprofile-arcs -ftest-coverage两个编译参数,即可使用gcov的功能
在编译成功后,会生成.gcno文件,文件来自于编译过程中对目标文件打的桩生成的。
对可执行文件进行一次运行,即可得到.gcda文件
最终,用gcov工具对源代码进行处理,得到.gcov文件,即为我们需要的覆盖信息的初试状态
因为gcov生成的是纯文字,不好直观展现,lcov工具就是在gcov的基础上,生成html做了界面化展现。
我们准备在chromium项目(Cronet)中新增gcov单测覆盖率
chromium使用的是Google自研的gn & ninja,前者gn是用于生成类似Makefile的编译文件,后者进行真正的编译,产出对象文件
关于chromium的编译可以参考官方文档:chromium/build-instructions
实现
准备材料:
- lcov 1.10版本
- gcc 4.8.1及以上版本
实现步骤:
在build.gn中添加全局编译参数
|
|
|
|
enable_coverage即为全局gcov开关
编译的时候,
gn args out/default
执行gcov.sh,本地化lcov工具脚本
最终,在out_html下就有我们需要的产出,以html形式。
踩坑点
1.pkg-config could not run
- chromium为了更好支持跨机器,使用了pkg-config这个编译辅助工具,目的是为了快速找到编译依赖包。
- 在配置完gn后,可能会出现xxx.pc无法找到,pkg-config cound not run的错误
solution: - 去了解了一下pkg-config的作用后,明白这个错误其实就是环境变量没有添加好
- 在/usr下找到所有xxx.pc的鬼东西,将其所在目录路径(可能是多个)添加到 export PKG_CONFIG_PATH中去
2.gcc/g++版本请务必使用4.8.1及以上的,为了支持C++11(gcc/g++ 4.6只认识-std=c++0x,这是C++11的早期标识,正式的是-std=gnu++11).
- 如果不升级,会报一堆gcc的运行参数错误
- ps.最开始不知道为啥我机器上4.6版本不支持c++11,后来找了一些资料才知道4.8.1之前的版本只认识早期c++11或者c++0x这种标识,官方推荐的应该是gnu++11,只在gcc 4.8.1开始
3.升级gcc后,可能你的gcov版本还是老版本(比如4.6)通过gcc/gcov -v可以查看版本。但其实你机器上已经存在了gcov-4.8了,可以去/usr/bin下查看
- 如果gcc和gcov版本不一致,在gcov运行阶段,会报版本错误,可能最终能生成html,但覆盖率数据会有问题
solution: - 替换/usr/bin下的gcov,这个gcov仅仅是一个软连接,删除它,新建一个gcov的软连接指向gcov-4.8即可
4.lcov版本问题,1.9版本的会出错
- lcov1.9版本有代码bug(网上可以搜到,包括已经提交到了lcov官方),使用它可能会出现
- geninfo: ERROR: xxx.gcno:reached unexpected end of file
solution: - 使用lcov1.10版本,不会出现这个问题
5.gcov编译参数一定要加全局
cflags = [ “-fprofile-arcs”, “-ftest-coverage” ]这个编译参数一定要加到全局
当时为了节省效率,只对需要产出覆盖率的那部分source代码加上了gcov的编译参数
problem:
- 这样做确实会节省很多时间,主要是在gcov处理方面会很快(只有你加了编译参数的source才会产出.gcno/.gcda文件)
- 但是在真正运行时,会导致所有的ut全部crash
solution: - 直接把编译参数加到全局(黄龑已经写好了,我们只需要打开enable_coverage开关即可)
- 全局后,即便只是编译你的ut模块,但会对所有依赖的source产出gcno和gcda,而且都产出覆盖率
- 编译和gcov处理时间会超过10+分钟(我只是对bdns作为目标产出),如果整体全局,估计会更长
- 这个问题跟gcov本身原理有关,因为它会对代码进行特殊处理,可能是只对一部分代码加编译参数导致整体不一致的情况,ut执行的时候调用了gcov处理过的和没处理过的代码,触发了crash
6.修改代码,重新跑覆盖率时,gcno/gcda文件又出错
solution:
- 最好gn clean一下,重新跑一遍全过程。
- 或者至少清除产出目录下的 .gcno/.gcda文件。
- 还是lcov的bug,如果连续跑覆盖率,不清除上一次产生的gcno/gcda文件,可能又会产生这些文件无法打开或读取的问题。