gcovr 使用方式及参数说明
gcovr 是基于 gcov 的覆盖率报告工具。它可以直接生成文本、HTML、XML、Cobertura、SonarQube 等格式,常用于 CI,因为命令相对简洁。
gcovr 与 lcov 的区别
| 工具 | 特点 |
|---|---|
| lcov + genhtml | 经典组合,HTML 报告清晰,Linux 工程常见 |
| gcovr | 单工具生成多格式报告,CI 集成方便 |
二者都依赖编译器生成覆盖率数据。选择哪一个更多取决于团队习惯和 CI 报告格式要求。
基本命令
gcovr -r . build-coverage
gcovr -r . build-coverage --html --html-details -o coverage.html
gcovr -r . build-coverage --xml-pretty -o coverage.xml
-r . 指定项目根目录。gcovr 会用它决定相对路径,并默认过滤根目录外的文件。
常用参数
| 参数 | 说明 |
|---|---|
-r, --root DIR |
指定源码根目录 |
search_paths... |
指定搜索覆盖率数据的路径,通常传构建目录 |
--filter REGEX |
只包含匹配路径 |
--exclude REGEX |
排除匹配路径 |
--exclude-directories REGEX |
搜索覆盖率数据时跳过匹配目录 |
--gcov-filter REGEX |
只处理匹配的 .gcov 数据文件 |
--gcov-exclude REGEX |
排除匹配的 .gcov 数据文件 |
--gcov-executable CMD |
指定 gcov 命令,例如 gcc-13-gcov 或 llvm-cov gcov |
--gcov-object-directory DIR |
指定 gcov 对象目录,路径推断失败时使用 |
--gcov-ignore-errors TYPE |
忽略 gcov 调用错误 |
--gcov-ignore-parse-errors TYPE |
忽略 gcov 输出解析错误 |
--keep |
保留 gcovr 生成的中间 .gcov 文件 |
--delete |
处理后删除输入覆盖率数据文件 |
--html |
生成 HTML 报告 |
--html-details |
生成带源码详情的 HTML 报告 |
--html-title TITLE |
设置 HTML 报告标题 |
--html-theme THEME |
设置 HTML 主题,具体可用值取决于 gcovr 版本 |
--xml |
生成 Cobertura XML |
--xml-pretty |
生成格式化 XML |
--json |
生成 JSON |
--json-summary |
生成 JSON 摘要 |
--csv |
生成 CSV 摘要 |
--sonarqube |
生成 SonarQube XML |
--coveralls |
生成 Coveralls JSON |
--lcov |
输出 lcov info 格式 |
--txt |
生成文本报告 |
--branches |
启用分支覆盖率 |
--decisions |
启用 decision coverage,具体支持取决于版本 |
--calls |
启用调用覆盖率,具体支持取决于版本和 gcov 数据 |
--print-summary |
打印摘要 |
--fail-under-line N |
行覆盖率低于 N 时返回失败 |
--fail-under-branch N |
分支覆盖率低于 N 时返回失败 |
--fail-under-function N |
函数覆盖率低于 N 时返回失败 |
--config FILE |
从配置文件读取选项 |
--verbose |
输出详细调试信息 |
--version |
输出版本 |
-o FILE |
指定输出文件 |
参数分类
| 目的 | 常用参数 |
|---|---|
| 搜索数据 | search_paths、--root、--gcov-object-directory |
| 过滤源码 | --filter、--exclude |
| 加速搜索 | --exclude-directories |
| 指定工具链 | --gcov-executable |
| 调试 gcov | --keep、--verbose、--gcov-ignore-errors |
| 输出报告 | --html、--xml-pretty、--json、--csv、--sonarqube |
| 覆盖率门禁 | --fail-under-line、--fail-under-branch、--fail-under-function |
推荐命令
gcovr \
--root . \
build-coverage \
--exclude '.*tests.*' \
--exclude '.*_deps.*' \
--branches \
--html \
--html-details \
--output coverage.html \
--print-summary
CI 中可以设置覆盖率门禁:
gcovr -r . build-coverage \
--branches \
--fail-under-line 80 \
--fail-under-branch 70 \
--xml-pretty \
-o coverage.xml
当覆盖率低于阈值时,gcovr 会返回非零退出码,CI 可以据此失败。
指定 gcov 工具
gcovr 会调用 gcov 把 .gcda、.gcno 转换成可分析数据。如果编译器不是默认 GCC,建议显式指定:
gcovr \
--root . \
build-coverage \
--gcov-executable gcc-13-gcov \
--html --html-details \
--output coverage.html
交叉工具链:
gcovr \
--root . \
build-coverage \
--gcov-executable /opt/toolchain/bin/arm-none-eabi-gcov \
--xml-pretty \
--output coverage.xml
Clang gcov 兼容模式:
gcovr \
--root . \
build-coverage \
--gcov-executable "llvm-cov gcov" \
--html --html-details \
--output coverage.html
--gcov-executable 必须和编译器生成的覆盖率数据格式匹配。gcovr 官方文档也明确建议 Clang 场景使用类似 llvm-cov gcov 的命令。
多格式输出
gcovr 可以一次命令生成一种主要输出。实际脚本中常多次调用 gcovr,分别生成不同格式。
gcovr -r . build-coverage --txt -o coverage.txt
gcovr -r . build-coverage --html --html-details -o coverage.html
gcovr -r . build-coverage --xml-pretty -o coverage.xml
gcovr -r . build-coverage --json -o coverage.json
gcovr -r . build-coverage --csv -o coverage.csv
gcovr -r . build-coverage --sonarqube -o sonarqube.xml
gcovr -r . build-coverage --lcov -o coverage.info
| 输出格式 | 适用场景 |
|---|---|
--txt |
终端查看和日志留存 |
--html --html-details |
本地人工阅读 |
--xml-pretty |
CI 平台 Cobertura 风格解析 |
--json |
自定义工具二次处理 |
--csv |
表格统计 |
--sonarqube |
SonarQube 平台 |
--lcov |
转换为 lcov info 格式 |
CMake 自定义目标示例
find_program(GCOVR_EXECUTABLE gcovr)
if(GCOVR_EXECUTABLE)
add_custom_target(coverage
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
COMMAND ${GCOVR_EXECUTABLE}
--root ${CMAKE_SOURCE_DIR}
${CMAKE_BINARY_DIR}
--exclude ".*tests.*"
--exclude ".*_deps.*"
--branches
--html
--html-details
--output ${CMAKE_BINARY_DIR}/coverage.html
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Running tests and generating gcovr coverage report")
endif()
运行:
cmake --build build-coverage --target coverage
使用配置文件
当参数很多时,可以把 gcovr 选项写入配置文件,减少 CI 脚本长度。
gcovr.cfg 示例:
root = .
filter = src/.*
filter = include/.*
exclude = .*tests.*
exclude = .*_deps.*
branches = yes
print-summary = yes
gcov-executable = gcov
执行:
gcovr --config gcovr.cfg build-coverage --html --html-details -o coverage.html
配置文件适合固定项目规则,命令行参数适合 CI 中临时覆盖输出路径和门禁阈值。
过滤规则
gcovr 的过滤和排除通常使用正则表达式。Windows 路径可能包含反斜杠,跨平台工程中建议让 CMake、gcovr 尽量使用统一根目录,并用较宽松的正则。
| 目标 | 示例 |
|---|---|
| 排除测试目录 | --exclude '.*tests.*' |
| 排除第三方依赖 | --exclude '.*third_party.*' |
| 只包含 src | --filter '.*/src/.*' |
| 排除构建生成文件 | --exclude '.*CMakeFiles.*' |
filter 与 exclude 的区别
--filter 和 --exclude 作用于源码文件路径。常见策略是先用 --filter 限定产品代码目录,再用 --exclude 排除测试和第三方。
gcovr -r . build-coverage \
--filter '.*/src/.*' \
--filter '.*/include/.*' \
--exclude '.*/tests/.*' \
--exclude '.*/third_party/.*'
--exclude-directories 作用于搜索覆盖率数据的目录,可用于加速:
gcovr -r . build-coverage \
--exclude-directories '.*/_deps/.*' \
--exclude-directories '.*/third_party/.*'
如果构建目录很大,先排除第三方和临时目录能明显减少扫描时间。
路径推断失败
gcovr 通常能自动推断 .gcda 文件与源码、对象文件之间的关系。但复杂构建或交叉编译工程中可能失败,此时可以指定对象目录:
gcovr \
--root . \
--gcov-object-directory build-coverage \
build-coverage \
--html --html-details \
--output coverage.html
如果报告为空但 .gcda 文件确实存在,--gcov-object-directory 是优先尝试的参数之一。
排除指定代码片段
gcovr 支持通过源码注释排除某些行或区域。具体标记随版本和配置可能不同,常见思想是用排除标记告诉工具“这段代码不计入覆盖率”。
示例:
void DebugOnlyLog() {
// GCOVR_EXCL_START
if (std::getenv("DEBUG_LOG")) {
std::cerr << "debug log\n";
}
// GCOVR_EXCL_STOP
}
排除标记适合不可达防御分支、平台相关分支、调试辅助代码。不要用它隐藏应该测试的业务逻辑。
CI 门禁示例
gcovr -r . build-coverage \
--branches \
--fail-under-line 80 \
--fail-under-branch 70 \
--fail-under-function 80 \
--xml-pretty \
-o coverage.xml
门禁阈值建议循序渐进。老项目可以先记录当前基线,再要求新增代码不降低覆盖率。
常见问题
| 问题 | 处理 |
|---|---|
| 报告为空 | 确认测试运行后生成 .gcda,并把构建目录传给 gcovr |
| 路径过滤不生效 | 检查正则是否匹配 gcovr 输出中的实际路径 |
| CI 无法解析报告 | 使用 --xml-pretty 或 CI 指定的格式 |
| 分支覆盖率为 0 | 添加 --branches,并确认编译器生成分支数据 |
| gcov 调用失败 | 使用 --gcov-executable 指定匹配工具 |
| 扫描很慢 | 使用 --exclude-directories 排除第三方和大目录 |
| 源码路径解析失败 | 尝试 --gcov-object-directory |
| 偶发解析错误 | 先用 --verbose 和 --keep 保留中间文件排查 |