Search code examples
c++cmakegcovcatch-unit-test

Using Gcov with CMake and Catch


I want to use Gcov to report coverage for my static library Catch test suite, compiled using CMake.

.
├── CMakeLists.txt
├── bin
├── CMakeModules
│   └── CodeCoverage.cmake
├── src
│   ├── some_function.cpp
│   ├── another_function.cpp
│   └── library_name.hpp
└── test
    └── main.cpp

I followed the instructions here, and added CMakeModules/CodeCoverage.cmake (see the file system tree above).

# CMakeLists.txt

cmake_minimum_required(VERSION 3.14)
project(my_project CXX)

set(CMAKE_CXX_STANDARD 11)

# Link CMake Gcov module
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMakeModules)
include(CodeCoverage.cmake)
append_coverage_compiler_flags()

# Library
file(GLOB_RECURSE LIBRARY_SOURCE_FILES src/*.cpp)
add_library(library STATIC ${LIBRARY_SOURCE_FILES})

# Tests
file(GLOB_RECURSE TEST_SOURCE_FILES test/*.cpp)
add_executable(test ${TEST_SOURCE_FILES})
target_link_libraries(test PRIVATE library)
set_target_properties(test
    PROPERTIES RUNTIME_OUTPUT_DIRECTORY
    ${CMAKE_SOURCE_DIR}/bin)

# Create a make target for the coverage executable
APPEND_COVERAGE_COMPILER_FLAGS()
SETUP_TARGET_FOR_COVERAGE_LCOV(
    NAME coverage
    EXECUTABLE bin/test
    DEPENDENCIES library test)

The binary bin/test will return a non-zero value if any of the test functions fail. This causes the coverage make target to fail:

$ make coverage

...

make[3]: *** [CMakeFiles/coverage.dir/build.make: CMakeFiles/coverage] Error 3
make[2]: *** [CMakeFiles/Makefile2: CMakeFiles/coverage.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2: CMakeFiles/coverage.dir/rule] Error 2

These errors point to the line in the Makefile where the test binary is invoked:

# build.make

CMakeFiles/coverage: bin/test
    bin/test

Any recommendations on how I might resolve this?


Solution

  • According to implementation of SETUP_TARGET_FOR_COVERAGE_LCOV command, it passes the whole content of EXECUTABLE clause to the COMMAND clause of the add_custom_target. The latter accepts a shell command line, so you may create a command line which runs your tests but always returns zero. E.g. that way:

    EXECUTABLE bin/test || /bin/true