必须加-g -o0 --coverage,缺一不可;-g确保源码行号可见,-o0防止优化干扰统计,--coverage等价于-fprofile-arcs和-ftest-coverage;未运行测试则无.gcda,lcov无法捕获数据;.gcda默认生成在.o所在目录,需在build目录执行lcov --capture;过滤须用-r排除系统头文件及第三方路径;genhtml生成报告后直接打开index.html查看。

编译时必须加 -g -O0 --coverage,缺一不可
不加 -g 会导致 lcov 找不到源码行号,报告全是“no data”;开优化(比如 -O2)会让代码被内联或删减,覆盖率统计错位甚至崩溃。实际项目中常有人只加 --coverage 就跑,结果生成的 .gcda 文件为空或无法合并。
推荐编译命令示例:
g++ -g -O0 --coverage -std=c++17 test.cpp -o test
注意:--coverage 等价于 -fprofile-arcs -ftest-coverage,但直接写前者更清晰;CMake 用户需在 CMAKE_CXX_FLAGS 和 CMAKE_EXE_LINKER_FLAGS 中都加入该标志。
lcov 提取数据前要先运行测试程序
没执行带 --coverage 编译出来的可执行文件,就不会生成 .gcda 文件,lcov -c 就只能扫到空数据。常见错误是只编译、不运行,或者运行了但工作目录不对,导致 .gcda 写在别处。
- 确保测试程序运行完毕且正常退出(非 crash 或 kill)
-
.gcda默认生成在目标文件(.o)所在目录,不是源码目录,也不在可执行文件目录 - 若用 CMake + out-of-source build,
.gcda会出现在build/CMakeFiles/xxx.dir/下,不是src/
提取命令示例(假设源码在 ./src):
lcov -d . -c -o coverage_base.info
其中 -d . 表示从当前目录递归找 .gcda,不是指源码根目录。
过滤掉头文件、第三方代码和无关路径
默认 lcov 会把所有扫描到的 .gcda 对应源码都计入,包括系统头文件(如 /usr/include/c++)、测试框架代码(如 catch2.hpp),导致覆盖率虚高或报告臃肿。
必须用 -r 排除,且顺序很重要:先 -c 提取,再 -r 过滤,最后 -a 合并(如有多个测试):
lcov -r coverage_base.info '/usr/*' '*/test/*' '*/third_party/*' '*/include/*' -o coverage_filtered.info
注意:-r 的路径模式是 shell glob,不是正则;*/include/* 能匹配 build/_deps/... 下的头文件,但写成 /include/* 就无效。
生成 HTML 报告后打开 index.html 即可查看
genhtml 是 lcov 自带工具,不依赖浏览器服务,但输出目录不能和源码同名(否则可能覆盖源文件),也不建议放在构建目录里(容易被 make clean 清掉)。
典型命令:
genhtml coverage_filtered.info -o coverage_report
生成后直接用浏览器打开 coverage_report/index.html。如果点进某个文件显示 “No data found”,大概率是路径没对上——检查 lcov -l coverage_filtered.info 看它记录的源文件路径是否和磁盘一致,尤其注意相对路径、符号链接、构建目录层级差异。
真正容易卡住的地方不在生成步骤,而在路径映射:.gcno/.gcda 记录的是编译时的绝对路径,而你本地源码位置变了,genhtml 就找不到对应文件。解决办法是用 lcov --remove <code>coverage_filtered.info 'wrong/path/*' -o fixed.info 临时修正,或统一用 CMake 的 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -fprofile-abs-path")(GCC 9+ 支持)避免路径漂移。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











