mirror of
https://github.com/catchorg/Catch2.git
synced 2024-12-27 05:03:30 +01:00
e344984a1b
* Every Linux build tracks coverage when running Debug mode * OS X not supported yet (Future WIP) * Our own unit tests, non-default reporters and Clara are ignored
355 lines
12 KiB
CMake
355 lines
12 KiB
CMake
# This file is part of CMake-codecov.
|
|
#
|
|
# Copyright (c)
|
|
# 2015-2017 RWTH Aachen University, Federal Republic of Germany
|
|
#
|
|
# See the LICENSE file in the package base directory for details
|
|
#
|
|
# Written by Alexander Haase, alexander.haase@rwth-aachen.de
|
|
#
|
|
|
|
|
|
# configuration
|
|
set(LCOV_DATA_PATH "${CMAKE_BINARY_DIR}/lcov/data")
|
|
set(LCOV_DATA_PATH_INIT "${LCOV_DATA_PATH}/init")
|
|
set(LCOV_DATA_PATH_CAPTURE "${LCOV_DATA_PATH}/capture")
|
|
set(LCOV_HTML_PATH "${CMAKE_BINARY_DIR}/lcov/html")
|
|
|
|
|
|
|
|
|
|
# Search for Gcov which is used by Lcov.
|
|
find_package(Gcov)
|
|
|
|
|
|
|
|
|
|
# This function will add lcov evaluation for target <TNAME>. Only sources of
|
|
# this target will be evaluated and no dependencies will be added. It will call
|
|
# geninfo on any source file of <TNAME> once and store the info file in the same
|
|
# directory.
|
|
#
|
|
# Note: This function is only a wrapper to define this function always, even if
|
|
# coverage is not supported by the compiler or disabled. This function must
|
|
# be defined here, because the module will be exited, if there is no coverage
|
|
# support by the compiler or it is disabled by the user.
|
|
function (add_lcov_target TNAME)
|
|
if (LCOV_FOUND)
|
|
# capture initial coverage data
|
|
lcov_capture_initial_tgt(${TNAME})
|
|
|
|
# capture coverage data after execution
|
|
lcov_capture_tgt(${TNAME})
|
|
endif ()
|
|
endfunction (add_lcov_target)
|
|
|
|
|
|
|
|
|
|
# include required Modules
|
|
include(FindPackageHandleStandardArgs)
|
|
|
|
# Search for required lcov binaries.
|
|
find_program(LCOV_BIN lcov)
|
|
find_program(GENINFO_BIN geninfo)
|
|
find_program(GENHTML_BIN genhtml)
|
|
find_package_handle_standard_args(lcov
|
|
REQUIRED_VARS LCOV_BIN GENINFO_BIN GENHTML_BIN
|
|
)
|
|
|
|
# enable genhtml C++ demangeling, if c++filt is found.
|
|
set(GENHTML_CPPFILT_FLAG "")
|
|
find_program(CPPFILT_BIN c++filt)
|
|
if (NOT CPPFILT_BIN STREQUAL "")
|
|
set(GENHTML_CPPFILT_FLAG "--demangle-cpp")
|
|
endif (NOT CPPFILT_BIN STREQUAL "")
|
|
|
|
# enable no-external flag for lcov, if available.
|
|
if (GENINFO_BIN AND NOT DEFINED GENINFO_EXTERN_FLAG)
|
|
set(FLAG "")
|
|
execute_process(COMMAND ${GENINFO_BIN} --help OUTPUT_VARIABLE GENINFO_HELP)
|
|
string(REGEX MATCH "external" GENINFO_RES "${GENINFO_HELP}")
|
|
if (GENINFO_RES)
|
|
set(FLAG "--no-external")
|
|
endif ()
|
|
|
|
set(GENINFO_EXTERN_FLAG "${FLAG}"
|
|
CACHE STRING "Geninfo flag to exclude system sources.")
|
|
endif ()
|
|
|
|
# If Lcov was not found, exit module now.
|
|
if (NOT LCOV_FOUND)
|
|
return()
|
|
endif (NOT LCOV_FOUND)
|
|
|
|
|
|
|
|
|
|
# Create directories to be used.
|
|
file(MAKE_DIRECTORY ${LCOV_DATA_PATH_INIT})
|
|
file(MAKE_DIRECTORY ${LCOV_DATA_PATH_CAPTURE})
|
|
|
|
set(LCOV_REMOVE_PATTERNS "")
|
|
|
|
# This function will merge lcov files to a single target file. Additional lcov
|
|
# flags may be set with setting LCOV_EXTRA_FLAGS before calling this function.
|
|
function (lcov_merge_files OUTFILE ...)
|
|
# Remove ${OUTFILE} from ${ARGV} and generate lcov parameters with files.
|
|
list(REMOVE_AT ARGV 0)
|
|
|
|
# Generate merged file.
|
|
string(REPLACE "${CMAKE_BINARY_DIR}/" "" FILE_REL "${OUTFILE}")
|
|
add_custom_command(OUTPUT "${OUTFILE}.raw"
|
|
COMMAND cat ${ARGV} > ${OUTFILE}.raw
|
|
DEPENDS ${ARGV}
|
|
COMMENT "Generating ${FILE_REL}"
|
|
)
|
|
|
|
add_custom_command(OUTPUT "${OUTFILE}"
|
|
COMMAND ${LCOV_BIN} --quiet -a ${OUTFILE}.raw --output-file ${OUTFILE}
|
|
--base-directory ${PROJECT_SOURCE_DIR} ${LCOV_EXTRA_FLAGS}
|
|
COMMAND ${LCOV_BIN} --quiet -r ${OUTFILE} ${LCOV_REMOVE_PATTERNS}
|
|
--output-file ${OUTFILE} ${LCOV_EXTRA_FLAGS}
|
|
DEPENDS ${OUTFILE}.raw
|
|
COMMENT "Post-processing ${FILE_REL}"
|
|
)
|
|
endfunction ()
|
|
|
|
|
|
|
|
|
|
# Add a new global target to generate initial coverage reports for all targets.
|
|
# This target will be used to generate the global initial info file, which is
|
|
# used to gather even empty report data.
|
|
if (NOT TARGET lcov-capture-init)
|
|
add_custom_target(lcov-capture-init)
|
|
set(LCOV_CAPTURE_INIT_FILES "" CACHE INTERNAL "")
|
|
endif (NOT TARGET lcov-capture-init)
|
|
|
|
|
|
# This function will add initial capture of coverage data for target <TNAME>,
|
|
# which is needed to get also data for objects, which were not loaded at
|
|
# execution time. It will call geninfo for every source file of <TNAME> once and
|
|
# store the info file in the same directory.
|
|
function (lcov_capture_initial_tgt TNAME)
|
|
# We don't have to check, if the target has support for coverage, thus this
|
|
# will be checked by add_coverage_target in Findcoverage.cmake. Instead we
|
|
# have to determine which gcov binary to use.
|
|
get_target_property(TSOURCES ${TNAME} SOURCES)
|
|
set(SOURCES "")
|
|
set(TCOMPILER "")
|
|
foreach (FILE ${TSOURCES})
|
|
codecov_path_of_source(${FILE} FILE)
|
|
if (NOT "${FILE}" STREQUAL "")
|
|
codecov_lang_of_source(${FILE} LANG)
|
|
if (NOT "${LANG}" STREQUAL "")
|
|
list(APPEND SOURCES "${FILE}")
|
|
set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
|
endif ()
|
|
endif ()
|
|
endforeach ()
|
|
|
|
# If no gcov binary was found, coverage data can't be evaluated.
|
|
if (NOT GCOV_${TCOMPILER}_BIN)
|
|
message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.")
|
|
return()
|
|
endif ()
|
|
|
|
set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}")
|
|
set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}")
|
|
|
|
|
|
set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir)
|
|
set(GENINFO_FILES "")
|
|
foreach(FILE ${SOURCES})
|
|
# generate empty coverage files
|
|
set(OUTFILE "${TDIR}/${FILE}.info.init")
|
|
list(APPEND GENINFO_FILES ${OUTFILE})
|
|
|
|
add_custom_command(OUTPUT ${OUTFILE} COMMAND ${GCOV_ENV} ${GENINFO_BIN}
|
|
--quiet --base-directory ${PROJECT_SOURCE_DIR} --initial
|
|
--gcov-tool ${GCOV_BIN} --output-filename ${OUTFILE}
|
|
${GENINFO_EXTERN_FLAG} ${TDIR}/${FILE}.gcno
|
|
DEPENDS ${TNAME}
|
|
COMMENT "Capturing initial coverage data for ${FILE}"
|
|
)
|
|
endforeach()
|
|
|
|
# Concatenate all files generated by geninfo to a single file per target.
|
|
set(OUTFILE "${LCOV_DATA_PATH_INIT}/${TNAME}.info")
|
|
set(LCOV_EXTRA_FLAGS "--initial")
|
|
lcov_merge_files("${OUTFILE}" ${GENINFO_FILES})
|
|
add_custom_target(${TNAME}-capture-init ALL DEPENDS ${OUTFILE})
|
|
|
|
# add geninfo file generation to global lcov-geninfo target
|
|
add_dependencies(lcov-capture-init ${TNAME}-capture-init)
|
|
set(LCOV_CAPTURE_INIT_FILES "${LCOV_CAPTURE_INIT_FILES}"
|
|
"${OUTFILE}" CACHE INTERNAL ""
|
|
)
|
|
endfunction (lcov_capture_initial_tgt)
|
|
|
|
|
|
# This function will generate the global info file for all targets. It has to be
|
|
# called after all other CMake functions in the root CMakeLists.txt file, to get
|
|
# a full list of all targets that generate coverage data.
|
|
function (lcov_capture_initial)
|
|
# Skip this function (and do not create the following targets), if there are
|
|
# no input files.
|
|
if ("${LCOV_CAPTURE_INIT_FILES}" STREQUAL "")
|
|
return()
|
|
endif ()
|
|
|
|
# Add a new target to merge the files of all targets.
|
|
set(OUTFILE "${LCOV_DATA_PATH_INIT}/all_targets.info")
|
|
lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_INIT_FILES})
|
|
add_custom_target(lcov-geninfo-init ALL DEPENDS ${OUTFILE}
|
|
lcov-capture-init
|
|
)
|
|
endfunction (lcov_capture_initial)
|
|
|
|
|
|
|
|
|
|
# Add a new global target to generate coverage reports for all targets. This
|
|
# target will be used to generate the global info file.
|
|
if (NOT TARGET lcov-capture)
|
|
add_custom_target(lcov-capture)
|
|
set(LCOV_CAPTURE_FILES "" CACHE INTERNAL "")
|
|
endif (NOT TARGET lcov-capture)
|
|
|
|
|
|
# This function will add capture of coverage data for target <TNAME>, which is
|
|
# needed to get also data for objects, which were not loaded at execution time.
|
|
# It will call geninfo for every source file of <TNAME> once and store the info
|
|
# file in the same directory.
|
|
function (lcov_capture_tgt TNAME)
|
|
# We don't have to check, if the target has support for coverage, thus this
|
|
# will be checked by add_coverage_target in Findcoverage.cmake. Instead we
|
|
# have to determine which gcov binary to use.
|
|
get_target_property(TSOURCES ${TNAME} SOURCES)
|
|
set(SOURCES "")
|
|
set(TCOMPILER "")
|
|
foreach (FILE ${TSOURCES})
|
|
codecov_path_of_source(${FILE} FILE)
|
|
if (NOT "${FILE}" STREQUAL "")
|
|
codecov_lang_of_source(${FILE} LANG)
|
|
if (NOT "${LANG}" STREQUAL "")
|
|
list(APPEND SOURCES "${FILE}")
|
|
set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
|
endif ()
|
|
endif ()
|
|
endforeach ()
|
|
|
|
# If no gcov binary was found, coverage data can't be evaluated.
|
|
if (NOT GCOV_${TCOMPILER}_BIN)
|
|
message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.")
|
|
return()
|
|
endif ()
|
|
|
|
set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}")
|
|
set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}")
|
|
|
|
|
|
set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir)
|
|
set(GENINFO_FILES "")
|
|
foreach(FILE ${SOURCES})
|
|
# Generate coverage files. If no .gcda file was generated during
|
|
# execution, the empty coverage file will be used instead.
|
|
set(OUTFILE "${TDIR}/${FILE}.info")
|
|
list(APPEND GENINFO_FILES ${OUTFILE})
|
|
|
|
add_custom_command(OUTPUT ${OUTFILE}
|
|
COMMAND test -f "${TDIR}/${FILE}.gcda"
|
|
&& ${GCOV_ENV} ${GENINFO_BIN} --quiet --base-directory
|
|
${PROJECT_SOURCE_DIR} --gcov-tool ${GCOV_BIN}
|
|
--output-filename ${OUTFILE} ${GENINFO_EXTERN_FLAG}
|
|
${TDIR}/${FILE}.gcda
|
|
|| cp ${OUTFILE}.init ${OUTFILE}
|
|
DEPENDS ${TNAME} ${TNAME}-capture-init
|
|
COMMENT "Capturing coverage data for ${FILE}"
|
|
)
|
|
endforeach()
|
|
|
|
# Concatenate all files generated by geninfo to a single file per target.
|
|
set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/${TNAME}.info")
|
|
lcov_merge_files("${OUTFILE}" ${GENINFO_FILES})
|
|
add_custom_target(${TNAME}-geninfo DEPENDS ${OUTFILE})
|
|
|
|
# add geninfo file generation to global lcov-capture target
|
|
add_dependencies(lcov-capture ${TNAME}-geninfo)
|
|
set(LCOV_CAPTURE_FILES "${LCOV_CAPTURE_FILES}" "${OUTFILE}" CACHE INTERNAL
|
|
""
|
|
)
|
|
|
|
# Add target for generating html output for this target only.
|
|
file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/${TNAME})
|
|
add_custom_target(${TNAME}-genhtml
|
|
COMMAND ${GENHTML_BIN} --quiet --sort --prefix ${PROJECT_SOURCE_DIR}
|
|
--baseline-file ${LCOV_DATA_PATH_INIT}/${TNAME}.info
|
|
--output-directory ${LCOV_HTML_PATH}/${TNAME}
|
|
--title "${CMAKE_PROJECT_NAME} - target ${TNAME}"
|
|
${GENHTML_CPPFILT_FLAG} ${OUTFILE}
|
|
DEPENDS ${TNAME}-geninfo ${TNAME}-capture-init
|
|
)
|
|
endfunction (lcov_capture_tgt)
|
|
|
|
|
|
# This function will generate the global info file for all targets. It has to be
|
|
# called after all other CMake functions in the root CMakeLists.txt file, to get
|
|
# a full list of all targets that generate coverage data.
|
|
function (lcov_capture)
|
|
# Skip this function (and do not create the following targets), if there are
|
|
# no input files.
|
|
if ("${LCOV_CAPTURE_FILES}" STREQUAL "")
|
|
return()
|
|
endif ()
|
|
|
|
# Add a new target to merge the files of all targets.
|
|
set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/all_targets.info")
|
|
lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_FILES})
|
|
add_custom_target(lcov-geninfo DEPENDS ${OUTFILE} lcov-capture)
|
|
|
|
# Add a new global target for all lcov targets. This target could be used to
|
|
# generate the lcov html output for the whole project instead of calling
|
|
# <TARGET>-geninfo and <TARGET>-genhtml for each target. It will also be
|
|
# used to generate a html site for all project data together instead of one
|
|
# for each target.
|
|
if (NOT TARGET lcov)
|
|
file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/all_targets)
|
|
add_custom_target(lcov
|
|
COMMAND ${GENHTML_BIN} --quiet --sort
|
|
--baseline-file ${LCOV_DATA_PATH_INIT}/all_targets.info
|
|
--output-directory ${LCOV_HTML_PATH}/all_targets
|
|
--title "${CMAKE_PROJECT_NAME}" --prefix "${PROJECT_SOURCE_DIR}"
|
|
${GENHTML_CPPFILT_FLAG} ${OUTFILE}
|
|
DEPENDS lcov-geninfo-init lcov-geninfo
|
|
)
|
|
endif ()
|
|
endfunction (lcov_capture)
|
|
|
|
|
|
|
|
|
|
# Add a new global target to generate the lcov html report for the whole project
|
|
# instead of calling <TARGET>-genhtml for each target (to create an own report
|
|
# for each target). Instead of the lcov target it does not require geninfo for
|
|
# all targets, so you have to call <TARGET>-geninfo to generate the info files
|
|
# the targets you'd like to have in your report or lcov-geninfo for generating
|
|
# info files for all targets before calling lcov-genhtml.
|
|
file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/selected_targets)
|
|
if (NOT TARGET lcov-genhtml)
|
|
add_custom_target(lcov-genhtml
|
|
COMMAND ${GENHTML_BIN}
|
|
--quiet
|
|
--output-directory ${LCOV_HTML_PATH}/selected_targets
|
|
--title \"${CMAKE_PROJECT_NAME} - targets `find
|
|
${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name
|
|
\"all_targets.info\" -exec basename {} .info \\\;`\"
|
|
--prefix ${PROJECT_SOURCE_DIR}
|
|
--sort
|
|
${GENHTML_CPPFILT_FLAG}
|
|
`find ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name
|
|
\"all_targets.info\"`
|
|
)
|
|
endif (NOT TARGET lcov-genhtml)
|