使用GCOVR统计共享库代码覆盖:无GCNO/GCDA文件生成问题
共享库项目代码覆盖率为空(无.gcno/.gcda文件)的解决方案
问题背景
测试项目包含共享库calculator,运行覆盖率目标时生成的XML为空:
- 共享库未生成
.gcno文件 - 仅单元测试可执行文件生成
.gcno - 完全没有生成
.gcda文件
项目目录结构
ProjectRoot/ |- src/ | |- calculator/ | | |- CMakeLists.txt | | |- Calculator.cpp | | |- Calculator.h | |- CMakeLists.txt | |- sources.cpp | |- sources.h |- tests/ | |- CMakeLists.txt | |- unit-test1.cpp |- CMakeLists.txt
现有CMake配置(关键部分)
根目录CMakeLists.txt
cmake_minimum_required (VERSION 3.14) enable_testing() project("testProject") add_subdirectory("src") if (CMAKE_BUILD_TYPE MATCHES Debug) add_subdirectory("tests") endif()
calculator目录CMakeLists.txt
project("calculator") add_library(${PROJECT_NAME} SHARED "Calculator.h" "Calculator.cpp") if (CMAKE_VERSION VERSION_GREATER 3.12) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) endif()
测试目录CMakeLists.txt
set(UNIT-TESTS "unit-tests") include(CTest) include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG v1.14.0) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) add_executable(${UNIT-TESTS} unit-test1.cpp) target_link_libraries(${UNIT-TESTS} GTest::gtest_main calculator) include(GoogleTest) gtest_discover_tests(${UNIT-TESTS}) set(CMAKE_MODULE_PATH /usr/src/CMake) include(CodeCoverage) append_coverage_compiler_flags(${UNIT-TESTS}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0") set(GCOVR_PATH "/usr/bin/gcovr") setup_target_for_coverage_gcovr_xml( NAME CoverageXml EXECUTABLE ${UNIT-TESTS} DEPENDENCIES ${UNIT-TESTS} EXECUTABLE_ARGS "--gtest_output=xml:report/" EXCLUDE "out/" "tests/")
编译命令
cmake -S ./ -B ./out/build/ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang-16 -DCMAKE_CXX_COMPILER=clang++-16 cmake --build ./out/build/ --parallel 2 --target CoverageXml unit-tests
解决方案(保留共享库架构)
问题核心是共享库未添加覆盖率编译/链接参数,导致无法生成.gcno和.gcda文件。以下是具体修改:
1. 给共享库添加覆盖率编译选项
修改src/calculator/CMakeLists.txt,在Debug模式下为共享库添加覆盖率flags并关闭优化:
project("calculator") add_library(${PROJECT_NAME} SHARED "Calculator.h" "Calculator.cpp") if (CMAKE_VERSION VERSION_GREATER 3.12) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) endif() # 仅在Debug模式下添加覆盖率配置 if (CMAKE_BUILD_TYPE MATCHES Debug) # 导入CodeCoverage模块 set(CMAKE_MODULE_PATH /usr/src/CMake) include(CodeCoverage) # 为共享库添加覆盖率编译/链接flags append_coverage_compiler_flags(${PROJECT_NAME}) # 强制关闭优化,避免覆盖率统计失真 target_compile_options(${PROJECT_NAME} PRIVATE -O0) endif()
2. 优化测试目录的覆盖率配置
修改tests/CMakeLists.txt,确保覆盖率目标能正确扫描共享库的编译产物:
# ... 其他内容不变 ... include(CodeCoverage) # 为测试可执行文件添加覆盖率flags append_coverage_compiler_flags(${UNIT-TESTS}) # 为测试程序关闭优化 target_compile_options(${UNIT-TESTS} PRIVATE -O0) set(GCOVR_PATH "/usr/bin/gcovr") setup_target_for_coverage_gcovr_xml( NAME CoverageXml EXECUTABLE ${UNIT-TESTS} DEPENDENCIES ${UNIT-TESTS} calculator # 依赖共享库,确保先编译共享库 EXECUTABLE_ARGS "--gtest_output=xml:report/" EXCLUDE "out/" "tests/" BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src" # 指定源码根目录,帮助gcovr找到文件 )
3. 验证编译与运行
重新执行编译命令,此时:
- 共享库
calculator会生成对应的.gcno文件 - 运行测试后会生成
.gcda文件 - CoverageXml目标会生成包含共享库代码的覆盖率XML报告
关键原理
- 覆盖率统计需要编译时添加
-fprofile-arcs -ftest-coverage(GCC)或对应Clang参数,这些由append_coverage_compiler_flags自动添加 - 共享库和测试程序必须都启用这些参数,否则无法收集共享库的执行数据
- 优化级别
-O0是必须的,否则编译器会优化掉部分代码,导致覆盖率统计不准确
内容的提问来源于stack exchange,提问作者wes
相关产品推荐
相关产品推荐

