CTestCoverageCollectGCOV.cmake 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. #.rst:
  2. # CTestCoverageCollectGCOV
  3. # ------------------------
  4. #
  5. # This module provides the function ``ctest_coverage_collect_gcov``.
  6. # The function will run gcov on the .gcda files in a binary tree and then
  7. # package all of the .gcov files into a tar file with a data.json that
  8. # contains the source and build directories for CDash to use in parsing
  9. # the coverage data. In addtion the Labels.json files for targets that
  10. # have coverage information are also put in the tar file for CDash to
  11. # asign the correct labels. This file can be sent to a CDash server for
  12. # display with the
  13. # :command:`ctest_submit(CDASH_UPLOAD)` command.
  14. #
  15. # .. command:: cdash_coverage_collect_gcov
  16. #
  17. # ::
  18. #
  19. # ctest_coverage_collect_gcov(TARBALL <tarfile>
  20. # [SOURCE <source_dir>][BUILD <build_dir>]
  21. # [GCOV_COMMAND <gcov_command>]
  22. # [GCOV_OPTIONS <options>...]
  23. # )
  24. #
  25. # Run gcov and package a tar file for CDash. The options are:
  26. #
  27. # ``TARBALL <tarfile>``
  28. # Specify the location of the ``.tar`` file to be created for later
  29. # upload to CDash. Relative paths will be interpreted with respect
  30. # to the top-level build directory.
  31. #
  32. # ``SOURCE <source_dir>``
  33. # Specify the top-level source directory for the build.
  34. # Default is the value of :variable:`CTEST_SOURCE_DIRECTORY`.
  35. #
  36. # ``BUILD <build_dir>``
  37. # Specify the top-level build directory for the build.
  38. # Default is the value of :variable:`CTEST_BINARY_DIRECTORY`.
  39. #
  40. # ``GCOV_COMMAND <gcov_command>``
  41. # Specify the full path to the ``gcov`` command on the machine.
  42. # Default is the value of :variable:`CTEST_COVERAGE_COMMAND`.
  43. #
  44. # ``GCOV_OPTIONS <options>...``
  45. # Specify options to be passed to gcov. The ``gcov`` command
  46. # is run as ``gcov <options>... -o <gcov-dir> <file>.gcda``.
  47. # If not specified, the default option is just ``-b``.
  48. #=============================================================================
  49. # Copyright 2014-2015 Kitware, Inc.
  50. #
  51. # Distributed under the OSI-approved BSD License (the "License");
  52. # see accompanying file Copyright.txt for details.
  53. #
  54. # This software is distributed WITHOUT ANY WARRANTY; without even the
  55. # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  56. # See the License for more information.
  57. #=============================================================================
  58. # (To distribute this file outside of CMake, substitute the full
  59. # License text for the above reference.)
  60. include(CMakeParseArguments)
  61. function(ctest_coverage_collect_gcov)
  62. set(options "")
  63. set(oneValueArgs TARBALL SOURCE BUILD GCOV_COMMAND)
  64. set(multiValueArgs GCOV_OPTIONS)
  65. cmake_parse_arguments(GCOV "${options}" "${oneValueArgs}"
  66. "${multiValueArgs}" "" ${ARGN} )
  67. if(NOT DEFINED GCOV_TARBALL)
  68. message(FATAL_ERROR
  69. "TARBALL must be specified. for ctest_coverage_collect_gcov")
  70. endif()
  71. if(NOT DEFINED GCOV_SOURCE)
  72. set(source_dir "${CTEST_SOURCE_DIRECTORY}")
  73. else()
  74. set(source_dir "${GCOV_SOURCE}")
  75. endif()
  76. if(NOT DEFINED GCOV_BUILD)
  77. set(binary_dir "${CTEST_BINARY_DIRECTORY}")
  78. else()
  79. set(binary_dir "${GCOV_BUILD}")
  80. endif()
  81. if(NOT DEFINED GCOV_GCOV_COMMAND)
  82. set(gcov_command "${CTEST_COVERAGE_COMMAND}")
  83. else()
  84. set(gcov_command "${GCOV_GCOV_COMMAND}")
  85. endif()
  86. # run gcov on each gcda file in the binary tree
  87. set(gcda_files)
  88. set(label_files)
  89. # look for gcda files in the target directories
  90. # could do a glob from the top of the binary tree but
  91. # this will be faster and only look where the files will be
  92. file(STRINGS "${binary_dir}/CMakeFiles/TargetDirectories.txt" target_dirs
  93. ENCODING UTF-8)
  94. foreach(target_dir ${target_dirs})
  95. file(GLOB_RECURSE gfiles RELATIVE ${binary_dir} "${target_dir}/*.gcda")
  96. list(LENGTH gfiles len)
  97. # if we have gcda files then also grab the labels file for that target
  98. if(${len} GREATER 0)
  99. file(GLOB_RECURSE lfiles RELATIVE ${binary_dir}
  100. "${target_dir}/Labels.json")
  101. list(APPEND gcda_files ${gfiles})
  102. list(APPEND label_files ${lfiles})
  103. endif()
  104. endforeach()
  105. # return early if no coverage files were found
  106. list(LENGTH gcda_files len)
  107. if(len EQUAL 0)
  108. message("ctest_coverage_collect_gcov: No .gcda files found, "
  109. "ignoring coverage request.")
  110. return()
  111. endif()
  112. # setup the dir for the coverage files
  113. set(coverage_dir "${binary_dir}/Testing/CoverageInfo")
  114. file(MAKE_DIRECTORY "${coverage_dir}")
  115. # call gcov on each .gcda file
  116. foreach (gcda_file ${gcda_files})
  117. # get the directory of the gcda file
  118. get_filename_component(gcda_file ${binary_dir}/${gcda_file} ABSOLUTE)
  119. get_filename_component(gcov_dir ${gcda_file} DIRECTORY)
  120. # run gcov, this will produce the .gcov file in the current
  121. # working directory
  122. if(NOT DEFINED GCOV_GCOV_OPTIONS)
  123. set(GCOV_GCOV_OPTIONS -b)
  124. endif()
  125. execute_process(COMMAND
  126. ${gcov_command} ${GCOV_GCOV_OPTIONS} -o ${gcov_dir} ${gcda_file}
  127. OUTPUT_VARIABLE out
  128. RESULT_VARIABLE res
  129. WORKING_DIRECTORY ${coverage_dir})
  130. endforeach()
  131. if(NOT "${res}" EQUAL 0)
  132. message(STATUS "Error running gcov: ${res} ${out}")
  133. endif()
  134. # create json file with project information
  135. file(WRITE ${coverage_dir}/data.json
  136. "{
  137. \"Source\": \"${source_dir}\",
  138. \"Binary\": \"${binary_dir}\"
  139. }")
  140. # collect the gcov files
  141. set(gcov_files)
  142. file(GLOB_RECURSE gcov_files RELATIVE ${binary_dir} "${coverage_dir}/*.gcov")
  143. # tar up the coverage info with the same date so that the md5
  144. # sum will be the same for the tar file independent of file time
  145. # stamps
  146. string(REPLACE ";" "\n" gcov_files "${gcov_files}")
  147. string(REPLACE ";" "\n" label_files "${label_files}")
  148. file(WRITE "${coverage_dir}/coverage_file_list.txt"
  149. "${gcov_files}
  150. ${coverage_dir}/data.json
  151. ${label_files}
  152. ")
  153. execute_process(COMMAND
  154. ${CMAKE_COMMAND} -E tar cvfj ${GCOV_TARBALL}
  155. "--mtime=1970-01-01 0:0:0 UTC"
  156. --files-from=${coverage_dir}/coverage_file_list.txt
  157. WORKING_DIRECTORY ${binary_dir})
  158. endfunction()