diff --git a/.gitignore b/.gitignore index c25ce8a..73d7b19 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .idea_modules/ .build*/ .clangd +.devcontainer/ *.iws *.swp *.swo diff --git a/cmake/CodeCoverage.cmake b/cmake/CodeCoverage.cmake index ccbd3ce..52f95fa 100644 --- a/cmake/CodeCoverage.cmake +++ b/cmake/CodeCoverage.cmake @@ -26,6 +26,75 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # +# CHANGES: +# +# 2012-01-31, Lars Bilke +# - Enable Code Coverage +# +# 2013-09-17, Joakim Söderberg +# - Added support for Clang. +# - Some additional usage instructions. +# +# 2016-02-03, Lars Bilke +# - Refactored functions to use named parameters +# +# 2017-06-02, Lars Bilke +# - Merged with modified version from github.com/ufz/ogs +# +# 2019-05-06, Anatolii Kurotych +# - Remove unnecessary --coverage flag +# +# 2019-12-13, FeRD (Frank Dana) +# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor +# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments. +# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY +# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list +# - Set lcov basedir with -b argument +# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be +# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().) +# - Delete output dir, .info file on 'make clean' +# - Remove Python detection, since version mismatches will break gcovr +# - Minor cleanup (lowercase function names, update examples...) +# +# 2019-12-19, FeRD (Frank Dana) +# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets +# +# 2020-01-19, Bob Apthorpe +# - Added gfortran support +# +# 2020-02-17, FeRD (Frank Dana) +# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters +# in EXCLUDEs, and remove manual escaping from gcovr targets +# +# 2021-01-19, Robin Mueller +# - Add CODE_COVERAGE_VERBOSE option which will allow to print out commands which are run +# - Added the option for users to set the GCOVR_ADDITIONAL_ARGS variable to supply additional +# flags to the gcovr command +# +# 2020-05-04, Mihchael Davis +# - Add -fprofile-abs-path to make gcno files contain absolute paths +# - Fix BASE_DIRECTORY not working when defined +# - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines +# +# 2021-05-10, Martin Stump +# - Check if the generator is multi-config before warning about non-Debug builds +# +# 2022-02-22, Marko Wehle +# - Change gcovr output from -o for --xml and --html output respectively. +# This will allow for Multiple Output Formats at the same time by making use of GCOVR_ADDITIONAL_ARGS, e.g. GCOVR_ADDITIONAL_ARGS "--txt". +# +# 2022-09-28, Sebastian Mueller +# - fix append_coverage_compiler_flags_to_target to correctly add flags +# - replace "-fprofile-arcs -ftest-coverage" with "--coverage" (equivalent) +# +# 2023-12-15, Bronek Kozicki +# - remove setup_target_for_coverage_lcov (slow) and setup_target_for_coverage_fastcov (no support for Clang) +# - fix Clang support by adding find_program( ... llvm-cov ) +# - add Apple Clang support by adding execute_process( COMMAND xcrun -f llvm-cov ... ) +# - add CODE_COVERAGE_GCOV_TOOL to explicitly select gcov tool and disable find_program +# - replace both functions setup_target_for_coverage_gcovr_* with single setup_target_for_coverage_gcovr +# - add support for all gcovr output formats +# # USAGE: # # 1. Copy this file into your cmake modules path. @@ -50,7 +119,7 @@ # '/path/to/my/src/dir2/*') # Or, use the EXCLUDE argument to setup_target_for_coverage_*(). # Example: -# setup_target_for_coverage_lcov( +# setup_target_for_coverage_gcovr( # NAME coverage # EXECUTABLE testrunner # EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*") @@ -66,6 +135,15 @@ # BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src" # EXCLUDE "dir2/*") # +# 4.b If you need to pass specific options to gcovr, specify them in +# GCOVR_ADDITIONAL_ARGS variable. +# Example: +# set (GCOVR_ADDITIONAL_ARGS --exclude-throw-branches --exclude-noncode-lines -s) +# setup_target_for_coverage_gcovr( +# NAME coverage +# EXECUTABLE testrunner +# EXCLUDE "src/dir1" "src/dir2") +# # 5. Use the functions described below to create a custom make target which # runs your test executable and produces a code coverage report. # @@ -73,7 +151,6 @@ # cmake -DCMAKE_BUILD_TYPE=Debug .. # make # make my_coverage_target -# include(CMakeParseArguments) @@ -95,19 +172,14 @@ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") else() find_program( LLVMCOV_PATH llvm-cov ) endif() - if (NOT LLVMCOV_PATH) - message(FATAL_ERROR "Could not find llvm-cov tool! Aborting...") + if(LLVMCOV_PATH) + set(GCOV_TOOL "${LLVMCOV_PATH} gcov") endif() - set(GCOV_TOOL "${LLVMCOV_PATH} gcov") elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") find_program( GCOV_PATH gcov ) - set(GCOV_TOOL ${GCOV_PATH}) + set(GCOV_TOOL "${GCOV_PATH}") endif() -if(NOT GCOV_TOOL) - message(FATAL_ERROR "Could not find gcov or llvm-cov tool! Aborting...") -endif() # NOT GCOV_TOOL - # Check supported compiler (Clang, GNU and Flang) get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) foreach(LANG ${LANGUAGES}) @@ -188,10 +260,7 @@ endif() # # json-details coveralls csv txt # # html-single html-nested html-details # # (xml is an alias to cobertura; -# # if no format is set, defaults to xml; -# # if any of the supported formats is -# # set in GCOVR_ADDITIONAL_ARGS options -# # it will always take priority) +# # if no format is set, defaults to xml) # EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative # # to BASE_DIRECTORY, with CMake 3.4+) # ) @@ -203,6 +272,10 @@ function(setup_target_for_coverage_gcovr) set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + if(NOT GCOV_TOOL) + message(FATAL_ERROR "Could not find gcov or llvm-cov tool! Aborting...") + endif() + if(NOT GCOVR_PATH) message(FATAL_ERROR "Could not find gcovr tool! Aborting...") endif() @@ -214,64 +287,8 @@ function(setup_target_for_coverage_gcovr) set(BASEDIR ${PROJECT_SOURCE_DIR}) endif() - if("--txt" IN_LIST GCOVR_ADDITIONAL_ARGS) - set(Coverage_FORMAT txt) - elseif("--csv" IN_LIST GCOVR_ADDITIONAL_ARGS) - set(Coverage_FORMAT csv) - elseif(("--cobertura" IN_LIST GCOVR_ADDITIONAL_ARGS) - OR ("--cobertura-pretty" IN_LIST GCOVR_ADDITIONAL_ARGS) - OR ("--xml" IN_LIST GCOVR_ADDITIONAL_ARGS) - OR ("--xml-pretty" IN_LIST GCOVR_ADDITIONAL_ARGS) - OR ("-x" IN_LIST GCOVR_ADDITIONAL_ARGS)) - set(Coverage_FORMAT cobertura) - elseif("--sonarqube" IN_LIST GCOVR_ADDITIONAL_ARGS) - set(Coverage_FORMAT sonarqube) - elseif(("--json-summary" IN_LIST GCOVR_ADDITIONAL_ARGS) - OR ("--json-summary-pretty" IN_LIST GCOVR_ADDITIONAL_ARGS)) - set(Coverage_FORMAT json-summary) - elseif(("--json" IN_LIST GCOVR_ADDITIONAL_ARGS) - OR ("--json-pretty" IN_LIST GCOVR_ADDITIONAL_ARGS)) - set(Coverage_FORMAT json-details) - elseif(("--coveralls" IN_LIST GCOVR_ADDITIONAL_ARGS) - OR ("--coveralls-pretty" IN_LIST GCOVR_ADDITIONAL_ARGS)) - set(Coverage_FORMAT coveralls) - elseif(("--html" IN_LIST GCOVR_ADDITIONAL_ARGS) - OR ("--html-self-contained" IN_LIST GCOVR_ADDITIONAL_ARGS)) - set(Coverage_FORMAT html-single) - elseif("--html-details" IN_LIST GCOVR_ADDITIONAL_ARGS) - set(Coverage_FORMAT html-details) - elseif("--html-nested" IN_LIST GCOVR_ADDITIONAL_ARGS) - set(Coverage_FORMAT html-nested) - else() - if(NOT DEFINED Coverage_FORMAT) - set(Coverage_FORMAT xml) - endif() - - if ((Coverage_FORMAT STREQUAL "cobertura") - OR (Coverage_FORMAT STREQUAL "xml")) - list(APPEND GCOVR_ADDITIONAL_ARGS --cobertura-pretty) - set(Coverage_FORMAT cobertura) # overwrite xml - elseif(Coverage_FORMAT STREQUAL "sonarqube") - list(APPEND GCOVR_ADDITIONAL_ARGS --sonarqube) - elseif(Coverage_FORMAT STREQUAL "json-summary") - list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary-pretty) - elseif(Coverage_FORMAT STREQUAL "json-details") - list(APPEND GCOVR_ADDITIONAL_ARGS --json-pretty) - elseif(Coverage_FORMAT STREQUAL "coveralls") - list(APPEND GCOVR_ADDITIONAL_ARGS --coveralls-pretty) - elseif(Coverage_FORMAT STREQUAL "csv") - list(APPEND GCOVR_ADDITIONAL_ARGS --csv) - elseif(Coverage_FORMAT STREQUAL "txt") - list(APPEND GCOVR_ADDITIONAL_ARGS --txt) - elseif(Coverage_FORMAT STREQUAL "html-single") - list(APPEND GCOVR_ADDITIONAL_ARGS --html --html-self-contained) - elseif(Coverage_FORMAT STREQUAL "html-nested") - list(APPEND GCOVR_ADDITIONAL_ARGS --html --html-nested) - elseif(Coverage_FORMAT STREQUAL "html-details") - list(APPEND GCOVR_ADDITIONAL_ARGS --html --html-details) - else() - message(FATAL_ERROR "Unsupported output style ${Coverage_FORMAT}! Aborting...") - endif() + if(NOT DEFINED Coverage_FORMAT) + set(Coverage_FORMAT xml) endif() if("--output" IN_LIST GCOVR_ADDITIONAL_ARGS) @@ -294,7 +311,37 @@ function(setup_target_for_coverage_gcovr) else() set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.xml) endif() - list(APPEND GCOVR_ADDITIONAL_ARGS --output ${GCOVR_OUTPUT_FILE}) + endif() + + if ((Coverage_FORMAT STREQUAL "cobertura") + OR (Coverage_FORMAT STREQUAL "xml")) + list(APPEND GCOVR_ADDITIONAL_ARGS --cobertura "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --cobertura-pretty ) + set(Coverage_FORMAT cobertura) # overwrite xml + elseif(Coverage_FORMAT STREQUAL "sonarqube") + list(APPEND GCOVR_ADDITIONAL_ARGS --sonarqube "${GCOVR_OUTPUT_FILE}" ) + elseif(Coverage_FORMAT STREQUAL "json-summary") + list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary-pretty) + elseif(Coverage_FORMAT STREQUAL "json-details") + list(APPEND GCOVR_ADDITIONAL_ARGS --json "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --json-pretty) + elseif(Coverage_FORMAT STREQUAL "coveralls") + list(APPEND GCOVR_ADDITIONAL_ARGS --coveralls "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --coveralls-pretty) + elseif(Coverage_FORMAT STREQUAL "csv") + list(APPEND GCOVR_ADDITIONAL_ARGS --csv "${GCOVR_OUTPUT_FILE}" ) + elseif(Coverage_FORMAT STREQUAL "txt") + list(APPEND GCOVR_ADDITIONAL_ARGS --txt "${GCOVR_OUTPUT_FILE}" ) + elseif(Coverage_FORMAT STREQUAL "html-single") + list(APPEND GCOVR_ADDITIONAL_ARGS --html "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --html-self-contained) + elseif(Coverage_FORMAT STREQUAL "html-nested") + list(APPEND GCOVR_ADDITIONAL_ARGS --html-nested "${GCOVR_OUTPUT_FILE}" ) + elseif(Coverage_FORMAT STREQUAL "html-details") + list(APPEND GCOVR_ADDITIONAL_ARGS --html-details "${GCOVR_OUTPUT_FILE}" ) + else() + message(FATAL_ERROR "Unsupported output style ${Coverage_FORMAT}! Aborting...") endif() # Collect excludes (CMake 3.4+: Also compute absolute paths)