Monku
Monku

Reputation: 2650

How to do code coverage in cmake

I want to use code coverage tools(lcov) in my cmake project. I read the example here https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake The tests are added in my project using the 'add_test()' cmake function.

I want to create a custom target, something called 'test_coverage', that when invoked for execution should run all the tests, collect their coverage data and generate the html(using genhtml) in a directory 'code_coverage'.

Is there a way I could get the list of all the tests in my project and their directory paths, so that in the custom target 'test_coverage' I could execute each test individually and collect its coverage data ?

Upvotes: 29

Views: 31956

Answers (1)

Bohdan Lakatosh
Bohdan Lakatosh

Reputation: 196

I am not a cmake expert and when I had similar problem in my small project I did not want to deal with CDash it just looked like a too big effort for my case. So I came up with easier solution - invoke lcov and genhtml from cmake.

In case if you use add_test it is not that easy, since it does not support multiple commands and chaining command. But we can chain all the calls we need to generate coverage in a shell script (as suggested here. Simple example will look like this:

enable_testing()

add_library(coverage_options INTERFACE)
enable_coverage(coverage_options)

add_executable(example_test ${UNITTEST_FILES})
target_link_libraries(example_test PRIVATE coverage_options)

FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/main.sh
"${CMAKE_CURRENT_BINARY_DIR}/example_test && lcov -q --capture --directory . --output-file=all_coverage.info && lcov -q --extract all_coverage.info \"${CMAKE_SOURCE_DIR}/*\" --output-file=coverage.info && rm all_coverage.info  && genhtml  coverage.info --output-directory=coverage_html")

add_test(
    NAME example_test
    COMMAND sh ${CMAKE_CURRENT_BINARY_DIR}/main.sh
)

enable_coverage is a function from here. Namely

function(enable_coverage _project_name)
  if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
    target_compile_options(${_project_name} INTERFACE --coverage -O0 -g)
    target_link_libraries(${_project_name} INTERFACE --coverage)
  endif()
endfunction()

The solution is not ideal but I feel that it is easier to plug this in small projects than deal with CDash.

Upvotes: 0

Related Questions