1
# - Creates a special coverage build type and target on GCC.
3
# Defines a function ENABLE_COVERAGE_REPORT which generates the coverage target
4
# for selected targets. Optional arguments to this function are used to filter
5
# unwanted results using globbing expressions. Moreover targets with tests for
6
# the source code can be specified to trigger regenerating the report if the
9
# ENABLE_COVERAGE_REPORT(TARGETS target... [FILTER filter...] [TESTS test targets...])
11
# To generate a coverage report first build the project with
12
# CMAKE_BUILD_TYPE=coverage, then call make test and afterwards make coverage.
14
# The coverage report is based on gcov. Depending on the availability of lcov
15
# a HTML report will be generated and/or an XML report of gcovr is found.
16
# The generated coverage target executes all found solutions. Special targets
17
# exist to create e.g. only the xml report: coverage-xml.
19
# Copyright (C) 2010 by Johannes Wienke <jwienke at techfak dot uni-bielefeld dot de>
21
# This program is free software; you can redistribute it
22
# and/or modify it under the terms of the GNU General
23
# Public License as published by the Free Software Foundation;
24
# either version 2, or (at your option)
27
# This program is distributed in the hope that it will be useful,
28
# but WITHOUT ANY WARRANTY; without even the implied warranty of
29
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30
# GNU General Public License for more details.
33
INCLUDE(ParseArguments)
38
FUNCTION(ENABLE_COVERAGE_REPORT)
41
PARSE_ARGUMENTS(ARG "FILTER;TARGETS;TESTS" "" ${ARGN})
43
SET(COVERAGE_RAW_FILE "${CMAKE_BINARY_DIR}/coverage.raw.info")
44
SET(COVERAGE_FILTERED_FILE "${CMAKE_BINARY_DIR}/coverage.info")
45
SET(COVERAGE_REPORT_DIR "${CMAKE_BINARY_DIR}/coveragereport")
46
SET(COVERAGE_XML_FILE "${CMAKE_BINARY_DIR}/coverage.xml")
47
SET(COVERAGE_XML_COMMAND_FILE "${CMAKE_BINARY_DIR}/coverage-xml.cmake")
49
# decide if there is any tool to create coverage data
51
IF(LCOV_FOUND OR GCOVR_FOUND)
55
MESSAGE(STATUS "Cannot enable coverage targets because neither lcov nor gcovr are found.")
58
STRING(TOLOWER "${CMAKE_BUILD_TYPE}" COVERAGE_BUILD_TYPE)
59
IF(CMAKE_COMPILER_IS_GNUCXX AND TOOL_FOUND AND "${COVERAGE_BUILD_TYPE}" MATCHES "coverage")
61
MESSAGE(STATUS "Coverage support enabled for targets: ${ARG_TARGETS}")
63
# create coverage build type
64
SET(CMAKE_CXX_FLAGS_COVERAGE ${CMAKE_CXX_FLAGS_DEBUG} PARENT_SCOPE)
65
SET(CMAKE_C_FLAGS_COVERAGE ${CMAKE_C_FLAGS_DEBUG} PARENT_SCOPE)
66
SET(CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES} coverage PARENT_SCOPE)
69
SET_TARGET_PROPERTIES(${ARG_TARGETS} PROPERTIES COMPILE_FLAGS --coverage
70
LINK_FLAGS --coverage)
75
MESSAGE(STATUS "Enabling HTML coverage report")
77
# set up coverage target
79
ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_RAW_FILE}
80
COMMAND ${LCOV_EXECUTABLE} -c -d ${CMAKE_BINARY_DIR} -o ${COVERAGE_RAW_FILE}
81
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
82
COMMENT "Collecting coverage data"
83
DEPENDS ${ARG_TARGETS} ${ARG_TESTS}
86
# filter unwanted stuff
87
LIST(LENGTH ARG_FILTER FILTER_LENGTH)
88
IF(${FILTER_LENGTH} GREATER 0)
89
SET(FILTER COMMAND ${LCOV_EXECUTABLE})
90
FOREACH(F ${ARG_FILTER})
91
SET(FILTER ${FILTER} -r ${COVERAGE_FILTERED_FILE} ${F})
93
SET(FILTER ${FILTER} -o ${COVERAGE_FILTERED_FILE})
98
ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_FILTERED_FILE}
99
COMMAND ${LCOV_EXECUTABLE} -e ${COVERAGE_RAW_FILE} "${CMAKE_SOURCE_DIR}*" -o ${COVERAGE_FILTERED_FILE}
101
DEPENDS ${COVERAGE_RAW_FILE}
102
COMMENT "Filtering recorded coverage data for project-relevant entries"
104
ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_REPORT_DIR}
105
COMMAND ${CMAKE_COMMAND} -E make_directory ${COVERAGE_REPORT_DIR}
106
COMMAND ${GENHTML_EXECUTABLE} --legend --show-details -t "${PROJECT_NAME} test coverage" -o ${COVERAGE_REPORT_DIR} ${COVERAGE_FILTERED_FILE}
107
DEPENDS ${COVERAGE_FILTERED_FILE}
108
COMMENT "Generating HTML coverage report in ${COVERAGE_REPORT_DIR}"
111
ADD_CUSTOM_TARGET(coverage-html
112
DEPENDS ${COVERAGE_REPORT_DIR})
116
# xml coverage report
119
MESSAGE(STATUS "Enabling XML coverage report")
121
# filter unwanted stuff
123
LIST(LENGTH ARG_FILTER FILTER_LENGTH)
124
IF(${FILTER_LENGTH} GREATER 0)
125
FOREACH(F ${ARG_FILTER})
126
SET(GCOV_FILTER "${GCOV_FILTER} -e \"${F}\"")
130
# gcovr cannot write directly to a file so the execution needs to
131
# be wrapped in a cmake file that generates the file output
132
FILE(WRITE ${COVERAGE_XML_COMMAND_FILE}
133
"SET(ENV{LANG} en)\n")
134
FILE(APPEND ${COVERAGE_XML_COMMAND_FILE}
135
"EXECUTE_PROCESS(COMMAND \"${GCOVR_EXECUTABLE}\" -x -r \"${CMAKE_SOURCE_DIR}\" ${GCOV_FILTER} OUTPUT_FILE \"${COVERAGE_XML_FILE}\" WORKING_DIRECTORY \"${CMAKE_BINARY_DIR}\")\n")
137
ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_XML_FILE}
138
COMMAND ${CMAKE_COMMAND} ARGS -P ${COVERAGE_XML_COMMAND_FILE}
139
COMMENT "Generating coverage XML report"
142
ADD_CUSTOM_TARGET(coverage-xml
143
DEPENDS ${COVERAGE_XML_FILE})
147
# provide a global coverage target executing both steps if available
148
SET(GLOBAL_DEPENDS "")
150
LIST(APPEND GLOBAL_DEPENDS ${COVERAGE_REPORT_DIR})
153
LIST(APPEND GLOBAL_DEPENDS ${COVERAGE_XML_FILE})
155
IF(LCOV_FOUND OR GCOVR_FOUND)
156
ADD_CUSTOM_TARGET(coverage
157
DEPENDS ${GLOBAL_DEPENDS})
162
# This gets rid of any stale .gcda files. Run this if a running a binary causes lots of messages about
163
# about a "merge mismatch for summaries".
164
ADD_CUSTOM_TARGET(clean-coverage COMMAND find ${CMAKE_BINARY_DIR} -name '*.gcda' | xargs rm -f)