Joe Hildebrand | 7c6c356 | 2015-03-31 00:21:21 -0600 | [diff] [blame] | 1 | # |
| 2 | # Permission is hereby granted, free of charge, to any person obtaining a copy |
| 3 | # of this software and associated documentation files (the "Software"), to deal |
| 4 | # in the Software without restriction, including without limitation the rights |
| 5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 6 | # copies of the Software, and to permit persons to whom the Software is |
| 7 | # furnished to do so, subject to the following conditions: |
| 8 | # |
| 9 | # The above copyright notice and this permission notice shall be included in all |
| 10 | # copies or substantial portions of the Software. |
| 11 | # |
| 12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 18 | # SOFTWARE. |
| 19 | # |
| 20 | # Copyright (C) 2014 Joakim Söderberg <joakim.soderberg@gmail.com> |
| 21 | # |
| 22 | # This is intended to be run by a custom target in a CMake project like this. |
| 23 | # 0. Compile program with coverage support. |
| 24 | # 1. Clear coverage data. (Recursively delete *.gcda in build dir) |
| 25 | # 2. Run the unit tests. |
| 26 | # 3. Run this script specifying which source files the coverage should be performed on. |
| 27 | # |
| 28 | # This script will then use gcov to generate .gcov files in the directory specified |
| 29 | # via the COV_PATH var. This should probably be the same as your cmake build dir. |
| 30 | # |
| 31 | # It then parses the .gcov files to convert them into the Coveralls JSON format: |
| 32 | # https://coveralls.io/docs/api |
| 33 | # |
| 34 | # Example for running as standalone CMake script from the command line: |
| 35 | # (Note it is important the -P is at the end...) |
| 36 | # $ cmake -DCOV_PATH=$(pwd) |
| 37 | # -DCOVERAGE_SRCS="catcierge_rfid.c;catcierge_timer.c" |
| 38 | # -P ../cmake/CoverallsGcovUpload.cmake |
| 39 | # |
| 40 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) |
| 41 | |
| 42 | |
| 43 | # |
| 44 | # Make sure we have the needed arguments. |
| 45 | # |
| 46 | if (NOT COVERALLS_OUTPUT_FILE) |
| 47 | message(FATAL_ERROR "Coveralls: No coveralls output file specified. Please set COVERALLS_OUTPUT_FILE") |
| 48 | endif() |
| 49 | |
| 50 | if (NOT COV_PATH) |
| 51 | message(FATAL_ERROR "Coveralls: Missing coverage directory path where gcov files will be generated. Please set COV_PATH") |
| 52 | endif() |
| 53 | |
| 54 | if (NOT COVERAGE_SRCS) |
| 55 | message(FATAL_ERROR "Coveralls: Missing the list of source files that we should get the coverage data for COVERAGE_SRCS") |
| 56 | endif() |
| 57 | |
| 58 | if (NOT PROJECT_ROOT) |
| 59 | message(FATAL_ERROR "Coveralls: Missing PROJECT_ROOT.") |
| 60 | endif() |
| 61 | |
| 62 | # Since it's not possible to pass a CMake list properly in the |
| 63 | # "1;2;3" format to an external process, we have replaced the |
| 64 | # ";" with "*", so reverse that here so we get it back into the |
| 65 | # CMake list format. |
| 66 | string(REGEX REPLACE "\\*" ";" COVERAGE_SRCS ${COVERAGE_SRCS}) |
| 67 | |
| 68 | find_program(GCOV_EXECUTABLE gcov) |
| 69 | |
| 70 | if (NOT GCOV_EXECUTABLE) |
| 71 | message(FATAL_ERROR "gcov not found! Aborting...") |
| 72 | endif() |
| 73 | |
| 74 | find_package(Git) |
| 75 | |
| 76 | # TODO: Add these git things to the coveralls json. |
| 77 | if (GIT_FOUND) |
| 78 | # Branch. |
| 79 | execute_process( |
| 80 | COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD |
| 81 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} |
| 82 | OUTPUT_VARIABLE GIT_BRANCH |
| 83 | OUTPUT_STRIP_TRAILING_WHITESPACE |
| 84 | ) |
| 85 | |
| 86 | macro (git_log_format FORMAT_CHARS VAR_NAME) |
| 87 | execute_process( |
| 88 | COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%${FORMAT_CHARS} |
| 89 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} |
| 90 | OUTPUT_VARIABLE ${VAR_NAME} |
| 91 | OUTPUT_STRIP_TRAILING_WHITESPACE |
| 92 | ) |
| 93 | endmacro() |
| 94 | |
| 95 | git_log_format(an GIT_AUTHOR_EMAIL) |
| 96 | git_log_format(ae GIT_AUTHOR_EMAIL) |
| 97 | git_log_format(cn GIT_COMMITTER_NAME) |
| 98 | git_log_format(ce GIT_COMMITTER_EMAIL) |
| 99 | git_log_format(B GIT_COMMIT_MESSAGE) |
| 100 | |
| 101 | message("Git exe: ${GIT_EXECUTABLE}") |
| 102 | message("Git branch: ${GIT_BRANCH}") |
| 103 | message("Git author: ${GIT_AUTHOR_NAME}") |
| 104 | message("Git e-mail: ${GIT_AUTHOR_EMAIL}") |
| 105 | message("Git commiter name: ${GIT_COMMITTER_NAME}") |
| 106 | message("Git commiter e-mail: ${GIT_COMMITTER_EMAIL}") |
| 107 | message("Git commit message: ${GIT_COMMIT_MESSAGE}") |
| 108 | |
| 109 | endif() |
| 110 | |
| 111 | ############################# Macros ######################################### |
| 112 | |
| 113 | # |
| 114 | # This macro converts from the full path format gcov outputs: |
| 115 | # |
| 116 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov |
| 117 | # |
| 118 | # to the original source file path the .gcov is for: |
| 119 | # |
| 120 | # /path/to/project/root/subdir/the_file.c |
| 121 | # |
| 122 | macro(get_source_path_from_gcov_filename _SRC_FILENAME _GCOV_FILENAME) |
| 123 | |
| 124 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov |
| 125 | # -> |
| 126 | # #path#to#project#root#subdir#the_file.c.gcov |
| 127 | get_filename_component(_GCOV_FILENAME_WEXT ${_GCOV_FILENAME} NAME) |
| 128 | |
| 129 | # #path#to#project#root#subdir#the_file.c.gcov -> /path/to/project/root/subdir/the_file.c |
| 130 | string(REGEX REPLACE "\\.gcov$" "" SRC_FILENAME_TMP ${_GCOV_FILENAME_WEXT}) |
| 131 | string(REGEX REPLACE "\#" "/" SRC_FILENAME_TMP ${SRC_FILENAME_TMP}) |
| 132 | set(${_SRC_FILENAME} "${SRC_FILENAME_TMP}") |
| 133 | endmacro() |
| 134 | |
| 135 | ############################################################################## |
| 136 | |
| 137 | # Get the coverage data. |
| 138 | file(GLOB_RECURSE GCDA_FILES "${COV_PATH}/*.gcda") |
| 139 | message("GCDA files:") |
| 140 | |
| 141 | # Get a list of all the object directories needed by gcov |
| 142 | # (The directories the .gcda files and .o files are found in) |
| 143 | # and run gcov on those. |
| 144 | foreach(GCDA ${GCDA_FILES}) |
| 145 | message("Process: ${GCDA}") |
| 146 | message("------------------------------------------------------------------------------") |
| 147 | get_filename_component(GCDA_DIR ${GCDA} PATH) |
| 148 | |
| 149 | # |
| 150 | # The -p below refers to "Preserve path components", |
| 151 | # This means that the generated gcov filename of a source file will |
| 152 | # keep the original files entire filepath, but / is replaced with #. |
| 153 | # Example: |
| 154 | # |
| 155 | # /path/to/project/root/build/CMakeFiles/the_file.dir/subdir/the_file.c.gcda |
| 156 | # ------------------------------------------------------------------------------ |
| 157 | # File '/path/to/project/root/subdir/the_file.c' |
| 158 | # Lines executed:68.34% of 199 |
| 159 | # /path/to/project/root/subdir/the_file.c:creating '#path#to#project#root#subdir#the_file.c.gcov' |
| 160 | # |
| 161 | # If -p is not specified then the file is named only "the_file.c.gcov" |
| 162 | # |
| 163 | execute_process( |
Joe Hildebrand | c323262 | 2015-04-05 14:50:43 -0600 | [diff] [blame] | 164 | COMMAND ${GCOV_EXECUTABLE} -c -p -o ${GCDA_DIR} ${GCDA} |
Joe Hildebrand | 7c6c356 | 2015-03-31 00:21:21 -0600 | [diff] [blame] | 165 | WORKING_DIRECTORY ${COV_PATH} |
| 166 | ) |
| 167 | endforeach() |
| 168 | |
| 169 | # TODO: Make these be absolute path |
| 170 | file(GLOB ALL_GCOV_FILES ${COV_PATH}/*.gcov) |
| 171 | |
| 172 | # Get only the filenames to use for filtering. |
| 173 | #set(COVERAGE_SRCS_NAMES "") |
| 174 | #foreach (COVSRC ${COVERAGE_SRCS}) |
| 175 | # get_filename_component(COVSRC_NAME ${COVSRC} NAME) |
| 176 | # message("${COVSRC} -> ${COVSRC_NAME}") |
| 177 | # list(APPEND COVERAGE_SRCS_NAMES "${COVSRC_NAME}") |
| 178 | #endforeach() |
| 179 | |
| 180 | # |
| 181 | # Filter out all but the gcov files we want. |
| 182 | # |
| 183 | # We do this by comparing the list of COVERAGE_SRCS filepaths that the |
| 184 | # user wants the coverage data for with the paths of the generated .gcov files, |
| 185 | # so that we only keep the relevant gcov files. |
| 186 | # |
| 187 | # Example: |
| 188 | # COVERAGE_SRCS = |
| 189 | # /path/to/project/root/subdir/the_file.c |
| 190 | # |
| 191 | # ALL_GCOV_FILES = |
| 192 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov |
| 193 | # /path/to/project/root/build/#path#to#project#root#subdir#other_file.c.gcov |
| 194 | # |
| 195 | # Result should be: |
| 196 | # GCOV_FILES = |
| 197 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov |
| 198 | # |
| 199 | set(GCOV_FILES "") |
| 200 | #message("Look in coverage sources: ${COVERAGE_SRCS}") |
| 201 | message("\nFilter out unwanted GCOV files:") |
| 202 | message("===============================") |
| 203 | |
| 204 | set(COVERAGE_SRCS_REMAINING ${COVERAGE_SRCS}) |
| 205 | |
| 206 | foreach (GCOV_FILE ${ALL_GCOV_FILES}) |
| 207 | |
| 208 | # |
| 209 | # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov |
| 210 | # -> |
| 211 | # /path/to/project/root/subdir/the_file.c |
| 212 | get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE}) |
| 213 | |
| 214 | # Is this in the list of source files? |
| 215 | # TODO: We want to match against relative path filenames from the source file root... |
| 216 | list(FIND COVERAGE_SRCS ${GCOV_SRC_PATH} WAS_FOUND) |
| 217 | |
| 218 | if (NOT WAS_FOUND EQUAL -1) |
| 219 | message("YES: ${GCOV_FILE}") |
| 220 | list(APPEND GCOV_FILES ${GCOV_FILE}) |
| 221 | |
| 222 | # We remove it from the list, so we don't bother searching for it again. |
| 223 | # Also files left in COVERAGE_SRCS_REMAINING after this loop ends should |
| 224 | # have coverage data generated from them (no lines are covered). |
| 225 | list(REMOVE_ITEM COVERAGE_SRCS_REMAINING ${GCOV_SRC_PATH}) |
| 226 | else() |
| 227 | message("NO: ${GCOV_FILE}") |
| 228 | endif() |
| 229 | endforeach() |
| 230 | |
| 231 | # TODO: Enable setting these |
| 232 | set(JSON_SERVICE_NAME "travis-ci") |
| 233 | set(JSON_SERVICE_JOB_ID $ENV{TRAVIS_JOB_ID}) |
| 234 | |
| 235 | set(JSON_TEMPLATE |
| 236 | "{ |
| 237 | \"service_name\": \"\@JSON_SERVICE_NAME\@\", |
| 238 | \"service_job_id\": \"\@JSON_SERVICE_JOB_ID\@\", |
| 239 | \"source_files\": \@JSON_GCOV_FILES\@ |
| 240 | }" |
| 241 | ) |
| 242 | |
| 243 | set(SRC_FILE_TEMPLATE |
| 244 | "{ |
| 245 | \"name\": \"\@GCOV_SRC_REL_PATH\@\", |
| 246 | \"source_digest\": \"\@GCOV_CONTENTS_MD5\@\", |
| 247 | \"coverage\": \@GCOV_FILE_COVERAGE\@ |
| 248 | }" |
| 249 | ) |
| 250 | |
| 251 | message("\nGenerate JSON for files:") |
| 252 | message("=========================") |
| 253 | |
| 254 | set(JSON_GCOV_FILES "[") |
| 255 | |
| 256 | # Read the GCOV files line by line and get the coverage data. |
| 257 | foreach (GCOV_FILE ${GCOV_FILES}) |
| 258 | |
| 259 | get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE}) |
| 260 | file(RELATIVE_PATH GCOV_SRC_REL_PATH "${PROJECT_ROOT}" "${GCOV_SRC_PATH}") |
| 261 | |
| 262 | # The new coveralls API doesn't need the entire source (Yay!) |
| 263 | # However, still keeping that part for now. Will cleanup in the future. |
| 264 | file(MD5 "${GCOV_SRC_PATH}" GCOV_CONTENTS_MD5) |
| 265 | message("MD5: ${GCOV_SRC_PATH} = ${GCOV_CONTENTS_MD5}") |
| 266 | |
| 267 | # Loads the gcov file as a list of lines. |
| 268 | # (We first open the file and replace all occurences of [] with _ |
| 269 | # because CMake will fail to parse a line containing unmatched brackets... |
| 270 | # also the \ to escaped \n in macros screws up things.) |
| 271 | # https://public.kitware.com/Bug/view.php?id=15369 |
| 272 | file(READ ${GCOV_FILE} GCOV_CONTENTS) |
| 273 | string(REPLACE "[" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") |
| 274 | string(REPLACE "]" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") |
| 275 | string(REPLACE "\\" "_" GCOV_CONTENTS "${GCOV_CONTENTS}") |
| 276 | file(WRITE ${GCOV_FILE}_tmp "${GCOV_CONTENTS}") |
| 277 | |
| 278 | file(STRINGS ${GCOV_FILE}_tmp GCOV_LINES) |
| 279 | list(LENGTH GCOV_LINES LINE_COUNT) |
| 280 | |
| 281 | # Instead of trying to parse the source from the |
| 282 | # gcov file, simply read the file contents from the source file. |
| 283 | # (Parsing it from the gcov is hard because C-code uses ; in many places |
| 284 | # which also happens to be the same as the CMake list delimeter). |
| 285 | file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE) |
| 286 | |
| 287 | string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") |
| 288 | string(REGEX REPLACE "\"" "\\\\\"" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") |
| 289 | string(REPLACE "\t" "\\\\t" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") |
| 290 | string(REPLACE "\r" "\\\\r" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") |
| 291 | string(REPLACE "\n" "\\\\n" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") |
| 292 | # According to http://json.org/ these should be escaped as well. |
| 293 | # Don't know how to do that in CMake however... |
| 294 | #string(REPLACE "\b" "\\\\b" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") |
| 295 | #string(REPLACE "\f" "\\\\f" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") |
| 296 | #string(REGEX REPLACE "\u([a-fA-F0-9]{4})" "\\\\u\\1" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") |
| 297 | |
| 298 | # We want a json array of coverage data as a single string |
| 299 | # start building them from the contents of the .gcov |
| 300 | set(GCOV_FILE_COVERAGE "[") |
| 301 | |
| 302 | set(GCOV_LINE_COUNT 1) # Line number for the .gcov. |
| 303 | set(DO_SKIP 0) |
| 304 | foreach (GCOV_LINE ${GCOV_LINES}) |
| 305 | #message("${GCOV_LINE}") |
| 306 | # Example of what we're parsing: |
| 307 | # Hitcount |Line | Source |
| 308 | # " 8: 26: if (!allowed || (strlen(allowed) == 0))" |
| 309 | string(REGEX REPLACE |
| 310 | "^([^:]*):([^:]*):(.*)$" |
| 311 | "\\1;\\2;\\3" |
| 312 | RES |
| 313 | "${GCOV_LINE}") |
| 314 | |
| 315 | # Check if we should exclude lines using the Lcov syntax. |
| 316 | string(REGEX MATCH "LCOV_EXCL_START" START_SKIP "${GCOV_LINE}") |
| 317 | string(REGEX MATCH "LCOV_EXCL_END" END_SKIP "${GCOV_LINE}") |
| 318 | string(REGEX MATCH "LCOV_EXCL_LINE" LINE_SKIP "${GCOV_LINE}") |
| 319 | |
| 320 | set(RESET_SKIP 0) |
| 321 | if (LINE_SKIP AND NOT DO_SKIP) |
| 322 | set(DO_SKIP 1) |
| 323 | set(RESET_SKIP 1) |
| 324 | endif() |
| 325 | |
| 326 | if (START_SKIP) |
| 327 | set(DO_SKIP 1) |
| 328 | message("${GCOV_LINE_COUNT}: Start skip") |
| 329 | endif() |
| 330 | |
| 331 | if (END_SKIP) |
| 332 | set(DO_SKIP 0) |
| 333 | endif() |
| 334 | |
| 335 | list(LENGTH RES RES_COUNT) |
| 336 | |
| 337 | if (RES_COUNT GREATER 2) |
| 338 | list(GET RES 0 HITCOUNT) |
| 339 | list(GET RES 1 LINE) |
| 340 | list(GET RES 2 SOURCE) |
| 341 | |
| 342 | string(STRIP ${HITCOUNT} HITCOUNT) |
| 343 | string(STRIP ${LINE} LINE) |
| 344 | |
| 345 | # Lines with 0 line numbers are metadata and can be ignored. |
| 346 | if (NOT ${LINE} EQUAL 0) |
| 347 | |
| 348 | if (DO_SKIP) |
| 349 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}null, ") |
| 350 | else() |
| 351 | # Translate the hitcount into valid JSON values. |
| 352 | if (${HITCOUNT} STREQUAL "#####") |
| 353 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ") |
| 354 | elseif (${HITCOUNT} STREQUAL "-") |
| 355 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}null, ") |
| 356 | else() |
| 357 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}${HITCOUNT}, ") |
| 358 | endif() |
| 359 | endif() |
| 360 | endif() |
| 361 | else() |
| 362 | message(WARNING "Failed to properly parse line (RES_COUNT = ${RES_COUNT}) ${GCOV_FILE}:${GCOV_LINE_COUNT}\n-->${GCOV_LINE}") |
| 363 | endif() |
| 364 | |
| 365 | if (RESET_SKIP) |
| 366 | set(DO_SKIP 0) |
| 367 | endif() |
| 368 | math(EXPR GCOV_LINE_COUNT "${GCOV_LINE_COUNT}+1") |
| 369 | endforeach() |
| 370 | |
| 371 | message("${GCOV_LINE_COUNT} of ${LINE_COUNT} lines read!") |
| 372 | |
| 373 | # Advanced way of removing the trailing comma in the JSON array. |
| 374 | # "[1, 2, 3, " -> "[1, 2, 3" |
| 375 | string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE}) |
| 376 | |
| 377 | # Append the trailing ] to complete the JSON array. |
| 378 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]") |
| 379 | |
| 380 | # Generate the final JSON for this file. |
| 381 | message("Generate JSON for file: ${GCOV_SRC_REL_PATH}...") |
| 382 | string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON) |
| 383 | |
| 384 | set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ") |
| 385 | endforeach() |
| 386 | |
| 387 | # Loop through all files we couldn't find any coverage for |
| 388 | # as well, and generate JSON for those as well with 0% coverage. |
| 389 | foreach(NOT_COVERED_SRC ${COVERAGE_SRCS_REMAINING}) |
| 390 | |
| 391 | # Loads the source file as a list of lines. |
| 392 | file(STRINGS ${NOT_COVERED_SRC} SRC_LINES) |
| 393 | |
| 394 | set(GCOV_FILE_COVERAGE "[") |
| 395 | set(GCOV_FILE_SOURCE "") |
| 396 | |
| 397 | foreach (SOURCE ${SRC_LINES}) |
| 398 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ") |
| 399 | |
| 400 | string(REPLACE "\\" "\\\\" SOURCE "${SOURCE}") |
| 401 | string(REGEX REPLACE "\"" "\\\\\"" SOURCE "${SOURCE}") |
| 402 | string(REPLACE "\t" "\\\\t" SOURCE "${SOURCE}") |
| 403 | string(REPLACE "\r" "\\\\r" SOURCE "${SOURCE}") |
| 404 | set(GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}${SOURCE}\\n") |
| 405 | endforeach() |
| 406 | |
| 407 | # Remove trailing comma, and complete JSON array with ] |
| 408 | string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE}) |
| 409 | set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]") |
| 410 | |
| 411 | # Generate the final JSON for this file. |
| 412 | message("Generate JSON for non-gcov file: ${NOT_COVERED_SRC}...") |
| 413 | string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON) |
| 414 | set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ") |
| 415 | endforeach() |
| 416 | |
| 417 | # Get rid of trailing comma. |
| 418 | string(REGEX REPLACE ",[ ]*$" "" JSON_GCOV_FILES ${JSON_GCOV_FILES}) |
| 419 | set(JSON_GCOV_FILES "${JSON_GCOV_FILES}]") |
| 420 | |
| 421 | # Generate the final complete JSON! |
| 422 | message("Generate final JSON...") |
| 423 | string(CONFIGURE ${JSON_TEMPLATE} JSON) |
| 424 | |
| 425 | file(WRITE "${COVERALLS_OUTPUT_FILE}" "${JSON}") |
| 426 | message("###########################################################################") |
| 427 | message("Generated coveralls JSON containing coverage data:") |
| 428 | message("${COVERALLS_OUTPUT_FILE}") |
| 429 | message("###########################################################################") |