CodeCoverage.cmake 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. # Copyright (c) 2012 - 2017, Lars Bilke
  2. # All rights reserved.
  3. #
  4. # Redistribution and use in source and binary forms, with or without modification,
  5. # are permitted provided that the following conditions are met:
  6. #
  7. # 1. Redistributions of source code must retain the above copyright notice, this
  8. # list of conditions and the following disclaimer.
  9. #
  10. # 2. Redistributions in binary form must reproduce the above copyright notice,
  11. # this list of conditions and the following disclaimer in the documentation
  12. # and/or other materials provided with the distribution.
  13. #
  14. # 3. Neither the name of the copyright holder nor the names of its contributors
  15. # may be used to endorse or promote products derived from this software without
  16. # specific prior written permission.
  17. #
  18. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  22. # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  25. # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. #
  29. # CHANGES:
  30. #
  31. # 2012-01-31, Lars Bilke
  32. # - Enable Code Coverage
  33. #
  34. # 2013-09-17, Joakim Söderberg
  35. # - Added support for Clang.
  36. # - Some additional usage instructions.
  37. #
  38. # 2016-02-03, Lars Bilke
  39. # - Refactored functions to use named parameters
  40. #
  41. # 2017-06-02, Lars Bilke
  42. # - Merged with modified version from github.com/ufz/ogs
  43. #
  44. # 2019-05-06, Anatolii Kurotych
  45. # - Remove unnecessary --coverage flag
  46. #
  47. # 2019-12-13, FeRD (Frank Dana)
  48. # - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor
  49. # of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments.
  50. # - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY
  51. # - All setup functions: accept BASE_DIRECTORY, EXCLUDE list
  52. # - Set lcov basedir with -b argument
  53. # - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be
  54. # overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().)
  55. # - Delete output dir, .info file on 'make clean'
  56. # - Remove Python detection, since version mismatches will break gcovr
  57. # - Minor cleanup (lowercase function names, update examples...)
  58. #
  59. # 2019-12-19, FeRD (Frank Dana)
  60. # - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets
  61. #
  62. # 2020-01-19, Bob Apthorpe
  63. # - Added gfortran support
  64. #
  65. # 2020-02-17, FeRD (Frank Dana)
  66. # - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters
  67. # in EXCLUDEs, and remove manual escaping from gcovr targets
  68. #
  69. # 2020-05-04, Mihchael Davis
  70. # - Add -fprofile-abs-path to make gcno files contain absolute paths
  71. # - Fix BASE_DIRECTORY not working when defined
  72. # - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines
  73. # USAGE:
  74. #
  75. # 1. Copy this file into your cmake modules path.
  76. #
  77. # 2. Add the following line to your CMakeLists.txt (best inside an if-condition
  78. # using a CMake option() to enable it just optionally):
  79. # include(CodeCoverage)
  80. #
  81. # 3. Append necessary compiler flags:
  82. # append_coverage_compiler_flags()
  83. #
  84. # 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og
  85. #
  86. # 4. If you need to exclude additional directories from the report, specify them
  87. # using full paths in the COVERAGE_EXCLUDES variable before calling
  88. # setup_target_for_coverage_*().
  89. # Example:
  90. # set(COVERAGE_EXCLUDES
  91. # '${PROJECT_SOURCE_DIR}/src/dir1/*'
  92. # '/path/to/my/src/dir2/*')
  93. # Or, use the EXCLUDE argument to setup_target_for_coverage_*().
  94. # Example:
  95. # setup_target_for_coverage_lcov(
  96. # NAME coverage
  97. # EXECUTABLE testrunner
  98. # EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*")
  99. #
  100. # 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set
  101. # relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR)
  102. # Example:
  103. # set(COVERAGE_EXCLUDES "dir1/*")
  104. # setup_target_for_coverage_gcovr_html(
  105. # NAME coverage
  106. # EXECUTABLE testrunner
  107. # BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src"
  108. # EXCLUDE "dir2/*")
  109. #
  110. # 5. Use the functions described below to create a custom make target which
  111. # runs your test executable and produces a code coverage report.
  112. #
  113. # 6. Build a Debug build:
  114. # cmake -DCMAKE_BUILD_TYPE=Debug ..
  115. # make
  116. # make my_coverage_target
  117. #
  118. include(CMakeParseArguments)
  119. # Check prereqs
  120. find_program( GCOV_PATH gcov )
  121. find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
  122. find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
  123. find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
  124. find_program( CPPFILT_PATH NAMES c++filt )
  125. if(NOT GCOV_PATH)
  126. message(FATAL_ERROR "gcov not found! Aborting...")
  127. endif() # NOT GCOV_PATH
  128. if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
  129. if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
  130. message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
  131. endif()
  132. elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
  133. if("${CMAKE_Fortran_COMPILER_ID}" MATCHES "[Ff]lang")
  134. # Do nothing; exit conditional without error if true
  135. elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU")
  136. # Do nothing; exit conditional without error if true
  137. else()
  138. message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
  139. endif()
  140. endif()
  141. set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage -fprofile-abs-path"
  142. CACHE INTERNAL "")
  143. set(CMAKE_Fortran_FLAGS_COVERAGE
  144. ${COVERAGE_COMPILER_FLAGS}
  145. CACHE STRING "Flags used by the Fortran compiler during coverage builds."
  146. FORCE )
  147. set(CMAKE_CXX_FLAGS_COVERAGE
  148. ${COVERAGE_COMPILER_FLAGS}
  149. CACHE STRING "Flags used by the C++ compiler during coverage builds."
  150. FORCE )
  151. set(CMAKE_C_FLAGS_COVERAGE
  152. ${COVERAGE_COMPILER_FLAGS}
  153. CACHE STRING "Flags used by the C compiler during coverage builds."
  154. FORCE )
  155. set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
  156. ""
  157. CACHE STRING "Flags used for linking binaries during coverage builds."
  158. FORCE )
  159. set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
  160. ""
  161. CACHE STRING "Flags used by the shared libraries linker during coverage builds."
  162. FORCE )
  163. mark_as_advanced(
  164. CMAKE_Fortran_FLAGS_COVERAGE
  165. CMAKE_CXX_FLAGS_COVERAGE
  166. CMAKE_C_FLAGS_COVERAGE
  167. CMAKE_EXE_LINKER_FLAGS_COVERAGE
  168. CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
  169. if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
  170. message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
  171. endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
  172. if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
  173. link_libraries(gcov)
  174. endif()
  175. # Defines a target for running and collection code coverage information
  176. # Builds dependencies, runs the given executable and outputs reports.
  177. # NOTE! The executable should always have a ZERO as exit code otherwise
  178. # the coverage generation will not complete.
  179. #
  180. # setup_target_for_coverage_lcov(
  181. # NAME testrunner_coverage # New target name
  182. # EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
  183. # DEPENDENCIES testrunner # Dependencies to build first
  184. # BASE_DIRECTORY "../" # Base directory for report
  185. # # (defaults to PROJECT_SOURCE_DIR)
  186. # EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
  187. # # to BASE_DIRECTORY, with CMake 3.4+)
  188. # NO_DEMANGLE # Don't demangle C++ symbols
  189. # # even if c++filt is found
  190. # )
  191. function(setup_target_for_coverage_lcov)
  192. set(options NO_DEMANGLE)
  193. set(oneValueArgs BASE_DIRECTORY NAME)
  194. set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
  195. cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  196. if(NOT LCOV_PATH)
  197. message(FATAL_ERROR "lcov not found! Aborting...")
  198. endif() # NOT LCOV_PATH
  199. if(NOT GENHTML_PATH)
  200. message(FATAL_ERROR "genhtml not found! Aborting...")
  201. endif() # NOT GENHTML_PATH
  202. # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
  203. if(DEFINED Coverage_BASE_DIRECTORY)
  204. get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
  205. else()
  206. set(BASEDIR ${PROJECT_SOURCE_DIR})
  207. endif()
  208. # Collect excludes (CMake 3.4+: Also compute absolute paths)
  209. set(LCOV_EXCLUDES "")
  210. foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES})
  211. if(CMAKE_VERSION VERSION_GREATER 3.4)
  212. get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
  213. endif()
  214. list(APPEND LCOV_EXCLUDES "${EXCLUDE}")
  215. endforeach()
  216. list(REMOVE_DUPLICATES LCOV_EXCLUDES)
  217. # Conditional arguments
  218. if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
  219. set(GENHTML_EXTRA_ARGS "--demangle-cpp")
  220. endif()
  221. # Setup target
  222. add_custom_target(${Coverage_NAME}
  223. # Cleanup lcov
  224. COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . -b ${BASEDIR} --zerocounters
  225. # Create baseline to make sure untouched files show up in the report
  226. COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b ${BASEDIR} -o ${Coverage_NAME}.base
  227. # Run tests
  228. COMMAND ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
  229. # Capturing lcov counters and generating report
  230. COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b ${BASEDIR} --capture --output-file ${Coverage_NAME}.capture
  231. # add baseline counters
  232. COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total
  233. # filter collected data to final coverage report
  234. COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info
  235. # Generate HTML output
  236. COMMAND ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o ${Coverage_NAME} ${Coverage_NAME}.info
  237. # Set output files as GENERATED (will be removed on 'make clean')
  238. BYPRODUCTS
  239. ${Coverage_NAME}.base
  240. ${Coverage_NAME}.capture
  241. ${Coverage_NAME}.total
  242. ${Coverage_NAME}.info
  243. ${Coverage_NAME}/index.html
  244. WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
  245. DEPENDS ${Coverage_DEPENDENCIES}
  246. VERBATIM # Protect arguments to commands
  247. COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
  248. )
  249. # Show where to find the lcov info report
  250. add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
  251. COMMAND ;
  252. COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
  253. )
  254. # Show info where to find the report
  255. add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
  256. COMMAND ;
  257. COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
  258. )
  259. endfunction() # setup_target_for_coverage_lcov
  260. # Defines a target for running and collection code coverage information
  261. # Builds dependencies, runs the given executable and outputs reports.
  262. # NOTE! The executable should always have a ZERO as exit code otherwise
  263. # the coverage generation will not complete.
  264. #
  265. # setup_target_for_coverage_gcovr_xml(
  266. # NAME ctest_coverage # New target name
  267. # EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
  268. # DEPENDENCIES executable_target # Dependencies to build first
  269. # BASE_DIRECTORY "../" # Base directory for report
  270. # # (defaults to PROJECT_SOURCE_DIR)
  271. # EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
  272. # # to BASE_DIRECTORY, with CMake 3.4+)
  273. # )
  274. function(setup_target_for_coverage_gcovr_xml)
  275. set(options NONE)
  276. set(oneValueArgs BASE_DIRECTORY NAME)
  277. set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
  278. cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  279. if(NOT GCOVR_PATH)
  280. message(FATAL_ERROR "gcovr not found! Aborting...")
  281. endif() # NOT GCOVR_PATH
  282. # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
  283. if(DEFINED Coverage_BASE_DIRECTORY)
  284. get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
  285. else()
  286. set(BASEDIR ${PROJECT_SOURCE_DIR})
  287. endif()
  288. # Collect excludes (CMake 3.4+: Also compute absolute paths)
  289. set(GCOVR_EXCLUDES "")
  290. foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
  291. if(CMAKE_VERSION VERSION_GREATER 3.4)
  292. get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
  293. endif()
  294. list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
  295. endforeach()
  296. list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
  297. # Combine excludes to several -e arguments
  298. set(GCOVR_EXCLUDE_ARGS "")
  299. foreach(EXCLUDE ${GCOVR_EXCLUDES})
  300. list(APPEND GCOVR_EXCLUDE_ARGS "-e")
  301. list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
  302. endforeach()
  303. add_custom_target(${Coverage_NAME}
  304. # Run tests
  305. ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
  306. # Running gcovr
  307. COMMAND ${GCOVR_PATH} --xml
  308. -r ${BASEDIR} ${GCOVR_EXCLUDE_ARGS}
  309. --object-directory=${PROJECT_BINARY_DIR}
  310. -o ${Coverage_NAME}.xml
  311. BYPRODUCTS ${Coverage_NAME}.xml
  312. WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
  313. DEPENDS ${Coverage_DEPENDENCIES}
  314. VERBATIM # Protect arguments to commands
  315. COMMENT "Running gcovr to produce Cobertura code coverage report."
  316. )
  317. # Show info where to find the report
  318. add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
  319. COMMAND ;
  320. COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
  321. )
  322. endfunction() # setup_target_for_coverage_gcovr_xml
  323. # Defines a target for running and collection code coverage information
  324. # Builds dependencies, runs the given executable and outputs reports.
  325. # NOTE! The executable should always have a ZERO as exit code otherwise
  326. # the coverage generation will not complete.
  327. #
  328. # setup_target_for_coverage_gcovr_html(
  329. # NAME ctest_coverage # New target name
  330. # EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
  331. # DEPENDENCIES executable_target # Dependencies to build first
  332. # BASE_DIRECTORY "../" # Base directory for report
  333. # # (defaults to PROJECT_SOURCE_DIR)
  334. # EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
  335. # # to BASE_DIRECTORY, with CMake 3.4+)
  336. # )
  337. function(setup_target_for_coverage_gcovr_html)
  338. set(options NONE)
  339. set(oneValueArgs BASE_DIRECTORY NAME)
  340. set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
  341. cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  342. if(NOT GCOVR_PATH)
  343. message(FATAL_ERROR "gcovr not found! Aborting...")
  344. endif() # NOT GCOVR_PATH
  345. # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
  346. if(DEFINED Coverage_BASE_DIRECTORY)
  347. get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
  348. else()
  349. set(BASEDIR ${PROJECT_SOURCE_DIR})
  350. endif()
  351. # Collect excludes (CMake 3.4+: Also compute absolute paths)
  352. set(GCOVR_EXCLUDES "")
  353. foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
  354. if(CMAKE_VERSION VERSION_GREATER 3.4)
  355. get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
  356. endif()
  357. list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
  358. endforeach()
  359. list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
  360. # Combine excludes to several -e arguments
  361. set(GCOVR_EXCLUDE_ARGS "")
  362. foreach(EXCLUDE ${GCOVR_EXCLUDES})
  363. list(APPEND GCOVR_EXCLUDE_ARGS "-e")
  364. list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
  365. endforeach()
  366. add_custom_target(${Coverage_NAME}
  367. # Run tests
  368. ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
  369. # Create folder
  370. COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
  371. # Running gcovr
  372. COMMAND ${GCOVR_PATH} --html --html-details
  373. -r ${BASEDIR} ${GCOVR_EXCLUDE_ARGS}
  374. --object-directory=${PROJECT_BINARY_DIR}
  375. -o ${Coverage_NAME}/index.html
  376. BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory
  377. WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
  378. DEPENDS ${Coverage_DEPENDENCIES}
  379. VERBATIM # Protect arguments to commands
  380. COMMENT "Running gcovr to produce HTML code coverage report."
  381. )
  382. # Show info where to find the report
  383. add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
  384. COMMAND ;
  385. COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
  386. )
  387. endfunction() # setup_target_for_coverage_gcovr_html
  388. function(append_coverage_compiler_flags)
  389. set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
  390. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
  391. set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
  392. message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
  393. endfunction() # append_coverage_compiler_flags