0

我正在创建一个我计划在未来使用的通用 C++、CMake 和Catch项目模板,并希望为其启用代码覆盖率报告。为此,我决定将以下 CMake 模块添加到我的模块列表中:CodeCoverage.cmake。我对此的使用基本上归结为以下代码段:

if (ENABLE_COVERAGE AND NOT CMAKE_CONFIGURATION_TYPES)
    if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
        message(STATUS "Coverage in a non-debug build may lead to misleading results! Setting build type to 'Debug'!")
        set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "" FORCE)
    endif (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")

    include(CodeCoverage)
    APPEND_COVERAGE_COMPILER_FLAGS()

    if (NOT BUILD_TESTS)
        message(STATUS "Tests must be enabled in a coverage build! Setting BUILD_TESTS to On!")
        set(BUILD_TESTS On CACHE STRING "" FORCE)
    endif (NOT BUILD_TESTS)

    set(COVERAGE_EXCLUDES 'tests/*')

    include(CodeCoverage)
    APPEND_COVERAGE_COMPILER_FLAGS()

    SETUP_TARGET_FOR_COVERAGE(NAME coverage EXECUTABLE tests DEPENDENCIES coverage)
else (ENABLE_COVERAGE AND NOT CMAKE_CONFIGURATION_TYPES)
    # ...
endif (ENABLE_COVERAGE AND NOT CMAKE_CONFIGURATION_TYPES)

细节。

  • ENABLE_COVERAGE是我用来启用/禁用代码覆盖的命令行标志,它将使用 lcov/gcov 生成。
  • tests是运行我所有单元测试的可执行文件的名称。首先我add_subdirectory用来添加它的文件夹,并在我使用的文件夹内:

    set(TEST_SOURCES test_hello_world.cpp test_factorial.cpp)
    
    add_executable(tests main.cpp ${TEST_SOURCES})
    target_link_libraries(tests Project-Name-lib)
    
    include(ParseAndAddCatchTests)
    ParseAndAddCatchTests(tests)
    

我的问题:

当我通常运行我的make脚本时,代码很容易编译,包括构建需要大约 10 秒的测试可执行文件。但是,当我为我的代码启用覆盖时,代码会卡在构建main.cpp.o(Inside tests)上,并且make永远不会完成。当我运行时make VERBOSE=1,我得到以下正在为所述对象运行的命令:

cd project_dir/build/tests && /usr/bin/g++-5 
    -g -O0 --coverage -fprofile-arcs -ftest-coverage -g -O0 
    --coverage -fprofile-arcs -ftest-coverage -g 
    -I/project_dir/include -I/project_dir/build    
    -std=c++14 -o CMakeFiles/tests.dir/main.cpp.o -c /project_dir/main.cpp

(为了便于阅读,我缩短了一些路径,缩进的行是同一命令的一部分)

显然,即使使用set(COVERAGE_EXCLUDES 'tests/*'),编译器仍在将覆盖标志附加到测试可执行文件中,我认为这是构建时间缓慢的根源。如果我的结论是正确的,那么我如何告诉编译器不要将这些标志添加到我的测试可执行文件中?如果我的结论不正确,那么如何减少此可执行文件的构建时间?(我不想直接提及标志名称,因为这可能不适用于所有编译器(我的意思是 GCC/Clang))

在旁注中,我的main.cpp包含:

#define CATCH_CONFIG_MAIN
#include "catch.hpp"

一个示例测试文件包含:

#include <project-abbr/factorial.hpp>
#include "catch.hpp"

TEST_CASE("function factorial")
{
    SECTION("normal arguments")
    {
        REQUIRE(factorial(2) == 2);
        REQUIRE(factorial(3) == 6);
        REQUIRE(factorial(4) == 24);
        REQUIRE(factorial(5) == 120);
    }
}
4

1 回答 1

0

更新

以下代码并不是真正的解决方案。它仅适用于仅在源文件中定义的所有函数。这意味着如果你有一个模板库或一个只有头文件的库,那么这个解决方案是完全没用的。真正的解决方案调用append_coverage_compiler_flags允许完全覆盖的函数。但是,这可能会导致编译冻结,如 OP 的帖子中所示...


好的,我进行了一些实验,查看了文档,并找到了一个虽然不是最佳但仍然有效的解决方案。我使用该函数target_compile_options仅将覆盖标志添加到我想要的目标而不是ADD_COVERAGE_COMPILE_FLAGS()模块中的函数,如下所示:

如果(不是 CMAKE_BUILD_TYPE STREQUAL “调试”)
    消息(状态“非调试构建中的覆盖率可能会导致误导性结果!将构建类型设置为“调试”!”)
    设置(CMAKE_BUILD_TYPE“调试”缓存字符串“”强制)
endif(不是 CMAKE_BUILD_TYPE STREQUAL “调试”)

包括(代码覆盖)

如果(不是 BUILD_TESTS)
    消息(状态“必须在覆盖构建中启用测试!将 BUILD_TESTS 设置为开启!”)
    设置(缓存字符串上的BUILD_TESTS“”强制)
endif (NOT BUILD_TESTS)

设置(COVERAGE_EXCLUDES '测试/*')

包括(代码覆盖)

包含目录(包括 ${PROJECT_BINARY_DIR})
add_subdirectory(src)

target_compile_options(项目名称-lib PRIVATE“--coverage”)
target_compile_options(项目名称私有“--coverage”)

SETUP_TARGET_FOR_COVERAGE(NAME 覆盖 EXECUTABLE 测试 DEPENDENCIES 覆盖)

这个解决方案有一个警告。显然,头文件不包括在代码覆盖范围内......

于 2018-03-13T12:22:48.173 回答