|
ferencd@0
|
1 #
|
|
ferencd@0
|
2 # 2012-01-31, Lars Bilke
|
|
ferencd@0
|
3 # - Enable Code Coverage
|
|
ferencd@0
|
4 #
|
|
ferencd@0
|
5 # 2013-09-17, Joakim Söderberg
|
|
ferencd@0
|
6 # - Added support for Clang.
|
|
ferencd@0
|
7 # - Some additional usage instructions.
|
|
ferencd@0
|
8 #
|
|
ferencd@0
|
9 # USAGE:
|
|
ferencd@0
|
10 # 1. Copy this file into your cmake modules path.
|
|
ferencd@0
|
11 #
|
|
ferencd@0
|
12 # 2. Add the following line to your CMakeLists.txt:
|
|
ferencd@0
|
13 # INCLUDE(CodeCoverage)
|
|
ferencd@0
|
14 #
|
|
ferencd@0
|
15 # 3. Set compiler flags to turn off optimization and enable coverage:
|
|
ferencd@0
|
16 # SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
|
|
ferencd@0
|
17 # SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
|
|
ferencd@0
|
18 #
|
|
ferencd@0
|
19 # 3. Use the function SETUP_TARGET_FOR_COVERAGE to create a custom make target
|
|
ferencd@0
|
20 # which runs your test executable and produces a lcov code coverage report:
|
|
ferencd@0
|
21 # Example:
|
|
ferencd@0
|
22 # SETUP_TARGET_FOR_COVERAGE(
|
|
ferencd@0
|
23 # my_coverage_target # Name for custom target.
|
|
ferencd@0
|
24 # test_driver # Name of the test driver executable that runs the tests.
|
|
ferencd@0
|
25 # # NOTE! This should always have a ZERO as exit code
|
|
ferencd@0
|
26 # # otherwise the coverage generation will not complete.
|
|
ferencd@0
|
27 # coverage # Name of output directory.
|
|
ferencd@0
|
28 # )
|
|
ferencd@0
|
29 #
|
|
ferencd@0
|
30 # 4. Build a Debug build:
|
|
ferencd@0
|
31 # cmake -DCMAKE_BUILD_TYPE=Debug ..
|
|
ferencd@0
|
32 # make
|
|
ferencd@0
|
33 # make my_coverage_target
|
|
ferencd@0
|
34 #
|
|
ferencd@0
|
35 #
|
|
ferencd@0
|
36
|
|
ferencd@0
|
37 # Check prereqs
|
|
ferencd@0
|
38 FIND_PROGRAM( GCOV_PATH gcov )
|
|
ferencd@0
|
39 FIND_PROGRAM( LCOV_PATH lcov )
|
|
ferencd@0
|
40 FIND_PROGRAM( GENHTML_PATH genhtml )
|
|
ferencd@0
|
41 FIND_PROGRAM( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests)
|
|
ferencd@0
|
42
|
|
ferencd@0
|
43 IF(NOT GCOV_PATH)
|
|
ferencd@0
|
44 MESSAGE(FATAL_ERROR "gcov not found! Aborting...")
|
|
ferencd@0
|
45 ENDIF() # NOT GCOV_PATH
|
|
ferencd@0
|
46
|
|
ferencd@0
|
47 IF(NOT CMAKE_COMPILER_IS_GNUCXX)
|
|
ferencd@0
|
48 # Clang version 3.0.0 and greater now supports gcov as well.
|
|
ferencd@0
|
49 MESSAGE(WARNING "Compiler is not GNU gcc! Clang Version 3.0.0 and greater supports gcov as well, but older versions don't.")
|
|
ferencd@0
|
50
|
|
ferencd@0
|
51 IF(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
|
ferencd@0
|
52 MESSAGE(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
|
|
ferencd@0
|
53 ENDIF()
|
|
ferencd@0
|
54 ENDIF() # NOT CMAKE_COMPILER_IS_GNUCXX
|
|
ferencd@0
|
55
|
|
ferencd@0
|
56 IF ( NOT CMAKE_BUILD_TYPE STREQUAL "Debug" )
|
|
ferencd@0
|
57 MESSAGE( WARNING "Code coverage results with an optimized (non-Debug) build may be misleading" )
|
|
ferencd@0
|
58 ENDIF() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
|
|
ferencd@0
|
59
|
|
ferencd@0
|
60
|
|
ferencd@0
|
61 # Param _targetname The name of new the custom make target
|
|
ferencd@0
|
62 # Param _testrunner The name of the target which runs the tests.
|
|
ferencd@0
|
63 # MUST return ZERO always, even on errors.
|
|
ferencd@0
|
64 # If not, no coverage report will be created!
|
|
ferencd@0
|
65 # Param _outputname lcov output is generated as _outputname.info
|
|
ferencd@0
|
66 # HTML report is generated in _outputname/index.html
|
|
ferencd@0
|
67 # Optional fourth parameter is passed as arguments to _testrunner
|
|
ferencd@0
|
68 # Pass them in list form, e.g.: "-j;2" for -j 2
|
|
ferencd@0
|
69 FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _testrunner _outputname)
|
|
ferencd@0
|
70
|
|
ferencd@0
|
71 IF(NOT LCOV_PATH)
|
|
ferencd@0
|
72 MESSAGE(FATAL_ERROR "lcov not found! Aborting...")
|
|
ferencd@0
|
73 ENDIF() # NOT LCOV_PATH
|
|
ferencd@0
|
74
|
|
ferencd@0
|
75 IF(NOT GENHTML_PATH)
|
|
ferencd@0
|
76 MESSAGE(FATAL_ERROR "genhtml not found! Aborting...")
|
|
ferencd@0
|
77 ENDIF() # NOT GENHTML_PATH
|
|
ferencd@0
|
78
|
|
ferencd@0
|
79 # Setup target
|
|
ferencd@0
|
80 ADD_CUSTOM_TARGET(${_targetname}
|
|
ferencd@0
|
81
|
|
ferencd@0
|
82 # Cleanup lcov
|
|
ferencd@0
|
83 ${LCOV_PATH} --directory . --zerocounters
|
|
ferencd@0
|
84
|
|
ferencd@0
|
85 # Run tests
|
|
ferencd@0
|
86 COMMAND ${_testrunner} ${ARGV3}
|
|
ferencd@0
|
87
|
|
ferencd@0
|
88 # Capturing lcov counters and generating report
|
|
ferencd@0
|
89 COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info
|
|
ferencd@0
|
90 COMMAND ${LCOV_PATH} --remove ${_outputname}.info 'tests/*' '/usr/*' --output-file ${_outputname}.info.cleaned
|
|
ferencd@0
|
91 COMMAND ${GENHTML_PATH} -o ${_outputname} ${_outputname}.info.cleaned
|
|
ferencd@0
|
92 COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned
|
|
ferencd@0
|
93
|
|
ferencd@0
|
94 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
|
ferencd@0
|
95 COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
|
|
ferencd@0
|
96 )
|
|
ferencd@0
|
97
|
|
ferencd@0
|
98 # Show info where to find the report
|
|
ferencd@0
|
99 ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD
|
|
ferencd@0
|
100 COMMAND ;
|
|
ferencd@0
|
101 COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report."
|
|
ferencd@0
|
102 )
|
|
ferencd@0
|
103
|
|
ferencd@0
|
104 ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE
|
|
ferencd@0
|
105
|
|
ferencd@0
|
106 # Param _targetname The name of new the custom make target
|
|
ferencd@0
|
107 # Param _testrunner The name of the target which runs the tests
|
|
ferencd@0
|
108 # Param _outputname cobertura output is generated as _outputname.xml
|
|
ferencd@0
|
109 # Optional fourth parameter is passed as arguments to _testrunner
|
|
ferencd@0
|
110 # Pass them in list form, e.g.: "-j;2" for -j 2
|
|
ferencd@0
|
111 FUNCTION(SETUP_TARGET_FOR_COVERAGE_COBERTURA _targetname _testrunner _outputname)
|
|
ferencd@0
|
112
|
|
ferencd@0
|
113 IF(NOT PYTHON_EXECUTABLE)
|
|
ferencd@0
|
114 MESSAGE(FATAL_ERROR "Python not found! Aborting...")
|
|
ferencd@0
|
115 ENDIF() # NOT PYTHON_EXECUTABLE
|
|
ferencd@0
|
116
|
|
ferencd@0
|
117 IF(NOT GCOVR_PATH)
|
|
ferencd@0
|
118 MESSAGE(FATAL_ERROR "gcovr not found! Aborting...")
|
|
ferencd@0
|
119 ENDIF() # NOT GCOVR_PATH
|
|
ferencd@0
|
120
|
|
ferencd@0
|
121 ADD_CUSTOM_TARGET(${_targetname}
|
|
ferencd@0
|
122
|
|
ferencd@0
|
123 # Run tests
|
|
ferencd@0
|
124 ${_testrunner} ${ARGV3}
|
|
ferencd@0
|
125
|
|
ferencd@0
|
126 # Running gcovr
|
|
ferencd@0
|
127 COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} -e '${CMAKE_SOURCE_DIR}/tests/' -o ${_outputname}.xml
|
|
ferencd@0
|
128 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
|
ferencd@0
|
129 COMMENT "Running gcovr to produce Cobertura code coverage report."
|
|
ferencd@0
|
130 )
|
|
ferencd@0
|
131
|
|
ferencd@0
|
132 # Show info where to find the report
|
|
ferencd@0
|
133 ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD
|
|
ferencd@0
|
134 COMMAND ;
|
|
ferencd@0
|
135 COMMENT "Cobertura code coverage report saved in ${_outputname}.xml."
|
|
ferencd@0
|
136 )
|
|
ferencd@0
|
137
|
|
ferencd@0
|
138 ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE_COBERTURA
|