CodeCoverage.cmake 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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. include(CheckCXXCompilerFlag)
  142. CHECK_CXX_COMPILER_FLAG(-fprofile-abs-path ProfileAbsPathAvailable)
  143. if (ProfileAbsPathAvailable)
  144. set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage -fprofile-abs-path"
  145. CACHE INTERNAL "")
  146. else()
  147. set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage"
  148. CACHE INTERNAL "")
  149. endif()
  150. set(CMAKE_Fortran_FLAGS_COVERAGE
  151. ${COVERAGE_COMPILER_FLAGS}
  152. CACHE STRING "Flags used by the Fortran compiler during coverage builds."
  153. FORCE )
  154. set(CMAKE_CXX_FLAGS_COVERAGE
  155. ${COVERAGE_COMPILER_FLAGS}
  156. CACHE STRING "Flags used by the C++ compiler during coverage builds."
  157. FORCE )
  158. set(CMAKE_C_FLAGS_COVERAGE
  159. ${COVERAGE_COMPILER_FLAGS}
  160. CACHE STRING "Flags used by the C compiler during coverage builds."
  161. FORCE )
  162. set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
  163. ""
  164. CACHE STRING "Flags used for linking binaries during coverage builds."
  165. FORCE )
  166. set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
  167. ""
  168. CACHE STRING "Flags used by the shared libraries linker during coverage builds."
  169. FORCE )
  170. mark_as_advanced(
  171. CMAKE_Fortran_FLAGS_COVERAGE
  172. CMAKE_CXX_FLAGS_COVERAGE
  173. CMAKE_C_FLAGS_COVERAGE
  174. CMAKE_EXE_LINKER_FLAGS_COVERAGE
  175. CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
  176. if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
  177. message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
  178. endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
  179. if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
  180. link_libraries(gcov)
  181. endif()
  182. # Defines a target for running and collection code coverage information
  183. # Builds dependencies, runs the given executable and outputs reports.
  184. # NOTE! The executable should always have a ZERO as exit code otherwise
  185. # the coverage generation will not complete.
  186. #
  187. # setup_target_for_coverage_lcov(
  188. # NAME testrunner_coverage # New target name
  189. # EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
  190. # DEPENDENCIES testrunner # Dependencies to build first
  191. # BASE_DIRECTORY "../" # Base directory for report
  192. # # (defaults to PROJECT_SOURCE_DIR)
  193. # EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
  194. # # to BASE_DIRECTORY, with CMake 3.4+)
  195. # NO_DEMANGLE # Don't demangle C++ symbols
  196. # # even if c++filt is found
  197. # )
  198. function(setup_target_for_coverage_lcov)
  199. set(options NO_DEMANGLE)
  200. set(oneValueArgs BASE_DIRECTORY NAME)
  201. set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
  202. cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  203. if(NOT LCOV_PATH)
  204. message(FATAL_ERROR "lcov not found! Aborting...")
  205. endif() # NOT LCOV_PATH
  206. if(NOT GENHTML_PATH)
  207. message(FATAL_ERROR "genhtml not found! Aborting...")
  208. endif() # NOT GENHTML_PATH
  209. # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
  210. if(DEFINED Coverage_BASE_DIRECTORY)
  211. get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
  212. else()
  213. set(BASEDIR ${PROJECT_SOURCE_DIR})
  214. endif()
  215. # Collect excludes (CMake 3.4+: Also compute absolute paths)
  216. set(LCOV_EXCLUDES "")
  217. foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES})
  218. if(CMAKE_VERSION VERSION_GREATER 3.4)
  219. get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
  220. endif()
  221. list(APPEND LCOV_EXCLUDES "${EXCLUDE}")
  222. endforeach()
  223. list(REMOVE_DUPLICATES LCOV_EXCLUDES)
  224. # Conditional arguments
  225. if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
  226. set(GENHTML_EXTRA_ARGS "--demangle-cpp")
  227. endif()
  228. # Setup target
  229. add_custom_target(${Coverage_NAME}
  230. # Cleanup lcov
  231. COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . -b ${BASEDIR} --zerocounters
  232. # Create baseline to make sure untouched files show up in the report
  233. COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b ${BASEDIR} -o ${Coverage_NAME}.base
  234. # Run tests
  235. COMMAND ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
  236. # Capturing lcov counters and generating report
  237. COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b ${BASEDIR} --capture --output-file ${Coverage_NAME}.capture
  238. # add baseline counters
  239. COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total
  240. # filter collected data to final coverage report
  241. COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info
  242. # Generate HTML output
  243. COMMAND ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o ${Coverage_NAME} ${Coverage_NAME}.info
  244. # Set output files as GENERATED (will be removed on 'make clean')
  245. BYPRODUCTS
  246. ${Coverage_NAME}.base
  247. ${Coverage_NAME}.capture
  248. ${Coverage_NAME}.total
  249. ${Coverage_NAME}.info
  250. ${Coverage_NAME}/index.html
  251. WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
  252. DEPENDS ${Coverage_DEPENDENCIES}
  253. VERBATIM # Protect arguments to commands
  254. COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
  255. )
  256. # Show where to find the lcov info report
  257. add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
  258. COMMAND ;
  259. COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
  260. )
  261. # Show info where to find the report
  262. add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
  263. COMMAND ;
  264. COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
  265. )
  266. endfunction() # setup_target_for_coverage_lcov
  267. # Defines a target for running and collection code coverage information
  268. # Builds dependencies, runs the given executable and outputs reports.
  269. # NOTE! The executable should always have a ZERO as exit code otherwise
  270. # the coverage generation will not complete.
  271. #
  272. # setup_target_for_coverage_gcovr_xml(
  273. # NAME ctest_coverage # New target name
  274. # EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
  275. # DEPENDENCIES executable_target # Dependencies to build first
  276. # BASE_DIRECTORY "../" # Base directory for report
  277. # # (defaults to PROJECT_SOURCE_DIR)
  278. # EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
  279. # # to BASE_DIRECTORY, with CMake 3.4+)
  280. # )
  281. function(setup_target_for_coverage_gcovr_xml)
  282. set(options NONE)
  283. set(oneValueArgs BASE_DIRECTORY NAME)
  284. set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
  285. cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  286. if(NOT GCOVR_PATH)
  287. message(FATAL_ERROR "gcovr not found! Aborting...")
  288. endif() # NOT GCOVR_PATH
  289. # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
  290. if(DEFINED Coverage_BASE_DIRECTORY)
  291. get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
  292. else()
  293. set(BASEDIR ${PROJECT_SOURCE_DIR})
  294. endif()
  295. # Collect excludes (CMake 3.4+: Also compute absolute paths)
  296. set(GCOVR_EXCLUDES "")
  297. foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
  298. if(CMAKE_VERSION VERSION_GREATER 3.4)
  299. get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
  300. endif()
  301. list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
  302. endforeach()
  303. list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
  304. # Combine excludes to several -e arguments
  305. set(GCOVR_EXCLUDE_ARGS "")
  306. foreach(EXCLUDE ${GCOVR_EXCLUDES})
  307. list(APPEND GCOVR_EXCLUDE_ARGS "-e")
  308. list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
  309. endforeach()
  310. add_custom_target(${Coverage_NAME}
  311. # Run tests
  312. ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
  313. # Running gcovr
  314. COMMAND ${GCOVR_PATH} --xml
  315. -r ${BASEDIR} ${GCOVR_EXCLUDE_ARGS}
  316. --object-directory=${PROJECT_BINARY_DIR}
  317. -o ${Coverage_NAME}.xml
  318. BYPRODUCTS ${Coverage_NAME}.xml
  319. WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
  320. DEPENDS ${Coverage_DEPENDENCIES}
  321. VERBATIM # Protect arguments to commands
  322. COMMENT "Running gcovr to produce Cobertura code coverage report."
  323. )
  324. # Show info where to find the report
  325. add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
  326. COMMAND ;
  327. COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
  328. )
  329. endfunction() # setup_target_for_coverage_gcovr_xml
  330. # Defines a target for running and collection code coverage information
  331. # Builds dependencies, runs the given executable and outputs reports.
  332. # NOTE! The executable should always have a ZERO as exit code otherwise
  333. # the coverage generation will not complete.
  334. #
  335. # setup_target_for_coverage_gcovr_html(
  336. # NAME ctest_coverage # New target name
  337. # EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
  338. # DEPENDENCIES executable_target # Dependencies to build first
  339. # BASE_DIRECTORY "../" # Base directory for report
  340. # # (defaults to PROJECT_SOURCE_DIR)
  341. # EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
  342. # # to BASE_DIRECTORY, with CMake 3.4+)
  343. # )
  344. function(setup_target_for_coverage_gcovr_html)
  345. set(options NONE)
  346. set(oneValueArgs BASE_DIRECTORY NAME)
  347. set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
  348. cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  349. if(NOT GCOVR_PATH)
  350. message(FATAL_ERROR "gcovr not found! Aborting...")
  351. endif() # NOT GCOVR_PATH
  352. # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
  353. if(DEFINED Coverage_BASE_DIRECTORY)
  354. get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
  355. else()
  356. set(BASEDIR ${PROJECT_SOURCE_DIR})
  357. endif()
  358. # Collect excludes (CMake 3.4+: Also compute absolute paths)
  359. set(GCOVR_EXCLUDES "")
  360. foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
  361. if(CMAKE_VERSION VERSION_GREATER 3.4)
  362. get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
  363. endif()
  364. list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
  365. endforeach()
  366. list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
  367. # Combine excludes to several -e arguments
  368. set(GCOVR_EXCLUDE_ARGS "")
  369. foreach(EXCLUDE ${GCOVR_EXCLUDES})
  370. list(APPEND GCOVR_EXCLUDE_ARGS "-e")
  371. list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
  372. endforeach()
  373. add_custom_target(${Coverage_NAME}
  374. # Run tests
  375. ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
  376. # Create folder
  377. COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
  378. # Running gcovr
  379. COMMAND ${GCOVR_PATH} --html --html-details
  380. -r ${BASEDIR} ${GCOVR_EXCLUDE_ARGS}
  381. --object-directory=${PROJECT_BINARY_DIR}
  382. -o ${Coverage_NAME}/index.html
  383. BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory
  384. WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
  385. DEPENDS ${Coverage_DEPENDENCIES}
  386. VERBATIM # Protect arguments to commands
  387. COMMENT "Running gcovr to produce HTML code coverage report."
  388. )
  389. # Show info where to find the report
  390. add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
  391. COMMAND ;
  392. COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
  393. )
  394. endfunction() # setup_target_for_coverage_gcovr_html
  395. function(append_coverage_compiler_flags)
  396. set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
  397. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
  398. set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
  399. message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
  400. endfunction() # append_coverage_compiler_flags