Warning, /sdk/codevis/cmake/CodeCoverage.cmake is written in an unsupported language. File is not indexed.
0001 # Copyright (c) 2012 - 2017, Lars Bilke 0002 # All rights reserved. 0003 # 0004 # Redistribution and use in source and binary forms, with or without modification, 0005 # are permitted provided that the following conditions are met: 0006 # 0007 # 1. Redistributions of source code must retain the above copyright notice, this 0008 # list of conditions and the following disclaimer. 0009 # 0010 # 2. Redistributions in binary form must reproduce the above copyright notice, 0011 # this list of conditions and the following disclaimer in the documentation 0012 # and/or other materials provided with the distribution. 0013 # 0014 # 3. Neither the name of the copyright holder nor the names of its contributors 0015 # may be used to endorse or promote products derived from this software without 0016 # specific prior written permission. 0017 # 0018 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 0019 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 0020 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 0021 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 0022 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 0023 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 0024 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 0025 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0026 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 0027 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0028 # 0029 # CHANGES: 0030 # 0031 # 2012-01-31, Lars Bilke 0032 # - Enable Code Coverage 0033 # 0034 # 2013-09-17, Joakim Söderberg 0035 # - Added support for Clang. 0036 # - Some additional usage instructions. 0037 # 0038 # 2016-02-03, Lars Bilke 0039 # - Refactored functions to use named parameters 0040 # 0041 # 2017-06-02, Lars Bilke 0042 # - Merged with modified version from github.com/ufz/ogs 0043 # 0044 # 2019-05-06, Anatolii Kurotych 0045 # - Remove unnecessary --coverage flag 0046 # 0047 # 2019-12-13, FeRD (Frank Dana) 0048 # - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor 0049 # of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments. 0050 # - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY 0051 # - All setup functions: accept BASE_DIRECTORY, EXCLUDE list 0052 # - Set lcov basedir with -b argument 0053 # - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be 0054 # overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().) 0055 # - Delete output dir, .info file on 'make clean' 0056 # - Remove Python detection, since version mismatches will break gcovr 0057 # - Minor cleanup (lowercase function names, update examples...) 0058 # 0059 # 2019-12-19, FeRD (Frank Dana) 0060 # - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets 0061 # 0062 # 2020-01-19, Bob Apthorpe 0063 # - Added gfortran support 0064 # 0065 # 2020-02-17, FeRD (Frank Dana) 0066 # - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters 0067 # in EXCLUDEs, and remove manual escaping from gcovr targets 0068 # 0069 # 2021-01-19, Robin Mueller 0070 # - Add CODE_COVERAGE_VERBOSE option which will allow to print out commands which are run 0071 # - Added the option for users to set the GCOVR_ADDITIONAL_ARGS variable to supply additional 0072 # flags to the gcovr command 0073 # 0074 # 2020-05-04, Mihchael Davis 0075 # - Add -fprofile-abs-path to make gcno files contain absolute paths 0076 # - Fix BASE_DIRECTORY not working when defined 0077 # - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines 0078 # 0079 # 2021-05-10, Martin Stump 0080 # - Check if the generator is multi-config before warning about non-Debug builds 0081 # 0082 # USAGE: 0083 # 0084 # 1. Copy this file into your cmake modules path. 0085 # 0086 # 2. Add the following line to your CMakeLists.txt (best inside an if-condition 0087 # using a CMake option() to enable it just optionally): 0088 # include(CodeCoverage) 0089 # 0090 # 3. Append necessary compiler flags: 0091 # append_coverage_compiler_flags() 0092 # 0093 # 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og 0094 # 0095 # 4. If you need to exclude additional directories from the report, specify them 0096 # using full paths in the COVERAGE_EXCLUDES variable before calling 0097 # setup_target_for_coverage_*(). 0098 # Example: 0099 # set(COVERAGE_EXCLUDES 0100 # '${PROJECT_SOURCE_DIR}/src/dir1/*' 0101 # '/path/to/my/src/dir2/*') 0102 # Or, use the EXCLUDE argument to setup_target_for_coverage_*(). 0103 # Example: 0104 # setup_target_for_coverage_lcov( 0105 # NAME coverage 0106 # EXECUTABLE testrunner 0107 # EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*") 0108 # 0109 # 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set 0110 # relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR) 0111 # Example: 0112 # set(COVERAGE_EXCLUDES "dir1/*") 0113 # setup_target_for_coverage_gcovr_html( 0114 # NAME coverage 0115 # EXECUTABLE testrunner 0116 # BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src" 0117 # EXCLUDE "dir2/*") 0118 # 0119 # 5. Use the functions described below to create a custom make target which 0120 # runs your test executable and produces a code coverage report. 0121 # 0122 # 6. Build a Debug build: 0123 # cmake -DCMAKE_BUILD_TYPE=Debug .. 0124 # make 0125 # make my_coverage_target 0126 # 0127 0128 include(CMakeParseArguments) 0129 0130 option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE) 0131 0132 # Check prereqs 0133 find_program( GCOV_PATH gcov ) 0134 find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl) 0135 find_program( FASTCOV_PATH NAMES fastcov fastcov.py ) 0136 find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat ) 0137 find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) 0138 find_program( CPPFILT_PATH NAMES c++filt ) 0139 0140 if(NOT GCOV_PATH) 0141 message(FATAL_ERROR "gcov not found! Aborting...") 0142 endif() # NOT GCOV_PATH 0143 0144 get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) 0145 list(GET LANGUAGES 0 LANG) 0146 0147 if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") 0148 if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3) 0149 message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...") 0150 endif() 0151 elseif(NOT CMAKE_COMPILER_IS_GNUCXX) 0152 if("${CMAKE_Fortran_COMPILER_ID}" MATCHES "[Ff]lang") 0153 # Do nothing; exit conditional without error if true 0154 elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU") 0155 # Do nothing; exit conditional without error if true 0156 else() 0157 message("Current Compiler: ${CMAKE_CXX_COMPILER_ID}") 0158 message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...") 0159 endif() 0160 endif() 0161 0162 set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage" 0163 CACHE INTERNAL "") 0164 if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") 0165 include(CheckCXXCompilerFlag) 0166 check_cxx_compiler_flag(-fprofile-abs-path HAVE_fprofile_abs_path) 0167 if(HAVE_fprofile_abs_path) 0168 set(COVERAGE_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path") 0169 endif() 0170 endif() 0171 0172 set(CMAKE_Fortran_FLAGS_COVERAGE 0173 ${COVERAGE_COMPILER_FLAGS} 0174 CACHE STRING "Flags used by the Fortran compiler during coverage builds." 0175 FORCE ) 0176 set(CMAKE_CXX_FLAGS_COVERAGE 0177 ${COVERAGE_COMPILER_FLAGS} 0178 CACHE STRING "Flags used by the C++ compiler during coverage builds." 0179 FORCE ) 0180 set(CMAKE_C_FLAGS_COVERAGE 0181 ${COVERAGE_COMPILER_FLAGS} 0182 CACHE STRING "Flags used by the C compiler during coverage builds." 0183 FORCE ) 0184 set(CMAKE_EXE_LINKER_FLAGS_COVERAGE 0185 "" 0186 CACHE STRING "Flags used for linking binaries during coverage builds." 0187 FORCE ) 0188 set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE 0189 "" 0190 CACHE STRING "Flags used by the shared libraries linker during coverage builds." 0191 FORCE ) 0192 mark_as_advanced( 0193 CMAKE_Fortran_FLAGS_COVERAGE 0194 CMAKE_CXX_FLAGS_COVERAGE 0195 CMAKE_C_FLAGS_COVERAGE 0196 CMAKE_EXE_LINKER_FLAGS_COVERAGE 0197 CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) 0198 0199 get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 0200 if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG)) 0201 message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading") 0202 endif() # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG) 0203 0204 if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") 0205 link_libraries(gcov) 0206 endif() 0207 0208 # Defines a target for running and collection code coverage information 0209 # Builds dependencies, runs the given executable and outputs reports. 0210 # NOTE! The executable should always have a ZERO as exit code otherwise 0211 # the coverage generation will not complete. 0212 # 0213 # setup_target_for_coverage_lcov( 0214 # NAME testrunner_coverage # New target name 0215 # EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR 0216 # DEPENDENCIES testrunner # Dependencies to build first 0217 # BASE_DIRECTORY "../" # Base directory for report 0218 # # (defaults to PROJECT_SOURCE_DIR) 0219 # EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative 0220 # # to BASE_DIRECTORY, with CMake 3.4+) 0221 # NO_DEMANGLE # Don't demangle C++ symbols 0222 # # even if c++filt is found 0223 # ) 0224 function(setup_target_for_coverage_lcov) 0225 0226 set(options NO_DEMANGLE) 0227 set(oneValueArgs BASE_DIRECTORY NAME) 0228 set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS) 0229 cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 0230 0231 if(NOT LCOV_PATH) 0232 message(FATAL_ERROR "lcov not found! Aborting...") 0233 endif() # NOT LCOV_PATH 0234 0235 if(NOT GENHTML_PATH) 0236 message(FATAL_ERROR "genhtml not found! Aborting...") 0237 endif() # NOT GENHTML_PATH 0238 0239 # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR 0240 if(DEFINED Coverage_BASE_DIRECTORY) 0241 get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) 0242 else() 0243 set(BASEDIR ${PROJECT_SOURCE_DIR}) 0244 endif() 0245 0246 # Collect excludes (CMake 3.4+: Also compute absolute paths) 0247 set(LCOV_EXCLUDES "") 0248 foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES}) 0249 if(CMAKE_VERSION VERSION_GREATER 3.4) 0250 get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) 0251 endif() 0252 list(APPEND LCOV_EXCLUDES "${EXCLUDE}") 0253 endforeach() 0254 list(REMOVE_DUPLICATES LCOV_EXCLUDES) 0255 0256 # Conditional arguments 0257 if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE}) 0258 set(GENHTML_EXTRA_ARGS "--demangle-cpp") 0259 endif() 0260 0261 # Setting up commands which will be run to generate coverage data. 0262 # Cleanup lcov 0263 set(LCOV_CLEAN_CMD 0264 ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . 0265 -b ${BASEDIR} --zerocounters 0266 ) 0267 # Create baseline to make sure untouched files show up in the report 0268 set(LCOV_BASELINE_CMD 0269 ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b 0270 ${BASEDIR} -o ${Coverage_NAME}.base 0271 ) 0272 # Run tests 0273 set(LCOV_EXEC_TESTS_CMD 0274 ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} 0275 ) 0276 # Capturing lcov counters and generating report 0277 set(LCOV_CAPTURE_CMD 0278 ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b 0279 ${BASEDIR} --capture --output-file ${Coverage_NAME}.capture 0280 ) 0281 # add baseline counters 0282 set(LCOV_BASELINE_COUNT_CMD 0283 ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base 0284 -a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total 0285 ) 0286 # filter collected data to final coverage report 0287 set(LCOV_FILTER_CMD 0288 ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove 0289 ${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info 0290 ) 0291 # Generate HTML output 0292 set(LCOV_GEN_HTML_CMD 0293 ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o 0294 ${Coverage_NAME} ${Coverage_NAME}.info 0295 ) 0296 0297 0298 if(CODE_COVERAGE_VERBOSE) 0299 message(STATUS "Executed command report") 0300 message(STATUS "Command to clean up lcov: ") 0301 string(REPLACE ";" " " LCOV_CLEAN_CMD_SPACED "${LCOV_CLEAN_CMD}") 0302 message(STATUS "${LCOV_CLEAN_CMD_SPACED}") 0303 0304 message(STATUS "Command to create baseline: ") 0305 string(REPLACE ";" " " LCOV_BASELINE_CMD_SPACED "${LCOV_BASELINE_CMD}") 0306 message(STATUS "${LCOV_BASELINE_CMD_SPACED}") 0307 0308 message(STATUS "Command to run the tests: ") 0309 string(REPLACE ";" " " LCOV_EXEC_TESTS_CMD_SPACED "${LCOV_EXEC_TESTS_CMD}") 0310 message(STATUS "${LCOV_EXEC_TESTS_CMD_SPACED}") 0311 0312 message(STATUS "Command to capture counters and generate report: ") 0313 string(REPLACE ";" " " LCOV_CAPTURE_CMD_SPACED "${LCOV_CAPTURE_CMD}") 0314 message(STATUS "${LCOV_CAPTURE_CMD_SPACED}") 0315 0316 message(STATUS "Command to add baseline counters: ") 0317 string(REPLACE ";" " " LCOV_BASELINE_COUNT_CMD_SPACED "${LCOV_BASELINE_COUNT_CMD}") 0318 message(STATUS "${LCOV_BASELINE_COUNT_CMD_SPACED}") 0319 0320 message(STATUS "Command to filter collected data: ") 0321 string(REPLACE ";" " " LCOV_FILTER_CMD_SPACED "${LCOV_FILTER_CMD}") 0322 message(STATUS "${LCOV_FILTER_CMD_SPACED}") 0323 0324 message(STATUS "Command to generate lcov HTML output: ") 0325 string(REPLACE ";" " " LCOV_GEN_HTML_CMD_SPACED "${LCOV_GEN_HTML_CMD}") 0326 message(STATUS "${LCOV_GEN_HTML_CMD_SPACED}") 0327 endif() 0328 0329 # Setup target 0330 add_custom_target(${Coverage_NAME} 0331 COMMAND ${LCOV_CLEAN_CMD} 0332 COMMAND ${LCOV_BASELINE_CMD} 0333 COMMAND ${LCOV_EXEC_TESTS_CMD} 0334 COMMAND ${LCOV_CAPTURE_CMD} 0335 COMMAND ${LCOV_BASELINE_COUNT_CMD} 0336 COMMAND ${LCOV_FILTER_CMD} 0337 COMMAND ${LCOV_GEN_HTML_CMD} 0338 0339 # Set output files as GENERATED (will be removed on 'make clean') 0340 BYPRODUCTS 0341 ${Coverage_NAME}.base 0342 ${Coverage_NAME}.capture 0343 ${Coverage_NAME}.total 0344 ${Coverage_NAME}.info 0345 ${Coverage_NAME}/index.html 0346 WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 0347 DEPENDS ${Coverage_DEPENDENCIES} 0348 VERBATIM # Protect arguments to commands 0349 COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." 0350 ) 0351 0352 # Show where to find the lcov info report 0353 add_custom_command(TARGET ${Coverage_NAME} POST_BUILD 0354 COMMAND ; 0355 COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info." 0356 ) 0357 0358 # Show info where to find the report 0359 add_custom_command(TARGET ${Coverage_NAME} POST_BUILD 0360 COMMAND ; 0361 COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." 0362 ) 0363 0364 endfunction() # setup_target_for_coverage_lcov 0365 0366 # Defines a target for running and collection code coverage information 0367 # Builds dependencies, runs the given executable and outputs reports. 0368 # NOTE! The executable should always have a ZERO as exit code otherwise 0369 # the coverage generation will not complete. 0370 # 0371 # setup_target_for_coverage_gcovr_xml( 0372 # NAME ctest_coverage # New target name 0373 # EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR 0374 # DEPENDENCIES executable_target # Dependencies to build first 0375 # BASE_DIRECTORY "../" # Base directory for report 0376 # # (defaults to PROJECT_SOURCE_DIR) 0377 # EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative 0378 # # to BASE_DIRECTORY, with CMake 3.4+) 0379 # ) 0380 # The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the 0381 # GCVOR command. 0382 function(setup_target_for_coverage_gcovr_xml) 0383 0384 set(options NONE) 0385 set(oneValueArgs BASE_DIRECTORY NAME) 0386 set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) 0387 cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 0388 0389 if(NOT GCOVR_PATH) 0390 message(FATAL_ERROR "gcovr not found! Aborting...") 0391 endif() # NOT GCOVR_PATH 0392 0393 # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR 0394 if(DEFINED Coverage_BASE_DIRECTORY) 0395 get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) 0396 else() 0397 set(BASEDIR ${PROJECT_SOURCE_DIR}) 0398 endif() 0399 0400 # Collect excludes (CMake 3.4+: Also compute absolute paths) 0401 set(GCOVR_EXCLUDES "") 0402 foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) 0403 if(CMAKE_VERSION VERSION_GREATER 3.4) 0404 get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) 0405 endif() 0406 list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") 0407 endforeach() 0408 list(REMOVE_DUPLICATES GCOVR_EXCLUDES) 0409 0410 # Combine excludes to several -e arguments 0411 set(GCOVR_EXCLUDE_ARGS "") 0412 foreach(EXCLUDE ${GCOVR_EXCLUDES}) 0413 list(APPEND GCOVR_EXCLUDE_ARGS "-e") 0414 list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") 0415 endforeach() 0416 0417 # Set up commands which will be run to generate coverage data 0418 # Run tests 0419 set(GCOVR_XML_EXEC_TESTS_CMD 0420 ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} 0421 ) 0422 # Running gcovr 0423 set(GCOVR_XML_CMD 0424 ${GCOVR_PATH} --xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} ${GCOVR_EXCLUDE_ARGS} 0425 --object-directory=${PROJECT_BINARY_DIR} -o ${Coverage_NAME}.xml 0426 ) 0427 0428 if(CODE_COVERAGE_VERBOSE) 0429 message(STATUS "Executed command report") 0430 0431 message(STATUS "Command to run tests: ") 0432 string(REPLACE ";" " " GCOVR_XML_EXEC_TESTS_CMD_SPACED "${GCOVR_XML_EXEC_TESTS_CMD}") 0433 message(STATUS "${GCOVR_XML_EXEC_TESTS_CMD_SPACED}") 0434 0435 message(STATUS "Command to generate gcovr XML coverage data: ") 0436 string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}") 0437 message(STATUS "${GCOVR_XML_CMD_SPACED}") 0438 endif() 0439 0440 add_custom_target(${Coverage_NAME} 0441 COMMAND ${GCOVR_XML_EXEC_TESTS_CMD} 0442 COMMAND ${GCOVR_XML_CMD} 0443 0444 BYPRODUCTS ${Coverage_NAME}.xml 0445 WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 0446 DEPENDS ${Coverage_DEPENDENCIES} 0447 VERBATIM # Protect arguments to commands 0448 COMMENT "Running gcovr to produce Cobertura code coverage report." 0449 ) 0450 0451 # Show info where to find the report 0452 add_custom_command(TARGET ${Coverage_NAME} POST_BUILD 0453 COMMAND ; 0454 COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml." 0455 ) 0456 endfunction() # setup_target_for_coverage_gcovr_xml 0457 0458 # Defines a target for running and collection code coverage information 0459 # Builds dependencies, runs the given executable and outputs reports. 0460 # NOTE! The executable should always have a ZERO as exit code otherwise 0461 # the coverage generation will not complete. 0462 # 0463 # setup_target_for_coverage_gcovr_html( 0464 # NAME ctest_coverage # New target name 0465 # EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR 0466 # DEPENDENCIES executable_target # Dependencies to build first 0467 # BASE_DIRECTORY "../" # Base directory for report 0468 # # (defaults to PROJECT_SOURCE_DIR) 0469 # EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative 0470 # # to BASE_DIRECTORY, with CMake 3.4+) 0471 # ) 0472 # The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the 0473 # GCVOR command. 0474 function(setup_target_for_coverage_gcovr_html) 0475 0476 set(options NONE) 0477 set(oneValueArgs BASE_DIRECTORY NAME) 0478 set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) 0479 cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 0480 0481 if(NOT GCOVR_PATH) 0482 message(FATAL_ERROR "gcovr not found! Aborting...") 0483 endif() # NOT GCOVR_PATH 0484 0485 # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR 0486 if(DEFINED Coverage_BASE_DIRECTORY) 0487 get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) 0488 else() 0489 set(BASEDIR ${PROJECT_SOURCE_DIR}) 0490 endif() 0491 0492 # Collect excludes (CMake 3.4+: Also compute absolute paths) 0493 set(GCOVR_EXCLUDES "") 0494 foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) 0495 if(CMAKE_VERSION VERSION_GREATER 3.4) 0496 get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) 0497 endif() 0498 list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") 0499 endforeach() 0500 list(REMOVE_DUPLICATES GCOVR_EXCLUDES) 0501 0502 # Combine excludes to several -e arguments 0503 set(GCOVR_EXCLUDE_ARGS "") 0504 foreach(EXCLUDE ${GCOVR_EXCLUDES}) 0505 list(APPEND GCOVR_EXCLUDE_ARGS "-e") 0506 list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") 0507 endforeach() 0508 0509 # Set up commands which will be run to generate coverage data 0510 # Run tests 0511 set(GCOVR_HTML_EXEC_TESTS_CMD 0512 ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} 0513 ) 0514 # Create folder 0515 set(GCOVR_HTML_FOLDER_CMD 0516 ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME} 0517 ) 0518 # Running gcovr 0519 set(GCOVR_HTML_CMD 0520 ${GCOVR_PATH} --html --html-details -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} 0521 ${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR} 0522 -o ${Coverage_NAME}/index.html 0523 ) 0524 0525 if(CODE_COVERAGE_VERBOSE) 0526 message(STATUS "Executed command report") 0527 0528 message(STATUS "Command to run tests: ") 0529 string(REPLACE ";" " " GCOVR_HTML_EXEC_TESTS_CMD_SPACED "${GCOVR_HTML_EXEC_TESTS_CMD}") 0530 message(STATUS "${GCOVR_HTML_EXEC_TESTS_CMD_SPACED}") 0531 0532 message(STATUS "Command to create a folder: ") 0533 string(REPLACE ";" " " GCOVR_HTML_FOLDER_CMD_SPACED "${GCOVR_HTML_FOLDER_CMD}") 0534 message(STATUS "${GCOVR_HTML_FOLDER_CMD_SPACED}") 0535 0536 message(STATUS "Command to generate gcovr HTML coverage data: ") 0537 string(REPLACE ";" " " GCOVR_HTML_CMD_SPACED "${GCOVR_HTML_CMD}") 0538 message(STATUS "${GCOVR_HTML_CMD_SPACED}") 0539 endif() 0540 0541 add_custom_target(${Coverage_NAME} 0542 COMMAND ${GCOVR_HTML_EXEC_TESTS_CMD} 0543 COMMAND ${GCOVR_HTML_FOLDER_CMD} 0544 COMMAND ${GCOVR_HTML_CMD} 0545 0546 BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory 0547 WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 0548 DEPENDS ${Coverage_DEPENDENCIES} 0549 VERBATIM # Protect arguments to commands 0550 COMMENT "Running gcovr to produce HTML code coverage report." 0551 ) 0552 0553 # Show info where to find the report 0554 add_custom_command(TARGET ${Coverage_NAME} POST_BUILD 0555 COMMAND ; 0556 COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." 0557 ) 0558 0559 endfunction() # setup_target_for_coverage_gcovr_html 0560 0561 # Defines a target for running and collection code coverage information 0562 # Builds dependencies, runs the given executable and outputs reports. 0563 # NOTE! The executable should always have a ZERO as exit code otherwise 0564 # the coverage generation will not complete. 0565 # 0566 # setup_target_for_coverage_fastcov( 0567 # NAME testrunner_coverage # New target name 0568 # EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR 0569 # DEPENDENCIES testrunner # Dependencies to build first 0570 # BASE_DIRECTORY "../" # Base directory for report 0571 # # (defaults to PROJECT_SOURCE_DIR) 0572 # EXCLUDE "src/dir1/" "src/dir2/" # Patterns to exclude. 0573 # NO_DEMANGLE # Don't demangle C++ symbols 0574 # # even if c++filt is found 0575 # SKIP_HTML # Don't create html report 0576 # ) 0577 function(setup_target_for_coverage_fastcov) 0578 0579 set(options NO_DEMANGLE SKIP_HTML) 0580 set(oneValueArgs BASE_DIRECTORY NAME) 0581 set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES FASTCOV_ARGS GENHTML_ARGS) 0582 cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 0583 0584 if(NOT FASTCOV_PATH) 0585 message(FATAL_ERROR "fastcov not found! Aborting...") 0586 endif() 0587 0588 if(NOT GENHTML_PATH) 0589 message(FATAL_ERROR "genhtml not found! Aborting...") 0590 endif() 0591 0592 # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR 0593 if(Coverage_BASE_DIRECTORY) 0594 get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) 0595 else() 0596 set(BASEDIR ${PROJECT_SOURCE_DIR}) 0597 endif() 0598 0599 # Collect excludes (Patterns, not paths, for fastcov) 0600 set(FASTCOV_EXCLUDES "") 0601 foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_FASTCOV_EXCLUDES}) 0602 list(APPEND FASTCOV_EXCLUDES "${EXCLUDE}") 0603 endforeach() 0604 list(REMOVE_DUPLICATES FASTCOV_EXCLUDES) 0605 0606 # Conditional arguments 0607 if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE}) 0608 set(GENHTML_EXTRA_ARGS "--demangle-cpp") 0609 endif() 0610 0611 # Set up commands which will be run to generate coverage data 0612 set(FASTCOV_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}) 0613 0614 set(FASTCOV_CAPTURE_CMD ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH} 0615 --search-directory ${BASEDIR} 0616 --process-gcno 0617 --lcov 0618 --output ${Coverage_NAME}.info 0619 --exclude ${FASTCOV_EXCLUDES} 0620 --exclude ${FASTCOV_EXCLUDES} 0621 ) 0622 0623 if(Coverage_SKIP_HTML) 0624 set(FASTCOV_HTML_CMD ";") 0625 else() 0626 set(FASTCOV_HTML_CMD ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} 0627 -o ${Coverage_NAME} ${Coverage_NAME}.info 0628 ) 0629 endif() 0630 0631 if(CODE_COVERAGE_VERBOSE) 0632 message(STATUS "Code coverage commands for target ${Coverage_NAME} (fastcov):") 0633 0634 message(" Running tests:") 0635 string(REPLACE ";" " " FASTCOV_EXEC_TESTS_CMD_SPACED "${FASTCOV_EXEC_TESTS_CMD}") 0636 message(" ${FASTCOV_EXEC_TESTS_CMD_SPACED}") 0637 0638 message(" Capturing fastcov counters and generating report:") 0639 string(REPLACE ";" " " FASTCOV_CAPTURE_CMD_SPACED "${FASTCOV_CAPTURE_CMD}") 0640 message(" ${FASTCOV_CAPTURE_CMD_SPACED}") 0641 0642 if(NOT Coverage_SKIP_HTML) 0643 message(" Generating HTML report: ") 0644 string(REPLACE ";" " " FASTCOV_HTML_CMD_SPACED "${FASTCOV_HTML_CMD}") 0645 message(" ${FASTCOV_HTML_CMD_SPACED}") 0646 endif() 0647 endif() 0648 0649 # Setup target 0650 add_custom_target(${Coverage_NAME} 0651 0652 # Cleanup fastcov 0653 COMMAND ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH} 0654 --search-directory ${BASEDIR} 0655 --zerocounters 0656 0657 COMMAND ${FASTCOV_EXEC_TESTS_CMD} 0658 COMMAND ${FASTCOV_CAPTURE_CMD} 0659 COMMAND ${FASTCOV_HTML_CMD} 0660 0661 # Set output files as GENERATED (will be removed on 'make clean') 0662 BYPRODUCTS 0663 ${Coverage_NAME}.info 0664 ${Coverage_NAME}/index.html # report directory 0665 0666 WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 0667 DEPENDS ${Coverage_DEPENDENCIES} 0668 VERBATIM # Protect arguments to commands 0669 COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report." 0670 ) 0671 0672 set(INFO_MSG "fastcov code coverage info report saved in ${Coverage_NAME}.info.") 0673 if(NOT Coverage_SKIP_HTML) 0674 string(APPEND INFO_MSG " Open ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html in your browser to view the coverage report.") 0675 endif() 0676 # Show where to find the fastcov info report 0677 add_custom_command(TARGET ${Coverage_NAME} POST_BUILD 0678 COMMAND ${CMAKE_COMMAND} -E echo ${INFO_MSG} 0679 ) 0680 0681 endfunction() # setup_target_for_coverage_fastcov 0682 0683 function(append_coverage_compiler_flags) 0684 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) 0685 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) 0686 set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) 0687 message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}") 0688 endfunction() # append_coverage_compiler_flags