From 14233484314022ccd0c1504d928bad631c2b7d84 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Fri, 8 Dec 2023 16:37:35 +0000 Subject: [PATCH 01/23] Rewrite coverage_report target From https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake --- Builds/CMake/CodeCoverage.cmake | 747 ++++++++++++++++++++++++++++ Builds/CMake/RippledCov.cmake | 124 ++--- Builds/CMake/RippledInterface.cmake | 6 +- CMakeLists.txt | 6 +- 4 files changed, 786 insertions(+), 97 deletions(-) create mode 100644 Builds/CMake/CodeCoverage.cmake diff --git a/Builds/CMake/CodeCoverage.cmake b/Builds/CMake/CodeCoverage.cmake new file mode 100644 index 00000000000..b9e114bc373 --- /dev/null +++ b/Builds/CMake/CodeCoverage.cmake @@ -0,0 +1,747 @@ +# Copyright (c) 2012 - 2017, Lars Bilke +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (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) +# +# USAGE: +# +# 1. Copy this file into your cmake modules path. +# +# 2. Add the following line to your CMakeLists.txt (best inside an if-condition +# using a CMake option() to enable it just optionally): +# include(CodeCoverage) +# +# 3. Append necessary compiler flags for all supported source files: +# append_coverage_compiler_flags() +# Or for specific target: +# append_coverage_compiler_flags_to_target(YOUR_TARGET_NAME) +# +# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og +# +# 4. If you need to exclude additional directories from the report, specify them +# using full paths in the COVERAGE_EXCLUDES variable before calling +# setup_target_for_coverage_*(). +# Example: +# set(COVERAGE_EXCLUDES +# '${PROJECT_SOURCE_DIR}/src/dir1/*' +# '/path/to/my/src/dir2/*') +# Or, use the EXCLUDE argument to setup_target_for_coverage_*(). +# Example: +# setup_target_for_coverage_lcov( +# NAME coverage +# EXECUTABLE testrunner +# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*") +# +# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set +# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR) +# Example: +# set(COVERAGE_EXCLUDES "dir1/*") +# setup_target_for_coverage_gcovr_html( +# NAME coverage +# EXECUTABLE testrunner +# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src" +# EXCLUDE "dir2/*") +# +# 5. Use the functions described below to create a custom make target which +# runs your test executable and produces a code coverage report. +# +# 6. Build a Debug build: +# cmake -DCMAKE_BUILD_TYPE=Debug .. +# make +# make my_coverage_target +# + +include(CMakeParseArguments) + +option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE) + +# Check prereqs +find_program( GCOV_PATH gcov ) +find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl) +find_program( FASTCOV_PATH NAMES fastcov fastcov.py ) +find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat ) +find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) +find_program( CPPFILT_PATH NAMES c++filt ) + +if(NOT GCOV_PATH) + message(FATAL_ERROR "gcov not found! Aborting...") +endif() # NOT GCOV_PATH + +# Check supported compiler (Clang, GNU and Flang) +get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach(LANG ${LANGUAGES}) + if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") + if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3) + message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...") + endif() + elseif(NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "GNU" + AND NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(LLVM)?[Ff]lang") + message(FATAL_ERROR "Compiler is not GNU or Flang! Aborting...") + endif() +endforeach() + +set(COVERAGE_COMPILER_FLAGS "-g --coverage" + CACHE INTERNAL "") +if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag(-fprofile-abs-path HAVE_cxx_fprofile_abs_path) + if(HAVE_cxx_fprofile_abs_path) + set(COVERAGE_CXX_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path") + endif() + include(CheckCCompilerFlag) + check_c_compiler_flag(-fprofile-abs-path HAVE_c_fprofile_abs_path) + if(HAVE_c_fprofile_abs_path) + set(COVERAGE_C_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path") + endif() +endif() + +set(CMAKE_Fortran_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the Fortran compiler during coverage builds." + FORCE ) +set(CMAKE_CXX_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the C++ compiler during coverage builds." + FORCE ) +set(CMAKE_C_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the C compiler during coverage builds." + FORCE ) +set(CMAKE_EXE_LINKER_FLAGS_COVERAGE + "" + CACHE STRING "Flags used for linking binaries during coverage builds." + FORCE ) +set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE + "" + CACHE STRING "Flags used by the shared libraries linker during coverage builds." + FORCE ) +mark_as_advanced( + CMAKE_Fortran_FLAGS_COVERAGE + CMAKE_CXX_FLAGS_COVERAGE + CMAKE_C_FLAGS_COVERAGE + CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) + +get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG)) + message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading") +endif() # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG) + +if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") + link_libraries(gcov) +endif() + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# setup_target_for_coverage_lcov( +# NAME testrunner_coverage # New target name +# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES testrunner # Dependencies to build first +# BASE_DIRECTORY "../" # Base directory for report +# # (defaults to PROJECT_SOURCE_DIR) +# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative +# # to BASE_DIRECTORY, with CMake 3.4+) +# NO_DEMANGLE # Don't demangle C++ symbols +# # even if c++filt is found +# ) +function(setup_target_for_coverage_lcov) + + set(options NO_DEMANGLE SONARQUBE) + set(oneValueArgs BASE_DIRECTORY NAME) + set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT LCOV_PATH) + message(FATAL_ERROR "lcov not found! Aborting...") + endif() # NOT LCOV_PATH + + if(NOT GENHTML_PATH) + message(FATAL_ERROR "genhtml not found! Aborting...") + endif() # NOT GENHTML_PATH + + # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR + if(DEFINED Coverage_BASE_DIRECTORY) + get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + else() + set(BASEDIR ${PROJECT_SOURCE_DIR}) + endif() + + # Collect excludes (CMake 3.4+: Also compute absolute paths) + set(LCOV_EXCLUDES "") + foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES}) + if(CMAKE_VERSION VERSION_GREATER 3.4) + get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) + endif() + list(APPEND LCOV_EXCLUDES "${EXCLUDE}") + endforeach() + list(REMOVE_DUPLICATES LCOV_EXCLUDES) + + # Conditional arguments + if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE}) + set(GENHTML_EXTRA_ARGS "--demangle-cpp") + endif() + + # Setting up commands which will be run to generate coverage data. + # Cleanup lcov + set(LCOV_CLEAN_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . + -b ${BASEDIR} --zerocounters + ) + # Create baseline to make sure untouched files show up in the report + set(LCOV_BASELINE_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b + ${BASEDIR} -o ${Coverage_NAME}.base + ) + # Run tests + set(LCOV_EXEC_TESTS_CMD + ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} + ) + # Capturing lcov counters and generating report + set(LCOV_CAPTURE_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b + ${BASEDIR} --capture --output-file ${Coverage_NAME}.capture + ) + # add baseline counters + set(LCOV_BASELINE_COUNT_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base + -a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total + ) + # filter collected data to final coverage report + set(LCOV_FILTER_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove + ${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info + ) + # Generate HTML output + set(LCOV_GEN_HTML_CMD + ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o + ${Coverage_NAME} ${Coverage_NAME}.info + ) + if(${Coverage_SONARQUBE}) + # Generate SonarQube output + set(GCOVR_XML_CMD + ${GCOVR_PATH} --sonarqube ${Coverage_NAME}_sonarqube.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} + ${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR} + ) + set(GCOVR_XML_CMD_COMMAND + COMMAND ${GCOVR_XML_CMD} + ) + set(GCOVR_XML_CMD_BYPRODUCTS ${Coverage_NAME}_sonarqube.xml) + set(GCOVR_XML_CMD_COMMENT COMMENT "SonarQube code coverage info report saved in ${Coverage_NAME}_sonarqube.xml.") + endif() + + + if(CODE_COVERAGE_VERBOSE) + message(STATUS "Executed command report") + message(STATUS "Command to clean up lcov: ") + string(REPLACE ";" " " LCOV_CLEAN_CMD_SPACED "${LCOV_CLEAN_CMD}") + message(STATUS "${LCOV_CLEAN_CMD_SPACED}") + + message(STATUS "Command to create baseline: ") + string(REPLACE ";" " " LCOV_BASELINE_CMD_SPACED "${LCOV_BASELINE_CMD}") + message(STATUS "${LCOV_BASELINE_CMD_SPACED}") + + message(STATUS "Command to run the tests: ") + string(REPLACE ";" " " LCOV_EXEC_TESTS_CMD_SPACED "${LCOV_EXEC_TESTS_CMD}") + message(STATUS "${LCOV_EXEC_TESTS_CMD_SPACED}") + + message(STATUS "Command to capture counters and generate report: ") + string(REPLACE ";" " " LCOV_CAPTURE_CMD_SPACED "${LCOV_CAPTURE_CMD}") + message(STATUS "${LCOV_CAPTURE_CMD_SPACED}") + + message(STATUS "Command to add baseline counters: ") + string(REPLACE ";" " " LCOV_BASELINE_COUNT_CMD_SPACED "${LCOV_BASELINE_COUNT_CMD}") + message(STATUS "${LCOV_BASELINE_COUNT_CMD_SPACED}") + + message(STATUS "Command to filter collected data: ") + string(REPLACE ";" " " LCOV_FILTER_CMD_SPACED "${LCOV_FILTER_CMD}") + message(STATUS "${LCOV_FILTER_CMD_SPACED}") + + message(STATUS "Command to generate lcov HTML output: ") + string(REPLACE ";" " " LCOV_GEN_HTML_CMD_SPACED "${LCOV_GEN_HTML_CMD}") + message(STATUS "${LCOV_GEN_HTML_CMD_SPACED}") + + if(${Coverage_SONARQUBE}) + message(STATUS "Command to generate SonarQube XML output: ") + string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}") + message(STATUS "${GCOVR_XML_CMD_SPACED}") + endif() + endif() + + # Setup target + add_custom_target(${Coverage_NAME} + COMMAND ${LCOV_CLEAN_CMD} + COMMAND ${LCOV_BASELINE_CMD} + COMMAND ${LCOV_EXEC_TESTS_CMD} + COMMAND ${LCOV_CAPTURE_CMD} + COMMAND ${LCOV_BASELINE_COUNT_CMD} + COMMAND ${LCOV_FILTER_CMD} + COMMAND ${LCOV_GEN_HTML_CMD} + ${GCOVR_XML_CMD_COMMAND} + + # Set output files as GENERATED (will be removed on 'make clean') + BYPRODUCTS + ${Coverage_NAME}.base + ${Coverage_NAME}.capture + ${Coverage_NAME}.total + ${Coverage_NAME}.info + ${GCOVR_XML_CMD_BYPRODUCTS} + ${Coverage_NAME}/index.html + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." + ) + + # Show where to find the lcov info report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info." + ${GCOVR_XML_CMD_COMMENT} + ) + + # Show info where to find the report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." + ) + +endfunction() # setup_target_for_coverage_lcov + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# setup_target_for_coverage_gcovr_xml( +# NAME ctest_coverage # New target name +# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES executable_target # Dependencies to build first +# BASE_DIRECTORY "../" # Base directory for report +# # (defaults to PROJECT_SOURCE_DIR) +# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative +# # to BASE_DIRECTORY, with CMake 3.4+) +# ) +# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the +# GCVOR command. +function(setup_target_for_coverage_gcovr_xml) + + set(options NONE) + set(oneValueArgs BASE_DIRECTORY NAME) + set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT GCOVR_PATH) + message(FATAL_ERROR "gcovr not found! Aborting...") + endif() # NOT GCOVR_PATH + + # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR + if(DEFINED Coverage_BASE_DIRECTORY) + get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + else() + set(BASEDIR ${PROJECT_SOURCE_DIR}) + endif() + + # Collect excludes (CMake 3.4+: Also compute absolute paths) + set(GCOVR_EXCLUDES "") + foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) + if(CMAKE_VERSION VERSION_GREATER 3.4) + get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) + endif() + list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") + endforeach() + list(REMOVE_DUPLICATES GCOVR_EXCLUDES) + + # Combine excludes to several -e arguments + set(GCOVR_EXCLUDE_ARGS "") + foreach(EXCLUDE ${GCOVR_EXCLUDES}) + list(APPEND GCOVR_EXCLUDE_ARGS "-e") + list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") + endforeach() + + # Set up commands which will be run to generate coverage data + # Run tests + set(GCOVR_XML_EXEC_TESTS_CMD + ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} + ) + # Running gcovr + set(GCOVR_XML_CMD + ${GCOVR_PATH} --xml ${Coverage_NAME}.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} + ${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR} + ) + + if(CODE_COVERAGE_VERBOSE) + message(STATUS "Executed command report") + + message(STATUS "Command to run tests: ") + string(REPLACE ";" " " GCOVR_XML_EXEC_TESTS_CMD_SPACED "${GCOVR_XML_EXEC_TESTS_CMD}") + message(STATUS "${GCOVR_XML_EXEC_TESTS_CMD_SPACED}") + + message(STATUS "Command to generate gcovr XML coverage data: ") + string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}") + message(STATUS "${GCOVR_XML_CMD_SPACED}") + endif() + + add_custom_target(${Coverage_NAME} + COMMAND ${GCOVR_XML_EXEC_TESTS_CMD} + COMMAND ${GCOVR_XML_CMD} + + BYPRODUCTS ${Coverage_NAME}.xml + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Running gcovr to produce Cobertura code coverage report." + ) + + # Show info where to find the report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml." + ) +endfunction() # setup_target_for_coverage_gcovr_xml + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# setup_target_for_coverage_gcovr_html( +# NAME ctest_coverage # New target name +# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES executable_target # Dependencies to build first +# BASE_DIRECTORY "../" # Base directory for report +# # (defaults to PROJECT_SOURCE_DIR) +# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative +# # to BASE_DIRECTORY, with CMake 3.4+) +# ) +# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the +# GCVOR command. +function(setup_target_for_coverage_gcovr_html) + + set(options NONE) + set(oneValueArgs BASE_DIRECTORY NAME) + set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT GCOVR_PATH) + message(FATAL_ERROR "gcovr not found! Aborting...") + endif() # NOT GCOVR_PATH + + # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR + if(DEFINED Coverage_BASE_DIRECTORY) + get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + else() + set(BASEDIR ${PROJECT_SOURCE_DIR}) + endif() + + # Collect excludes (CMake 3.4+: Also compute absolute paths) + set(GCOVR_EXCLUDES "") + foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) + if(CMAKE_VERSION VERSION_GREATER 3.4) + get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) + endif() + list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") + endforeach() + list(REMOVE_DUPLICATES GCOVR_EXCLUDES) + + # Combine excludes to several -e arguments + set(GCOVR_EXCLUDE_ARGS "") + foreach(EXCLUDE ${GCOVR_EXCLUDES}) + list(APPEND GCOVR_EXCLUDE_ARGS "-e") + list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") + endforeach() + + # Set up commands which will be run to generate coverage data + # Run tests + set(GCOVR_HTML_EXEC_TESTS_CMD + ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} + ) + # Create folder + set(GCOVR_HTML_FOLDER_CMD + ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME} + ) + # Running gcovr + set(GCOVR_HTML_CMD + ${GCOVR_PATH} --html ${Coverage_NAME}/index.html --html-details -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} + ${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR} + ) + + if(CODE_COVERAGE_VERBOSE) + message(STATUS "Executed command report") + + message(STATUS "Command to run tests: ") + string(REPLACE ";" " " GCOVR_HTML_EXEC_TESTS_CMD_SPACED "${GCOVR_HTML_EXEC_TESTS_CMD}") + message(STATUS "${GCOVR_HTML_EXEC_TESTS_CMD_SPACED}") + + message(STATUS "Command to create a folder: ") + string(REPLACE ";" " " GCOVR_HTML_FOLDER_CMD_SPACED "${GCOVR_HTML_FOLDER_CMD}") + message(STATUS "${GCOVR_HTML_FOLDER_CMD_SPACED}") + + message(STATUS "Command to generate gcovr HTML coverage data: ") + string(REPLACE ";" " " GCOVR_HTML_CMD_SPACED "${GCOVR_HTML_CMD}") + message(STATUS "${GCOVR_HTML_CMD_SPACED}") + endif() + + add_custom_target(${Coverage_NAME} + COMMAND ${GCOVR_HTML_EXEC_TESTS_CMD} + COMMAND ${GCOVR_HTML_FOLDER_CMD} + COMMAND ${GCOVR_HTML_CMD} + + BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Running gcovr to produce HTML code coverage report." + ) + + # Show info where to find the report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." + ) + +endfunction() # setup_target_for_coverage_gcovr_html + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# setup_target_for_coverage_fastcov( +# NAME testrunner_coverage # New target name +# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES testrunner # Dependencies to build first +# BASE_DIRECTORY "../" # Base directory for report +# # (defaults to PROJECT_SOURCE_DIR) +# EXCLUDE "src/dir1/" "src/dir2/" # Patterns to exclude. +# NO_DEMANGLE # Don't demangle C++ symbols +# # even if c++filt is found +# SKIP_HTML # Don't create html report +# POST_CMD perl -i -pe s!${PROJECT_SOURCE_DIR}/!!g ctest_coverage.json # E.g. for stripping source dir from file paths +# ) +function(setup_target_for_coverage_fastcov) + + set(options NO_DEMANGLE SKIP_HTML) + set(oneValueArgs BASE_DIRECTORY NAME) + set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES FASTCOV_ARGS GENHTML_ARGS POST_CMD) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT FASTCOV_PATH) + message(FATAL_ERROR "fastcov not found! Aborting...") + endif() + + if(NOT Coverage_SKIP_HTML AND NOT GENHTML_PATH) + message(FATAL_ERROR "genhtml not found! Aborting...") + endif() + + # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR + if(Coverage_BASE_DIRECTORY) + get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + else() + set(BASEDIR ${PROJECT_SOURCE_DIR}) + endif() + + # Collect excludes (Patterns, not paths, for fastcov) + set(FASTCOV_EXCLUDES "") + foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_FASTCOV_EXCLUDES}) + list(APPEND FASTCOV_EXCLUDES "${EXCLUDE}") + endforeach() + list(REMOVE_DUPLICATES FASTCOV_EXCLUDES) + + # Conditional arguments + if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE}) + set(GENHTML_EXTRA_ARGS "--demangle-cpp") + endif() + + # Set up commands which will be run to generate coverage data + set(FASTCOV_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}) + + set(FASTCOV_CAPTURE_CMD ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH} + --search-directory ${BASEDIR} + --process-gcno + --output ${Coverage_NAME}.json + --exclude ${FASTCOV_EXCLUDES} + ) + + set(FASTCOV_CONVERT_CMD ${FASTCOV_PATH} + -C ${Coverage_NAME}.json --lcov --output ${Coverage_NAME}.info + ) + + if(Coverage_SKIP_HTML) + set(FASTCOV_HTML_CMD ";") + else() + set(FASTCOV_HTML_CMD ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} + -o ${Coverage_NAME} ${Coverage_NAME}.info + ) + endif() + + set(FASTCOV_POST_CMD ";") + if(Coverage_POST_CMD) + set(FASTCOV_POST_CMD ${Coverage_POST_CMD}) + endif() + + if(CODE_COVERAGE_VERBOSE) + message(STATUS "Code coverage commands for target ${Coverage_NAME} (fastcov):") + + message(" Running tests:") + string(REPLACE ";" " " FASTCOV_EXEC_TESTS_CMD_SPACED "${FASTCOV_EXEC_TESTS_CMD}") + message(" ${FASTCOV_EXEC_TESTS_CMD_SPACED}") + + message(" Capturing fastcov counters and generating report:") + string(REPLACE ";" " " FASTCOV_CAPTURE_CMD_SPACED "${FASTCOV_CAPTURE_CMD}") + message(" ${FASTCOV_CAPTURE_CMD_SPACED}") + + message(" Converting fastcov .json to lcov .info:") + string(REPLACE ";" " " FASTCOV_CONVERT_CMD_SPACED "${FASTCOV_CONVERT_CMD}") + message(" ${FASTCOV_CONVERT_CMD_SPACED}") + + if(NOT Coverage_SKIP_HTML) + message(" Generating HTML report: ") + string(REPLACE ";" " " FASTCOV_HTML_CMD_SPACED "${FASTCOV_HTML_CMD}") + message(" ${FASTCOV_HTML_CMD_SPACED}") + endif() + if(Coverage_POST_CMD) + message(" Running post command: ") + string(REPLACE ";" " " FASTCOV_POST_CMD_SPACED "${FASTCOV_POST_CMD}") + message(" ${FASTCOV_POST_CMD_SPACED}") + endif() + endif() + + # Setup target + add_custom_target(${Coverage_NAME} + + # Cleanup fastcov + COMMAND ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH} + --search-directory ${BASEDIR} + --zerocounters + + COMMAND ${FASTCOV_EXEC_TESTS_CMD} + COMMAND ${FASTCOV_CAPTURE_CMD} + COMMAND ${FASTCOV_CONVERT_CMD} + COMMAND ${FASTCOV_HTML_CMD} + COMMAND ${FASTCOV_POST_CMD} + + # Set output files as GENERATED (will be removed on 'make clean') + BYPRODUCTS + ${Coverage_NAME}.info + ${Coverage_NAME}.json + ${Coverage_NAME}/index.html # report directory + + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report." + ) + + set(INFO_MSG "fastcov code coverage info report saved in ${Coverage_NAME}.info and ${Coverage_NAME}.json.") + if(NOT Coverage_SKIP_HTML) + string(APPEND INFO_MSG " Open ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html in your browser to view the coverage report.") + endif() + # Show where to find the fastcov info report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo ${INFO_MSG} + ) + +endfunction() # setup_target_for_coverage_fastcov + +function(append_coverage_compiler_flags) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}") +endfunction() # append_coverage_compiler_flags + +# Setup coverage for specific library +function(append_coverage_compiler_flags_to_target name) + separate_arguments(_flag_list NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}") + target_compile_options(${name} PRIVATE ${_flag_list}) + if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") + target_link_libraries(${name} PRIVATE gcov) + endif() +endfunction() diff --git a/Builds/CMake/RippledCov.cmake b/Builds/CMake/RippledCov.cmake index e177aa52ae2..4a4d1cfc6e9 100644 --- a/Builds/CMake/RippledCov.cmake +++ b/Builds/CMake/RippledCov.cmake @@ -2,97 +2,39 @@ coverage report target #]===================================================================] -if (coverage) - if (is_clang) - if (APPLE) - execute_process (COMMAND xcrun -f llvm-profdata - OUTPUT_VARIABLE LLVM_PROFDATA - OUTPUT_STRIP_TRAILING_WHITESPACE) - else () - find_program (LLVM_PROFDATA llvm-profdata) - endif () - if (NOT LLVM_PROFDATA) - message (WARNING "unable to find llvm-profdata - skipping coverage_report target") - endif () - - if (APPLE) - execute_process (COMMAND xcrun -f llvm-cov - OUTPUT_VARIABLE LLVM_COV - OUTPUT_STRIP_TRAILING_WHITESPACE) - else () - find_program (LLVM_COV llvm-cov) - endif () - if (NOT LLVM_COV) - message (WARNING "unable to find llvm-cov - skipping coverage_report target") - endif () - - set (extract_pattern "") - if (coverage_core_only) - set (extract_pattern "${CMAKE_CURRENT_SOURCE_DIR}/src/ripple/") - endif () +ProcessorCount(PROCESSOR_COUNT) - if (LLVM_COV AND LLVM_PROFDATA) - add_custom_target (coverage_report - USES_TERMINAL - COMMAND ${CMAKE_COMMAND} -E echo "Generating coverage - results will be in ${CMAKE_BINARY_DIR}/coverage/index.html." - COMMAND ${CMAKE_COMMAND} -E echo "Running rippled tests." - COMMAND rippled --unittest$<$:=${coverage_test}> --quiet --unittest-log - COMMAND ${LLVM_PROFDATA} - merge -sparse default.profraw -o rip.profdata - COMMAND ${CMAKE_COMMAND} -E echo "Summary of coverage:" - COMMAND ${LLVM_COV} - report -instr-profile=rip.profdata - $ ${extract_pattern} - # generate html report - COMMAND ${LLVM_COV} - show -format=html -output-dir=${CMAKE_BINARY_DIR}/coverage - -instr-profile=rip.profdata - $ ${extract_pattern} - BYPRODUCTS coverage/index.html) - endif () - elseif (is_gcc) - find_program (LCOV lcov) - if (NOT LCOV) - message (WARNING "unable to find lcov - skipping coverage_report target") - endif () - - find_program (GENHTML genhtml) - if (NOT GENHTML) - message (WARNING "unable to find genhtml - skipping coverage_report target") - endif () +if (coverage) + if (NOT GENHTML_PATH) + message(FATAL_ERROR "Cannot find genhtml, aborting ...") + endif() - set (extract_pattern "*") - if (coverage_core_only) - set (extract_pattern "*/src/ripple/*") - endif () + math(EXPR TEST_PARALLELISM "(${PROCESSOR_COUNT} + 1)/ 2") + set(COVERAGE_EXCLUDES "/usr/include" "src/ed25519-donna" "src/secp256k1" "src/test") - if (LCOV AND GENHTML) - add_custom_target (coverage_report - USES_TERMINAL - COMMAND ${CMAKE_COMMAND} -E echo "Generating coverage- results will be in ${CMAKE_BINARY_DIR}/coverage/index.html." - # create baseline info file - COMMAND ${LCOV} - --no-external -d "${CMAKE_CURRENT_SOURCE_DIR}" -c -d . -i -o baseline.info - | grep -v "ignoring data for external file" - # run tests - COMMAND ${CMAKE_COMMAND} -E echo "Running rippled tests for coverage report." - COMMAND rippled --unittest$<$:=${coverage_test}> --quiet --unittest-log - # Create test coverage data file - COMMAND ${LCOV} - --no-external -d "${CMAKE_CURRENT_SOURCE_DIR}" -c -d . -o tests.info - | grep -v "ignoring data for external file" - # Combine baseline and test coverage data - COMMAND ${LCOV} - -a baseline.info -a tests.info -o lcov-all.info - # extract our files - COMMAND ${LCOV} - -e lcov-all.info "${extract_pattern}" -o lcov.info - COMMAND ${CMAKE_COMMAND} -E echo "Summary of coverage:" - COMMAND ${LCOV} --summary lcov.info - # generate HTML report - COMMAND ${GENHTML} - -o ${CMAKE_BINARY_DIR}/coverage lcov.info - BYPRODUCTS coverage/index.html) - endif () - endif () -endif () + if (NOT FASTCOV_PATH) + if (NOT GCOVR_PATH) + if (NOT LCOV_PATH) + message(FATAL_ERROR "Cannot find either of fastco, gcovr or lcov, aborting ...") + else() + setup_target_for_coverage_lcov( + NAME coverage_report + EXECUTABLE rippled -u --unittest-jobs ${TEST_PARALLELISM} --quiet --unittest-log + DEPENDENCIES rippled + ) + endif() + else() + setup_target_for_coverage_gcovr_html( + NAME coverage_report + EXECUTABLE rippled -u --unittest-jobs ${TEST_PARALLELISM} --quiet --unittest-log + DEPENDENCIES rippled + ) + endif() + else() + setup_target_for_coverage_fastcov( + NAME coverage_report + EXECUTABLE rippled -u --unittest-jobs ${TEST_PARALLELISM} --quiet --unittest-log + DEPENDENCIES rippled + ) + endif() +endif() diff --git a/Builds/CMake/RippledInterface.cmake b/Builds/CMake/RippledInterface.cmake index dfb57a52f46..4250d1b4b8c 100644 --- a/Builds/CMake/RippledInterface.cmake +++ b/Builds/CMake/RippledInterface.cmake @@ -23,15 +23,13 @@ target_compile_options (opts INTERFACE $<$,$>:-Wsuggest-override> $<$:-fno-omit-frame-pointer> - $<$,$>:-fprofile-arcs -ftest-coverage> - $<$,$>:-fprofile-instr-generate -fcoverage-mapping> + $<$:-g --coverage -fprofile-abs-path> $<$:-pg> $<$,$>:-p>) target_link_libraries (opts INTERFACE - $<$,$>:-fprofile-arcs -ftest-coverage> - $<$,$>:-fprofile-instr-generate -fcoverage-mapping> + $<$:-g --coverage -fprofile-abs-path> $<$:-pg> $<$,$>:-p>) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bbde549602..03d21e89e32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,10 @@ if(Git_FOUND) endif() endif() #git +include (CodeCoverage) +include (ProcessorCount) +include (RippledCov) + if(thread_safety_analysis) add_compile_options(-Wthread-safety -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -DRIPPLE_ENABLE_THREAD_SAFETY_ANNOTATIONS) add_compile_options("-stdlib=libc++") @@ -38,7 +42,6 @@ include (CheckCXXCompilerFlag) include (FetchContent) include (ExternalProject) include (CMakeFuncs) # must come *after* ExternalProject b/c it overrides one function in EP -include (ProcessorCount) if (target) message (FATAL_ERROR "The target option has been removed - use native cmake options to control build") endif () @@ -132,6 +135,5 @@ include(RippledCore) include(deps/Protobuf) include(deps/gRPC) include(RippledInstall) -include(RippledCov) include(RippledMultiConfig) include(RippledValidatorKeys) From c71abcb6822b22da4f5632f4c90cbdb377469b3c Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Fri, 8 Dec 2023 17:58:04 +0000 Subject: [PATCH 02/23] Skip coverage targets in MSVC --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 03d21e89e32..d87f5a5603d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,9 +28,11 @@ if(Git_FOUND) endif() endif() #git -include (CodeCoverage) include (ProcessorCount) -include (RippledCov) +if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + include (CodeCoverage) + include (RippledCov) +endif() if(thread_safety_analysis) add_compile_options(-Wthread-safety -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -DRIPPLE_ENABLE_THREAD_SAFETY_ANNOTATIONS) From c9683c974e8eec49fd79d68c2d61db7a7ebdb1da Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Fri, 8 Dec 2023 20:06:16 +0000 Subject: [PATCH 03/23] Clang does not support -fprofile-abs-path --- Builds/CMake/RippledInterface.cmake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Builds/CMake/RippledInterface.cmake b/Builds/CMake/RippledInterface.cmake index 4250d1b4b8c..56d36a528ff 100644 --- a/Builds/CMake/RippledInterface.cmake +++ b/Builds/CMake/RippledInterface.cmake @@ -23,13 +23,15 @@ target_compile_options (opts INTERFACE $<$,$>:-Wsuggest-override> $<$:-fno-omit-frame-pointer> - $<$:-g --coverage -fprofile-abs-path> + $<$,$>:-g --coverage -fprofile-abs-path> + $<$,$>:-g --coverage> $<$:-pg> $<$,$>:-p>) target_link_libraries (opts INTERFACE - $<$:-g --coverage -fprofile-abs-path> + $<$,$>:-g --coverage -fprofile-abs-path> + $<$,$>:-g --coverage> $<$:-pg> $<$,$>:-p>) From 0cec21a260aa326156ef035305e929c525fc160b Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Mon, 11 Dec 2023 17:00:25 +0000 Subject: [PATCH 04/23] Disable fastcov and lcov --- Builds/CMake/CodeCoverage.cmake | 330 -------------------------------- Builds/CMake/RippledCov.cmake | 35 +--- 2 files changed, 5 insertions(+), 360 deletions(-) diff --git a/Builds/CMake/CodeCoverage.cmake b/Builds/CMake/CodeCoverage.cmake index b9e114bc373..8ab40d2244e 100644 --- a/Builds/CMake/CodeCoverage.cmake +++ b/Builds/CMake/CodeCoverage.cmake @@ -140,16 +140,7 @@ include(CMakeParseArguments) option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE) # Check prereqs -find_program( GCOV_PATH gcov ) -find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl) -find_program( FASTCOV_PATH NAMES fastcov fastcov.py ) -find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat ) find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) -find_program( CPPFILT_PATH NAMES c++filt ) - -if(NOT GCOV_PATH) - message(FATAL_ERROR "gcov not found! Aborting...") -endif() # NOT GCOV_PATH # Check supported compiler (Clang, GNU and Flang) get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) @@ -215,185 +206,6 @@ if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU link_libraries(gcov) endif() -# Defines a target for running and collection code coverage information -# Builds dependencies, runs the given executable and outputs reports. -# NOTE! The executable should always have a ZERO as exit code otherwise -# the coverage generation will not complete. -# -# setup_target_for_coverage_lcov( -# NAME testrunner_coverage # New target name -# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR -# DEPENDENCIES testrunner # Dependencies to build first -# BASE_DIRECTORY "../" # Base directory for report -# # (defaults to PROJECT_SOURCE_DIR) -# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative -# # to BASE_DIRECTORY, with CMake 3.4+) -# NO_DEMANGLE # Don't demangle C++ symbols -# # even if c++filt is found -# ) -function(setup_target_for_coverage_lcov) - - set(options NO_DEMANGLE SONARQUBE) - set(oneValueArgs BASE_DIRECTORY NAME) - set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS) - cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if(NOT LCOV_PATH) - message(FATAL_ERROR "lcov not found! Aborting...") - endif() # NOT LCOV_PATH - - if(NOT GENHTML_PATH) - message(FATAL_ERROR "genhtml not found! Aborting...") - endif() # NOT GENHTML_PATH - - # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR - if(DEFINED Coverage_BASE_DIRECTORY) - get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) - else() - set(BASEDIR ${PROJECT_SOURCE_DIR}) - endif() - - # Collect excludes (CMake 3.4+: Also compute absolute paths) - set(LCOV_EXCLUDES "") - foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES}) - if(CMAKE_VERSION VERSION_GREATER 3.4) - get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) - endif() - list(APPEND LCOV_EXCLUDES "${EXCLUDE}") - endforeach() - list(REMOVE_DUPLICATES LCOV_EXCLUDES) - - # Conditional arguments - if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE}) - set(GENHTML_EXTRA_ARGS "--demangle-cpp") - endif() - - # Setting up commands which will be run to generate coverage data. - # Cleanup lcov - set(LCOV_CLEAN_CMD - ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . - -b ${BASEDIR} --zerocounters - ) - # Create baseline to make sure untouched files show up in the report - set(LCOV_BASELINE_CMD - ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b - ${BASEDIR} -o ${Coverage_NAME}.base - ) - # Run tests - set(LCOV_EXEC_TESTS_CMD - ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} - ) - # Capturing lcov counters and generating report - set(LCOV_CAPTURE_CMD - ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b - ${BASEDIR} --capture --output-file ${Coverage_NAME}.capture - ) - # add baseline counters - set(LCOV_BASELINE_COUNT_CMD - ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base - -a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total - ) - # filter collected data to final coverage report - set(LCOV_FILTER_CMD - ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove - ${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info - ) - # Generate HTML output - set(LCOV_GEN_HTML_CMD - ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o - ${Coverage_NAME} ${Coverage_NAME}.info - ) - if(${Coverage_SONARQUBE}) - # Generate SonarQube output - set(GCOVR_XML_CMD - ${GCOVR_PATH} --sonarqube ${Coverage_NAME}_sonarqube.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} - ${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR} - ) - set(GCOVR_XML_CMD_COMMAND - COMMAND ${GCOVR_XML_CMD} - ) - set(GCOVR_XML_CMD_BYPRODUCTS ${Coverage_NAME}_sonarqube.xml) - set(GCOVR_XML_CMD_COMMENT COMMENT "SonarQube code coverage info report saved in ${Coverage_NAME}_sonarqube.xml.") - endif() - - - if(CODE_COVERAGE_VERBOSE) - message(STATUS "Executed command report") - message(STATUS "Command to clean up lcov: ") - string(REPLACE ";" " " LCOV_CLEAN_CMD_SPACED "${LCOV_CLEAN_CMD}") - message(STATUS "${LCOV_CLEAN_CMD_SPACED}") - - message(STATUS "Command to create baseline: ") - string(REPLACE ";" " " LCOV_BASELINE_CMD_SPACED "${LCOV_BASELINE_CMD}") - message(STATUS "${LCOV_BASELINE_CMD_SPACED}") - - message(STATUS "Command to run the tests: ") - string(REPLACE ";" " " LCOV_EXEC_TESTS_CMD_SPACED "${LCOV_EXEC_TESTS_CMD}") - message(STATUS "${LCOV_EXEC_TESTS_CMD_SPACED}") - - message(STATUS "Command to capture counters and generate report: ") - string(REPLACE ";" " " LCOV_CAPTURE_CMD_SPACED "${LCOV_CAPTURE_CMD}") - message(STATUS "${LCOV_CAPTURE_CMD_SPACED}") - - message(STATUS "Command to add baseline counters: ") - string(REPLACE ";" " " LCOV_BASELINE_COUNT_CMD_SPACED "${LCOV_BASELINE_COUNT_CMD}") - message(STATUS "${LCOV_BASELINE_COUNT_CMD_SPACED}") - - message(STATUS "Command to filter collected data: ") - string(REPLACE ";" " " LCOV_FILTER_CMD_SPACED "${LCOV_FILTER_CMD}") - message(STATUS "${LCOV_FILTER_CMD_SPACED}") - - message(STATUS "Command to generate lcov HTML output: ") - string(REPLACE ";" " " LCOV_GEN_HTML_CMD_SPACED "${LCOV_GEN_HTML_CMD}") - message(STATUS "${LCOV_GEN_HTML_CMD_SPACED}") - - if(${Coverage_SONARQUBE}) - message(STATUS "Command to generate SonarQube XML output: ") - string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}") - message(STATUS "${GCOVR_XML_CMD_SPACED}") - endif() - endif() - - # Setup target - add_custom_target(${Coverage_NAME} - COMMAND ${LCOV_CLEAN_CMD} - COMMAND ${LCOV_BASELINE_CMD} - COMMAND ${LCOV_EXEC_TESTS_CMD} - COMMAND ${LCOV_CAPTURE_CMD} - COMMAND ${LCOV_BASELINE_COUNT_CMD} - COMMAND ${LCOV_FILTER_CMD} - COMMAND ${LCOV_GEN_HTML_CMD} - ${GCOVR_XML_CMD_COMMAND} - - # Set output files as GENERATED (will be removed on 'make clean') - BYPRODUCTS - ${Coverage_NAME}.base - ${Coverage_NAME}.capture - ${Coverage_NAME}.total - ${Coverage_NAME}.info - ${GCOVR_XML_CMD_BYPRODUCTS} - ${Coverage_NAME}/index.html - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - DEPENDS ${Coverage_DEPENDENCIES} - VERBATIM # Protect arguments to commands - COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." - ) - - # Show where to find the lcov info report - add_custom_command(TARGET ${Coverage_NAME} POST_BUILD - COMMAND ; - COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info." - ${GCOVR_XML_CMD_COMMENT} - ) - - # Show info where to find the report - add_custom_command(TARGET ${Coverage_NAME} POST_BUILD - COMMAND ; - COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." - ) - -endfunction() # setup_target_for_coverage_lcov - # Defines a target for running and collection code coverage information # Builds dependencies, runs the given executable and outputs reports. # NOTE! The executable should always have a ZERO as exit code otherwise @@ -588,148 +400,6 @@ function(setup_target_for_coverage_gcovr_html) endfunction() # setup_target_for_coverage_gcovr_html -# Defines a target for running and collection code coverage information -# Builds dependencies, runs the given executable and outputs reports. -# NOTE! The executable should always have a ZERO as exit code otherwise -# the coverage generation will not complete. -# -# setup_target_for_coverage_fastcov( -# NAME testrunner_coverage # New target name -# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR -# DEPENDENCIES testrunner # Dependencies to build first -# BASE_DIRECTORY "../" # Base directory for report -# # (defaults to PROJECT_SOURCE_DIR) -# EXCLUDE "src/dir1/" "src/dir2/" # Patterns to exclude. -# NO_DEMANGLE # Don't demangle C++ symbols -# # even if c++filt is found -# SKIP_HTML # Don't create html report -# POST_CMD perl -i -pe s!${PROJECT_SOURCE_DIR}/!!g ctest_coverage.json # E.g. for stripping source dir from file paths -# ) -function(setup_target_for_coverage_fastcov) - - set(options NO_DEMANGLE SKIP_HTML) - set(oneValueArgs BASE_DIRECTORY NAME) - set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES FASTCOV_ARGS GENHTML_ARGS POST_CMD) - cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if(NOT FASTCOV_PATH) - message(FATAL_ERROR "fastcov not found! Aborting...") - endif() - - if(NOT Coverage_SKIP_HTML AND NOT GENHTML_PATH) - message(FATAL_ERROR "genhtml not found! Aborting...") - endif() - - # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR - if(Coverage_BASE_DIRECTORY) - get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) - else() - set(BASEDIR ${PROJECT_SOURCE_DIR}) - endif() - - # Collect excludes (Patterns, not paths, for fastcov) - set(FASTCOV_EXCLUDES "") - foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_FASTCOV_EXCLUDES}) - list(APPEND FASTCOV_EXCLUDES "${EXCLUDE}") - endforeach() - list(REMOVE_DUPLICATES FASTCOV_EXCLUDES) - - # Conditional arguments - if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE}) - set(GENHTML_EXTRA_ARGS "--demangle-cpp") - endif() - - # Set up commands which will be run to generate coverage data - set(FASTCOV_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}) - - set(FASTCOV_CAPTURE_CMD ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH} - --search-directory ${BASEDIR} - --process-gcno - --output ${Coverage_NAME}.json - --exclude ${FASTCOV_EXCLUDES} - ) - - set(FASTCOV_CONVERT_CMD ${FASTCOV_PATH} - -C ${Coverage_NAME}.json --lcov --output ${Coverage_NAME}.info - ) - - if(Coverage_SKIP_HTML) - set(FASTCOV_HTML_CMD ";") - else() - set(FASTCOV_HTML_CMD ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} - -o ${Coverage_NAME} ${Coverage_NAME}.info - ) - endif() - - set(FASTCOV_POST_CMD ";") - if(Coverage_POST_CMD) - set(FASTCOV_POST_CMD ${Coverage_POST_CMD}) - endif() - - if(CODE_COVERAGE_VERBOSE) - message(STATUS "Code coverage commands for target ${Coverage_NAME} (fastcov):") - - message(" Running tests:") - string(REPLACE ";" " " FASTCOV_EXEC_TESTS_CMD_SPACED "${FASTCOV_EXEC_TESTS_CMD}") - message(" ${FASTCOV_EXEC_TESTS_CMD_SPACED}") - - message(" Capturing fastcov counters and generating report:") - string(REPLACE ";" " " FASTCOV_CAPTURE_CMD_SPACED "${FASTCOV_CAPTURE_CMD}") - message(" ${FASTCOV_CAPTURE_CMD_SPACED}") - - message(" Converting fastcov .json to lcov .info:") - string(REPLACE ";" " " FASTCOV_CONVERT_CMD_SPACED "${FASTCOV_CONVERT_CMD}") - message(" ${FASTCOV_CONVERT_CMD_SPACED}") - - if(NOT Coverage_SKIP_HTML) - message(" Generating HTML report: ") - string(REPLACE ";" " " FASTCOV_HTML_CMD_SPACED "${FASTCOV_HTML_CMD}") - message(" ${FASTCOV_HTML_CMD_SPACED}") - endif() - if(Coverage_POST_CMD) - message(" Running post command: ") - string(REPLACE ";" " " FASTCOV_POST_CMD_SPACED "${FASTCOV_POST_CMD}") - message(" ${FASTCOV_POST_CMD_SPACED}") - endif() - endif() - - # Setup target - add_custom_target(${Coverage_NAME} - - # Cleanup fastcov - COMMAND ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH} - --search-directory ${BASEDIR} - --zerocounters - - COMMAND ${FASTCOV_EXEC_TESTS_CMD} - COMMAND ${FASTCOV_CAPTURE_CMD} - COMMAND ${FASTCOV_CONVERT_CMD} - COMMAND ${FASTCOV_HTML_CMD} - COMMAND ${FASTCOV_POST_CMD} - - # Set output files as GENERATED (will be removed on 'make clean') - BYPRODUCTS - ${Coverage_NAME}.info - ${Coverage_NAME}.json - ${Coverage_NAME}/index.html # report directory - - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - DEPENDS ${Coverage_DEPENDENCIES} - VERBATIM # Protect arguments to commands - COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report." - ) - - set(INFO_MSG "fastcov code coverage info report saved in ${Coverage_NAME}.info and ${Coverage_NAME}.json.") - if(NOT Coverage_SKIP_HTML) - string(APPEND INFO_MSG " Open ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html in your browser to view the coverage report.") - endif() - # Show where to find the fastcov info report - add_custom_command(TARGET ${Coverage_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E echo ${INFO_MSG} - ) - -endfunction() # setup_target_for_coverage_fastcov - function(append_coverage_compiler_flags) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) diff --git a/Builds/CMake/RippledCov.cmake b/Builds/CMake/RippledCov.cmake index 4a4d1cfc6e9..44e706ee15a 100644 --- a/Builds/CMake/RippledCov.cmake +++ b/Builds/CMake/RippledCov.cmake @@ -5,36 +5,11 @@ ProcessorCount(PROCESSOR_COUNT) if (coverage) - if (NOT GENHTML_PATH) - message(FATAL_ERROR "Cannot find genhtml, aborting ...") - endif() - - math(EXPR TEST_PARALLELISM "(${PROCESSOR_COUNT} + 1)/ 2") set(COVERAGE_EXCLUDES "/usr/include" "src/ed25519-donna" "src/secp256k1" "src/test") - if (NOT FASTCOV_PATH) - if (NOT GCOVR_PATH) - if (NOT LCOV_PATH) - message(FATAL_ERROR "Cannot find either of fastco, gcovr or lcov, aborting ...") - else() - setup_target_for_coverage_lcov( - NAME coverage_report - EXECUTABLE rippled -u --unittest-jobs ${TEST_PARALLELISM} --quiet --unittest-log - DEPENDENCIES rippled - ) - endif() - else() - setup_target_for_coverage_gcovr_html( - NAME coverage_report - EXECUTABLE rippled -u --unittest-jobs ${TEST_PARALLELISM} --quiet --unittest-log - DEPENDENCIES rippled - ) - endif() - else() - setup_target_for_coverage_fastcov( - NAME coverage_report - EXECUTABLE rippled -u --unittest-jobs ${TEST_PARALLELISM} --quiet --unittest-log - DEPENDENCIES rippled - ) - endif() + setup_target_for_coverage_gcovr_html( + NAME coverage_report + EXECUTABLE rippled -u --unittest-jobs ${PROCESSOR_COUNT} --quiet --unittest-log + DEPENDENCIES rippled + ) endif() From 1de7131a2b674221f33b77be6175f91a9882aba7 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Mon, 11 Dec 2023 14:06:56 +0000 Subject: [PATCH 05/23] MacOS fixes, other improvements --- Builds/CMake/CodeCoverage.cmake | 57 +++++++++++++++++++++++++++++---- Builds/CMake/RippledCov.cmake | 12 +++++-- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/Builds/CMake/CodeCoverage.cmake b/Builds/CMake/CodeCoverage.cmake index 8ab40d2244e..c0e921f6a46 100644 --- a/Builds/CMake/CodeCoverage.cmake +++ b/Builds/CMake/CodeCoverage.cmake @@ -142,6 +142,32 @@ option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE) # Check prereqs find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) +if (DEFINED CODE_COVERAGE_GCOV_TOOL) + set(GCOV_TOOL "${CODE_COVERAGE_GCOV_TOOL}") +elseif (DEFINED ENV{CODE_COVERAGE_GCOV_TOOL}) + set(GCOV_TOOL "$ENV{CODE_COVERAGE_GCOV_TOOL}") +elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") + if (APPLE) + execute_process( COMMAND xcrun -f llvm-cov + OUTPUT_VARIABLE LLVMCOV_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + else() + find_program( LLVMCOV_PATH llvm-cov ) + endif() + if (NOT LLVMCOV_PATH) + message(FATAL_ERROR "llvm-cov tool not found! Aborting...") + endif() + set(GCOV_TOOL "${LLVMCOV_PATH} gcov") +elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + find_program( GCOV_PATH gcov ) + set(GCOV_TOOL ${GCOV_PATH}) +endif() + +if(NOT GCOV_TOOL) + message(FATAL_ERROR "gcov tool not found! Aborting...") +endif() # NOT GCOV_TOOL + # Check supported compiler (Clang, GNU and Flang) get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) foreach(LANG ${LANGUAGES}) @@ -223,7 +249,6 @@ endif() # The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the # GCVOR command. function(setup_target_for_coverage_gcovr_xml) - set(options NONE) set(oneValueArgs BASE_DIRECTORY NAME) set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) @@ -264,8 +289,15 @@ function(setup_target_for_coverage_gcovr_xml) ) # Running gcovr set(GCOVR_XML_CMD - ${GCOVR_PATH} --xml ${Coverage_NAME}.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} - ${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR} + ${GCOVR_PATH} + --gcov-executable ${GCOV_TOOL} + --gcov-ignore-parse-errors=negative_hits.warn_once_per_file + --output ${Coverage_NAME}.xml + --xml + -r ${BASEDIR} + ${GCOVR_ADDITIONAL_ARGS} + ${GCOVR_EXCLUDE_ARGS} + --object-directory=${PROJECT_BINARY_DIR} ) if(CODE_COVERAGE_VERBOSE) @@ -315,7 +347,6 @@ endfunction() # setup_target_for_coverage_gcovr_xml # The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the # GCVOR command. function(setup_target_for_coverage_gcovr_html) - set(options NONE) set(oneValueArgs BASE_DIRECTORY NAME) set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) @@ -332,6 +363,13 @@ function(setup_target_for_coverage_gcovr_html) set(BASEDIR ${PROJECT_SOURCE_DIR}) endif() + # Optionally set --html-details + if((NOT "--html-details" IN_LIST GCOVR_ADDITIONAL_ARGS) + AND (NOT "--html-nested" IN_LIST GCOVR_ADDITIONAL_ARGS) + AND (NOT "--html" IN_LIST GCOVR_ADDITIONAL_ARGS)) + list(APPEND GCOVR_ADDITIONAL_ARGS --html-details) + endif() + # Collect excludes (CMake 3.4+: Also compute absolute paths) set(GCOVR_EXCLUDES "") foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) @@ -360,8 +398,15 @@ function(setup_target_for_coverage_gcovr_html) ) # Running gcovr set(GCOVR_HTML_CMD - ${GCOVR_PATH} --html ${Coverage_NAME}/index.html --html-details -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} - ${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR} + ${GCOVR_PATH} + --gcov-executable ${GCOV_TOOL} + --gcov-ignore-parse-errors=negative_hits.warn_once_per_file + --output ${Coverage_NAME}/index.html + --html + -r ${BASEDIR} + ${GCOVR_ADDITIONAL_ARGS} + ${GCOVR_EXCLUDE_ARGS} + --object-directory=${PROJECT_BINARY_DIR} ) if(CODE_COVERAGE_VERBOSE) diff --git a/Builds/CMake/RippledCov.cmake b/Builds/CMake/RippledCov.cmake index 44e706ee15a..f7e1e29748a 100644 --- a/Builds/CMake/RippledCov.cmake +++ b/Builds/CMake/RippledCov.cmake @@ -5,11 +5,19 @@ ProcessorCount(PROCESSOR_COUNT) if (coverage) - set(COVERAGE_EXCLUDES "/usr/include" "src/ed25519-donna" "src/secp256k1" "src/test") + if (DEFINED CODE_COVERAGE_TEST_PARALLELISM) + set(TEST_PARALLELISM ${CODE_COVERAGE_TEST_PARALLELISM}) + else() + set(TEST_PARALLELISM ${PROCESSOR_COUNT}) + endif() + + set (GCOVR_ADDITIONAL_ARGS --exclude-noncode-lines --exclude-unreachable-branches -j ${PROCESSOR_COUNT} -s) setup_target_for_coverage_gcovr_html( NAME coverage_report - EXECUTABLE rippled -u --unittest-jobs ${PROCESSOR_COUNT} --quiet --unittest-log + EXECUTABLE rippled + EXECUTABLE_ARGS -u --unittest-jobs ${TEST_PARALLELISM} --quiet --unittest-log + EXCLUDE "src/test" "${CMAKE_BINARY_DIR}/proto_gen" "${CMAKE_BINARY_DIR}/proto_gen_grpc" DEPENDENCIES rippled ) endif() From 9f77969539b11295e31935b44d31174ccf9c68c2 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Tue, 12 Dec 2023 10:31:15 +0000 Subject: [PATCH 06/23] Workaround for clang error Ideally we want PATH set correctly in docker image used --- .github/actions/build/action.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index d7a92b3b409..8959cf6a791 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -10,6 +10,10 @@ inputs: runs: using: composite steps: + - name: update path for clang-14 + shell: bash + run: | + echo "/usr/lib/llvm-14/bin/" >> $GITHUB_PATH - name: configure shell: bash run: | From ef8221ebcb53f969ea3891d1351ba3a08e49037c Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Thu, 14 Dec 2023 17:31:56 +0000 Subject: [PATCH 07/23] Add coverage to github actions --- .github/actions/build/action.yml | 10 +- .github/actions/dependencies/action.yml | 3 + .github/workflows/nix.yml | 60 ++++++ .github/workflows/windows.yml | 1 + Builds/CMake/CodeCoverage.cmake | 255 +++++++++++------------- Builds/CMake/RippledCov.cmake | 11 +- 6 files changed, 196 insertions(+), 144 deletions(-) diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 8959cf6a791..6c74afc1f2f 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -6,14 +6,12 @@ inputs: required: true cmake-args: default: null + cmake-target: + default: all # An implicit input is the environment variable `build_dir`. runs: using: composite steps: - - name: update path for clang-14 - shell: bash - run: | - echo "/usr/lib/llvm-14/bin/" >> $GITHUB_PATH - name: configure shell: bash run: | @@ -22,6 +20,7 @@ runs: ${{ inputs.generator && format('-G "{0}"', inputs.generator) || '' }} \ -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \ -DCMAKE_BUILD_TYPE=${{ inputs.configuration }} \ + -DCODE_COVERAGE_GCOV_TOOL=/usr/bin/gcov \ ${{ inputs.cmake-args }} \ .. - name: build @@ -30,4 +29,5 @@ runs: cmake \ --build ${build_dir} \ --config ${{ inputs.configuration }} \ - --parallel ${NUM_PROCESSORS:-$(nproc)} + --parallel ${NUM_PROCESSORS:-$(nproc)} \ + --target ${{ inputs.cmake-target }} diff --git a/.github/actions/dependencies/action.yml b/.github/actions/dependencies/action.yml index 3147e8774f2..2c6679ee4b2 100644 --- a/.github/actions/dependencies/action.yml +++ b/.github/actions/dependencies/action.yml @@ -2,6 +2,8 @@ name: dependencies inputs: configuration: required: true + coverage: + default: "False" # An implicit input is the environment variable `build_dir`. runs: using: composite @@ -23,4 +25,5 @@ runs: --output-folder . \ --build missing \ --settings build_type=${{ inputs.configuration }} \ + --options coverage=${{ inputs.coverage }} \ .. diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index e43ae1379c9..93a737ddfdf 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -159,3 +159,63 @@ jobs: - name: test run: | ${build_dir}/rippled --unittest --unittest-jobs $(nproc) + + + coverage: + strategy: + fail-fast: false + matrix: + platform: + - linux + compiler: + - gcc + configuration: + - Debug + needs: dependencies + runs-on: [self-hosted, heavy] + container: thejohnfreeman/rippled-build-ubuntu:12e19cd9034b + env: + build_dir: .build + steps: + - name: download cache + uses: actions/download-artifact@v3 + with: + name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }} + - name: extract cache + run: | + mkdir -p ~/.conan + tar -xzf conan.tar -C ~/.conan + - name: install gcovr + run: | + pip install 'gcovr<7' + - name: check environment + run: | + echo ${PATH} | tr ':' '\n' + conan --version + cmake --version + gcovr --version + env | sort + ls ~/.conan + - name: checkout + uses: actions/checkout@v3 + - name: dependencies + uses: ./.github/actions/dependencies + with: + configuration: ${{ matrix.configuration }} + coverage: "True" + - name: build + uses: ./.github/actions/build + with: + generator: Ninja + configuration: ${{ matrix.configuration }} + cmake-args: >- + -DCODE_COVERAGE_REPORT_FORMAT=xml + -DCMAKE_CXX_FLAGS="-O0" + -DCMAKE_C_FLAGS="-O0" + cmake-target: coverage_report + - name: archive coverage results + uses: actions/upload-artifact@v3 + with: + name: coverage-report.xml + path: .build/coverage_report.xml + retention-days: 30 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 1d2b5bb5583..7286d2f1f34 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -90,6 +90,7 @@ jobs: configuration: ${{ matrix.configuration }} # Hard code for now. Move to the matrix if varied options are needed cmake-args: '-Dassert=ON -Dreporting=OFF -Dunity=ON' + cmake-target: install - name: test (permitted to silently fail) shell: bash # Github runners are resource limited, which causes unit tests to fail diff --git a/Builds/CMake/CodeCoverage.cmake b/Builds/CMake/CodeCoverage.cmake index c0e921f6a46..9c013bccab6 100644 --- a/Builds/CMake/CodeCoverage.cmake +++ b/Builds/CMake/CodeCoverage.cmake @@ -87,6 +87,14 @@ # - 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. @@ -111,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/*") @@ -120,12 +128,22 @@ # relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR) # Example: # set(COVERAGE_EXCLUDES "dir1/*") -# setup_target_for_coverage_gcovr_html( +# setup_target_for_coverage_gcovr( # NAME coverage # EXECUTABLE testrunner +# FORMAT html-details # 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. # @@ -133,7 +151,6 @@ # cmake -DCMAKE_BUILD_TYPE=Debug .. # make # make my_coverage_target -# include(CMakeParseArguments) @@ -155,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 "llvm-cov tool not found! 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 "gcov tool not found! Aborting...") -endif() # NOT GCOV_TOOL - # Check supported compiler (Clang, GNU and Flang) get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) foreach(LANG ${LANGUAGES}) @@ -237,26 +249,39 @@ endif() # NOTE! The executable should always have a ZERO as exit code otherwise # the coverage generation will not complete. # -# setup_target_for_coverage_gcovr_xml( +# setup_target_for_coverage_gcovr( # NAME ctest_coverage # New target name # EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR # DEPENDENCIES executable_target # Dependencies to build first # BASE_DIRECTORY "../" # Base directory for report # # (defaults to PROJECT_SOURCE_DIR) +# FORMAT "cobertura" # Output format, one of: +# # xml cobertura sonarqube json-summary +# # 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) # EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative # # to BASE_DIRECTORY, with CMake 3.4+) # ) # The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the # GCVOR command. -function(setup_target_for_coverage_gcovr_xml) +function(setup_target_for_coverage_gcovr) set(options NONE) - set(oneValueArgs BASE_DIRECTORY NAME) + set(oneValueArgs BASE_DIRECTORY NAME FORMAT) 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 "gcovr not found! Aborting...") - endif() # NOT GCOVR_PATH + message(FATAL_ERROR "Could not find gcovr tool! Aborting...") + endif() # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR if(DEFINED Coverage_BASE_DIRECTORY) @@ -265,109 +290,61 @@ function(setup_target_for_coverage_gcovr_xml) set(BASEDIR ${PROJECT_SOURCE_DIR}) endif() - # Collect excludes (CMake 3.4+: Also compute absolute paths) - set(GCOVR_EXCLUDES "") - foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) - if(CMAKE_VERSION VERSION_GREATER 3.4) - get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) - endif() - list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") - endforeach() - list(REMOVE_DUPLICATES GCOVR_EXCLUDES) - - # Combine excludes to several -e arguments - set(GCOVR_EXCLUDE_ARGS "") - foreach(EXCLUDE ${GCOVR_EXCLUDES}) - list(APPEND GCOVR_EXCLUDE_ARGS "-e") - list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") - endforeach() - - # Set up commands which will be run to generate coverage data - # Run tests - set(GCOVR_XML_EXEC_TESTS_CMD - ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} - ) - # Running gcovr - set(GCOVR_XML_CMD - ${GCOVR_PATH} - --gcov-executable ${GCOV_TOOL} - --gcov-ignore-parse-errors=negative_hits.warn_once_per_file - --output ${Coverage_NAME}.xml - --xml - -r ${BASEDIR} - ${GCOVR_ADDITIONAL_ARGS} - ${GCOVR_EXCLUDE_ARGS} - --object-directory=${PROJECT_BINARY_DIR} - ) - - if(CODE_COVERAGE_VERBOSE) - message(STATUS "Executed command report") - - message(STATUS "Command to run tests: ") - string(REPLACE ";" " " GCOVR_XML_EXEC_TESTS_CMD_SPACED "${GCOVR_XML_EXEC_TESTS_CMD}") - message(STATUS "${GCOVR_XML_EXEC_TESTS_CMD_SPACED}") - - message(STATUS "Command to generate gcovr XML coverage data: ") - string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}") - message(STATUS "${GCOVR_XML_CMD_SPACED}") + if(NOT DEFINED Coverage_FORMAT) + set(Coverage_FORMAT xml) endif() - add_custom_target(${Coverage_NAME} - COMMAND ${GCOVR_XML_EXEC_TESTS_CMD} - COMMAND ${GCOVR_XML_CMD} - - BYPRODUCTS ${Coverage_NAME}.xml - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - DEPENDS ${Coverage_DEPENDENCIES} - VERBATIM # Protect arguments to commands - COMMENT "Running gcovr to produce Cobertura code coverage report." - ) - - # Show info where to find the report - add_custom_command(TARGET ${Coverage_NAME} POST_BUILD - COMMAND ; - COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml." - ) -endfunction() # setup_target_for_coverage_gcovr_xml - -# Defines a target for running and collection code coverage information -# Builds dependencies, runs the given executable and outputs reports. -# NOTE! The executable should always have a ZERO as exit code otherwise -# the coverage generation will not complete. -# -# setup_target_for_coverage_gcovr_html( -# NAME ctest_coverage # New target name -# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR -# DEPENDENCIES executable_target # Dependencies to build first -# BASE_DIRECTORY "../" # Base directory for report -# # (defaults to PROJECT_SOURCE_DIR) -# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative -# # to BASE_DIRECTORY, with CMake 3.4+) -# ) -# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the -# GCVOR command. -function(setup_target_for_coverage_gcovr_html) - set(options NONE) - set(oneValueArgs BASE_DIRECTORY NAME) - set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) - cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if(NOT GCOVR_PATH) - message(FATAL_ERROR "gcovr not found! Aborting...") - endif() # NOT GCOVR_PATH - - # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR - if(DEFINED Coverage_BASE_DIRECTORY) - get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + if("--output" IN_LIST GCOVR_ADDITIONAL_ARGS) + message(FATAL_ERROR "Unsupported --output option detected in GCOVR_ADDITIONAL_ARGS! Aborting...") else() - set(BASEDIR ${PROJECT_SOURCE_DIR}) + if((Coverage_FORMAT STREQUAL "html-details") + OR (Coverage_FORMAT STREQUAL "html-nested")) + set(GCOVR_OUTPUT_FILE ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html) + set(GCOVR_CREATE_FOLDER ${PROJECT_BINARY_DIR}/${Coverage_NAME}) + elseif(Coverage_FORMAT STREQUAL "html-single") + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.html) + elseif((Coverage_FORMAT STREQUAL "json-summary") + OR (Coverage_FORMAT STREQUAL "json-details") + OR (Coverage_FORMAT STREQUAL "coveralls")) + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.json) + elseif(Coverage_FORMAT STREQUAL "txt") + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.txt) + elseif(Coverage_FORMAT STREQUAL "csv") + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.csv) + else() + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.xml) + endif() endif() - # Optionally set --html-details - if((NOT "--html-details" IN_LIST GCOVR_ADDITIONAL_ARGS) - AND (NOT "--html-nested" IN_LIST GCOVR_ADDITIONAL_ARGS) - AND (NOT "--html" IN_LIST GCOVR_ADDITIONAL_ARGS)) - list(APPEND GCOVR_ADDITIONAL_ARGS --html-details) + 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) @@ -389,20 +366,23 @@ function(setup_target_for_coverage_gcovr_html) # Set up commands which will be run to generate coverage data # Run tests - set(GCOVR_HTML_EXEC_TESTS_CMD + set(GCOVR_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} ) + # Create folder - set(GCOVR_HTML_FOLDER_CMD - ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME} - ) + if(DEFINED GCOVR_CREATE_FOLDER) + set(GCOVR_FOLDER_CMD + ${CMAKE_COMMAND} -E make_directory ${GCOVR_CREATE_FOLDER}) + else() + set(GCOVR_FOLDER_CMD echo) # dummy + endif() + # Running gcovr - set(GCOVR_HTML_CMD + set(GCOVR_CMD ${GCOVR_PATH} --gcov-executable ${GCOV_TOOL} --gcov-ignore-parse-errors=negative_hits.warn_once_per_file - --output ${Coverage_NAME}/index.html - --html -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} ${GCOVR_EXCLUDE_ARGS} @@ -413,37 +393,38 @@ function(setup_target_for_coverage_gcovr_html) message(STATUS "Executed command report") message(STATUS "Command to run tests: ") - string(REPLACE ";" " " GCOVR_HTML_EXEC_TESTS_CMD_SPACED "${GCOVR_HTML_EXEC_TESTS_CMD}") - message(STATUS "${GCOVR_HTML_EXEC_TESTS_CMD_SPACED}") + string(REPLACE ";" " " GCOVR_EXEC_TESTS_CMD_SPACED "${GCOVR_EXEC_TESTS_CMD}") + message(STATUS "${GCOVR_EXEC_TESTS_CMD_SPACED}") - message(STATUS "Command to create a folder: ") - string(REPLACE ";" " " GCOVR_HTML_FOLDER_CMD_SPACED "${GCOVR_HTML_FOLDER_CMD}") - message(STATUS "${GCOVR_HTML_FOLDER_CMD_SPACED}") + if(NOT GCOVR_FOLDER_CMD STREQUAL "echo") + message(STATUS "Command to create a folder: ") + string(REPLACE ";" " " GCOVR_FOLDER_CMD_SPACED "${GCOVR_FOLDER_CMD}") + message(STATUS "${GCOVR_FOLDER_CMD_SPACED}") + endif() - message(STATUS "Command to generate gcovr HTML coverage data: ") - string(REPLACE ";" " " GCOVR_HTML_CMD_SPACED "${GCOVR_HTML_CMD}") - message(STATUS "${GCOVR_HTML_CMD_SPACED}") + message(STATUS "Command to generate gcovr coverage data: ") + string(REPLACE ";" " " GCOVR_CMD_SPACED "${GCOVR_CMD}") + message(STATUS "${GCOVR_CMD_SPACED}") endif() add_custom_target(${Coverage_NAME} - COMMAND ${GCOVR_HTML_EXEC_TESTS_CMD} - COMMAND ${GCOVR_HTML_FOLDER_CMD} - COMMAND ${GCOVR_HTML_CMD} + COMMAND ${GCOVR_EXEC_TESTS_CMD} + COMMAND ${GCOVR_FOLDER_CMD} + COMMAND ${GCOVR_CMD} - BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory + BYPRODUCTS ${GCOVR_OUTPUT_FILE} WORKING_DIRECTORY ${PROJECT_BINARY_DIR} DEPENDS ${Coverage_DEPENDENCIES} VERBATIM # Protect arguments to commands - COMMENT "Running gcovr to produce HTML code coverage report." + COMMENT "Running gcovr to produce code coverage report." ) # Show info where to find the report add_custom_command(TARGET ${Coverage_NAME} POST_BUILD COMMAND ; - COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." + COMMENT "Code coverage report saved in ${GCOVR_OUTPUT_FILE} formatted as ${Coverage_FORMAT}" ) - -endfunction() # setup_target_for_coverage_gcovr_html +endfunction() # setup_target_for_coverage_gcovr function(append_coverage_compiler_flags) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) diff --git a/Builds/CMake/RippledCov.cmake b/Builds/CMake/RippledCov.cmake index f7e1e29748a..0723f14109f 100644 --- a/Builds/CMake/RippledCov.cmake +++ b/Builds/CMake/RippledCov.cmake @@ -11,10 +11,17 @@ if (coverage) set(TEST_PARALLELISM ${PROCESSOR_COUNT}) endif() - set (GCOVR_ADDITIONAL_ARGS --exclude-noncode-lines --exclude-unreachable-branches -j ${PROCESSOR_COUNT} -s) + if (DEFINED CODE_COVERAGE_REPORT_FORMAT) + set(CODE_COVERAGE_FORMAT ${CODE_COVERAGE_REPORT_FORMAT}) + else() + set(CODE_COVERAGE_FORMAT html-details) + endif() + + set (GCOVR_ADDITIONAL_ARGS --exclude-throw-branches --exclude-noncode-lines --exclude-unreachable-branches -s) - setup_target_for_coverage_gcovr_html( + setup_target_for_coverage_gcovr( NAME coverage_report + FORMAT ${CODE_COVERAGE_FORMAT} EXECUTABLE rippled EXECUTABLE_ARGS -u --unittest-jobs ${TEST_PARALLELISM} --quiet --unittest-log EXCLUDE "src/test" "${CMAKE_BINARY_DIR}/proto_gen" "${CMAKE_BINARY_DIR}/proto_gen_grpc" From db7fcd8c90da6d2309eeb31800e0de766ffa6707 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Thu, 14 Dec 2023 21:45:20 +0000 Subject: [PATCH 08/23] Add codecov step to coverage workflow --- .github/workflows/nix.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 93a737ddfdf..03d80d9d5d7 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -219,3 +219,11 @@ jobs: name: coverage-report.xml path: .build/coverage_report.xml retention-days: 30 + - name: upload coverage report + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + with: + files: .build/coverage_report.xml + fail_ci_if_error: true + verbose: true From 1a2d7aa5e0f0410b08713028d83de12a77d004fc Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Thu, 14 Dec 2023 22:16:10 +0000 Subject: [PATCH 09/23] Rewrite codecov.yml --- .codecov.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.codecov.yml b/.codecov.yml index b2bc67814e3..3baf7eb96cf 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,5 +1,6 @@ - -codecov: - ci: - - !appveyor - - travis +coverage: + status: + project: + default: + target: 70% + threshold: 2% From 0dc34dcfd4b5ac4032dc43bf57c635f8c6d5c6c3 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Fri, 15 Dec 2023 12:17:32 +0000 Subject: [PATCH 10/23] Switch to rippleci/rippled-build-ubuntu --- .codecov.yml | 2 +- .github/actions/build/action.yml | 10 ++++++++-- .github/workflows/nix.yml | 16 +++++++--------- Builds/CMake/CodeCoverage.cmake | 5 +---- Builds/CMake/RippledCov.cmake | 5 ++++- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/.codecov.yml b/.codecov.yml index 3baf7eb96cf..191144aae16 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -2,5 +2,5 @@ coverage: status: project: default: - target: 70% + target: 60% threshold: 2% diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 6c74afc1f2f..7a6d58ef822 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -8,6 +8,8 @@ inputs: default: null cmake-target: default: all + output: + default: null # An implicit input is the environment variable `build_dir`. runs: using: composite @@ -15,14 +17,18 @@ runs: - name: configure shell: bash run: | - cd ${build_dir} + pushd ${build_dir} cmake \ ${{ inputs.generator && format('-G "{0}"', inputs.generator) || '' }} \ -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \ -DCMAKE_BUILD_TYPE=${{ inputs.configuration }} \ - -DCODE_COVERAGE_GCOV_TOOL=/usr/bin/gcov \ ${{ inputs.cmake-args }} \ .. + popd + [[ -n "${{ inputs.output }}" ]] \ + && [[ -e "${build_dir}/${{ inputs.output }}" ]] \ + && mv "${build_dir}/${{ inputs.output }}" ./ \ + || echo "Output ignored" - name: build shell: bash run: | diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 03d80d9d5d7..17776884b89 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -49,7 +49,7 @@ jobs: cc: /usr/bin/clang-14 cxx: /usr/bin/clang++-14 runs-on: [self-hosted, heavy] - container: thejohnfreeman/rippled-build-ubuntu:12e19cd9034b + container: rippleci/rippled-build-ubuntu:aaf5e3e env: build_dir: .build steps: @@ -125,7 +125,7 @@ jobs: - "-Dunity=ON" needs: dependencies runs-on: [self-hosted, heavy] - container: thejohnfreeman/rippled-build-ubuntu:12e19cd9034b + container: rippleci/rippled-build-ubuntu:aaf5e3e env: build_dir: .build steps: @@ -173,7 +173,7 @@ jobs: - Debug needs: dependencies runs-on: [self-hosted, heavy] - container: thejohnfreeman/rippled-build-ubuntu:12e19cd9034b + container: rippleci/rippled-build-ubuntu:aaf5e3e env: build_dir: .build steps: @@ -185,9 +185,6 @@ jobs: run: | mkdir -p ~/.conan tar -xzf conan.tar -C ~/.conan - - name: install gcovr - run: | - pip install 'gcovr<7' - name: check environment run: | echo ${PATH} | tr ':' '\n' @@ -213,17 +210,18 @@ jobs: -DCMAKE_CXX_FLAGS="-O0" -DCMAKE_C_FLAGS="-O0" cmake-target: coverage_report - - name: archive coverage results + output: coverage_report.xml + - name: archive coverage reports uses: actions/upload-artifact@v3 with: name: coverage-report.xml - path: .build/coverage_report.xml + path: coverage_report.xml retention-days: 30 - name: upload coverage report uses: codecov/codecov-action@v3 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: - files: .build/coverage_report.xml + files: coverage_report.xml fail_ci_if_error: true verbose: true diff --git a/Builds/CMake/CodeCoverage.cmake b/Builds/CMake/CodeCoverage.cmake index 9c013bccab6..52f95faa4ed 100644 --- a/Builds/CMake/CodeCoverage.cmake +++ b/Builds/CMake/CodeCoverage.cmake @@ -260,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+) # ) diff --git a/Builds/CMake/RippledCov.cmake b/Builds/CMake/RippledCov.cmake index 0723f14109f..79f5d1c4852 100644 --- a/Builds/CMake/RippledCov.cmake +++ b/Builds/CMake/RippledCov.cmake @@ -17,7 +17,10 @@ if (coverage) set(CODE_COVERAGE_FORMAT html-details) endif() - set (GCOVR_ADDITIONAL_ARGS --exclude-throw-branches --exclude-noncode-lines --exclude-unreachable-branches -s) + set (GCOVR_ADDITIONAL_ARGS + --exclude-throw-branches + --exclude-noncode-lines + --exclude-unreachable-branches -s ) setup_target_for_coverage_gcovr( NAME coverage_report From f61b23121f1f9e63460d236dfeab095f8ab2202b Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Fri, 15 Dec 2023 13:05:56 +0000 Subject: [PATCH 11/23] Move coverage option to cmake, update BUILD.md --- .github/actions/dependencies/action.yml | 3 -- .github/workflows/nix.yml | 2 +- BUILD.md | 51 ++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/.github/actions/dependencies/action.yml b/.github/actions/dependencies/action.yml index 2c6679ee4b2..3147e8774f2 100644 --- a/.github/actions/dependencies/action.yml +++ b/.github/actions/dependencies/action.yml @@ -2,8 +2,6 @@ name: dependencies inputs: configuration: required: true - coverage: - default: "False" # An implicit input is the environment variable `build_dir`. runs: using: composite @@ -25,5 +23,4 @@ runs: --output-folder . \ --build missing \ --settings build_type=${{ inputs.configuration }} \ - --options coverage=${{ inputs.coverage }} \ .. diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 17776884b89..d12d3e8729f 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -199,7 +199,6 @@ jobs: uses: ./.github/actions/dependencies with: configuration: ${{ matrix.configuration }} - coverage: "True" - name: build uses: ./.github/actions/build with: @@ -209,6 +208,7 @@ jobs: -DCODE_COVERAGE_REPORT_FORMAT=xml -DCMAKE_CXX_FLAGS="-O0" -DCMAKE_C_FLAGS="-O0" + -Dcoverage=ON cmake-target: coverage_report output: coverage_report.xml - name: archive coverage reports diff --git a/BUILD.md b/BUILD.md index 21341ae9a71..4d63759cd8b 100644 --- a/BUILD.md +++ b/BUILD.md @@ -262,17 +262,55 @@ It patches their CMake to correctly import its dependencies. generator. Pass `--help` to see the rest of the command line options. +### Coverage reports + +Coverage reports are an additional feature intended for compilers GCC and Clang +(including Apple Clang). They are generated by the build target `coverage_report`, +which is only enabled when `coverage` option is set, e.g. with +`--options coverage=True` in `conan` or `-Dcoverage=ON` in `cmake` + +Prerequisites for coverage reports are: + +- [gcovr tool][5] (can be installed e.g. with pip) +- `gcov` for GCC (installed by default) or +- `llvm-cov` for Clang (installed by default) + +Coverage reports require: + +- `rippled` built with instrumentation data, which are enabled by the `coverage` + option mentioned above +- completed run of unit tests, which populates coverage capture data +- completed run of `gcovr` tool (which internally invokes either `gcov` or `llvm-cov`) + to assemble both instrumentation data and coverage data into a single report + +All of the above steps are automated into a single target `coverage_report` +but the user can also invoke them separately. The instrumented `rippled` binary can +be used for regular development work, at the cost of extra disk space utilisation +and a small performance hit (to store coverage capture). + +The default coverage report format is Cobertura XML (used in CI), but the user +can override it to any of the formats listed in `Builds/CMake/CodeCoverage.cmake` +by setting `CODE_COVERAGE_REPORT_FORMAT` either as an environment variable, +or as `cmake` option. + +After `coverage_report` target is completed, the generated coverage report +can be found inside the build directory, named as `coverage_report`, with added +suitable extension for the report format, or as a directory for `html-details` +report format. + + ## Options | Option | Default Value | Description | | --- | ---| ---| | `assert` | OFF | Enable assertions. | `reporting` | OFF | Build the reporting mode feature. | +| `coverage` | OFF | Prepare the coverage report. | | `tests` | ON | Build tests. | | `unity` | ON | Configure a unity build. | | `san` | N/A | Enable a sanitizer with Clang. Choices are `thread` and `address`. | -[Unity builds][5] may be faster for the first build +[Unity builds][6] may be faster for the first build (at the cost of much more memory) since they concatenate sources into fewer translation units. Non-unity builds may be faster for incremental builds, and can be helpful for detecting `#include` omissions. @@ -311,8 +349,8 @@ conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_HAS_STD_INVOKE_R ### call to 'async_teardown' is ambiguous If you are compiling with an early version of Clang 16, then you might hit -a [regression][6] when compiling C++20 that manifests as an [error in a Boost -header][7]. You can workaround it by adding this preprocessor definition: +a [regression][7] when compiling C++20 that manifests as an [error in a Boost +header][8]. You can workaround it by adding this preprocessor definition: ``` conan profile update 'env.CXXFLAGS="-DBOOST_ASIO_DISABLE_CONCEPTS"' default @@ -359,9 +397,10 @@ If you want to experiment with a new package, follow these steps: [1]: https://github.com/conan-io/conan-center-index/issues/13168 [2]: https://en.cppreference.com/w/cpp/compiler_support/20 [3]: https://docs.conan.io/en/latest/getting_started.html -[5]: https://en.wikipedia.org/wiki/Unity_build -[6]: https://github.com/boostorg/beast/issues/2648 -[7]: https://github.com/boostorg/beast/issues/2661 +[5]: https://gcovr.com/en/stable/getting-started.html +[6]: https://en.wikipedia.org/wiki/Unity_build +[7]: https://github.com/boostorg/beast/issues/2648 +[8]: https://github.com/boostorg/beast/issues/2661 [build_type]: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html [runtime]: https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html [toolchain]: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html From 2068b3e19fa44f1eda5529d2ba8845db03f232f3 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Fri, 15 Dec 2023 13:43:48 +0000 Subject: [PATCH 12/23] Fix artifact upload --- .github/actions/build/action.yml | 13 ++++++------- .github/workflows/nix.yml | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 7a6d58ef822..1687824c5f3 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -8,7 +8,7 @@ inputs: default: null cmake-target: default: all - output: + artifact: default: null # An implicit input is the environment variable `build_dir`. runs: @@ -17,18 +17,13 @@ runs: - name: configure shell: bash run: | - pushd ${build_dir} + cd ${build_dir} cmake \ ${{ inputs.generator && format('-G "{0}"', inputs.generator) || '' }} \ -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \ -DCMAKE_BUILD_TYPE=${{ inputs.configuration }} \ ${{ inputs.cmake-args }} \ .. - popd - [[ -n "${{ inputs.output }}" ]] \ - && [[ -e "${build_dir}/${{ inputs.output }}" ]] \ - && mv "${build_dir}/${{ inputs.output }}" ./ \ - || echo "Output ignored" - name: build shell: bash run: | @@ -37,3 +32,7 @@ runs: --config ${{ inputs.configuration }} \ --parallel ${NUM_PROCESSORS:-$(nproc)} \ --target ${{ inputs.cmake-target }} + [[ -n "${{ inputs.artifact }}" ]] \ + && [[ -e "${build_dir}/${{ inputs.artifact }}" ]] \ + && mv "${build_dir}/${{ inputs.artifact }}" ./ \ + || echo diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index d12d3e8729f..8d1fa3c809e 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -210,8 +210,8 @@ jobs: -DCMAKE_C_FLAGS="-O0" -Dcoverage=ON cmake-target: coverage_report - output: coverage_report.xml - - name: archive coverage reports + artifact: coverage_report.xml + - name: archive coverage report uses: actions/upload-artifact@v3 with: name: coverage-report.xml From 8dacf4fd8c2093caf4cc0548c036329ccd1212d3 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Fri, 15 Dec 2023 15:20:12 +0000 Subject: [PATCH 13/23] Add CODE_COVERAGE_EXTRA_ARGS , update BUILD.md --- BUILD.md | 64 +++++++++++++++++++++++------------ Builds/CMake/RippledCov.cmake | 9 ++++- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/BUILD.md b/BUILD.md index 4d63759cd8b..b6dc4e11713 100644 --- a/BUILD.md +++ b/BUILD.md @@ -262,36 +262,55 @@ It patches their CMake to correctly import its dependencies. generator. Pass `--help` to see the rest of the command line options. -### Coverage reports -Coverage reports are an additional feature intended for compilers GCC and Clang -(including Apple Clang). They are generated by the build target `coverage_report`, +### Coverage report + +Coverage report is an additional feature intended for compilers GCC and Clang +(including Apple Clang). It is generated by the build target `coverage_report`, which is only enabled when `coverage` option is set, e.g. with `--options coverage=True` in `conan` or `-Dcoverage=ON` in `cmake` -Prerequisites for coverage reports are: +Prerequisites for coverage report are: -- [gcovr tool][5] (can be installed e.g. with pip) -- `gcov` for GCC (installed by default) or -- `llvm-cov` for Clang (installed by default) +- [gcovr tool][5] (can be installed e.g. with [pip][6]) +- `gcov` for GCC (installed with compiler by default) or +- `llvm-cov` for Clang (installed with compiler by default) +- `Debug` build type -Coverage reports require: +Coverage report is created when the following steps are completed, in order: -- `rippled` built with instrumentation data, which are enabled by the `coverage` - option mentioned above -- completed run of unit tests, which populates coverage capture data -- completed run of `gcovr` tool (which internally invokes either `gcov` or `llvm-cov`) - to assemble both instrumentation data and coverage data into a single report +1. `rippled` binary built with instrumentation data, enabled by the `coverage` + option mentioned above +2. completed run of unit tests, which populates coverage capture data +3. completed run of `gcovr` tool (which internally invokes either `gcov` or `llvm-cov`) + to assemble both instrumentation data and coverage capture data into a single report All of the above steps are automated into a single target `coverage_report` but the user can also invoke them separately. The instrumented `rippled` binary can be used for regular development work, at the cost of extra disk space utilisation -and a small performance hit (to store coverage capture). +and a small performance hit (to store coverage capture). In case of a spurious failure +of unit tests, it is possile to re-run `coverage_report` target without rebuilding +the `rippled` binary (since it is simply a dependency of the coverage report). The default coverage report format is Cobertura XML (used in CI), but the user can override it to any of the formats listed in `Builds/CMake/CodeCoverage.cmake` -by setting `CODE_COVERAGE_REPORT_FORMAT` either as an environment variable, -or as `cmake` option. +by setting `CODE_COVERAGE_REPORT_FORMAT` option in `cmake`, +or as `cmake` option. It is also possible to generate more than one format at a time +by setting `CODE_COVERAGE_EXTRA_ARGS` option in `cmake`. + +The code coverage tool by default runs parallel unit tests with `--unittest-jobs` +set to the number of available CPU cores. This may cause spurious test errors on Apple. +User can override unit test parallelism with `CODE_COVERAGE_TEST_PARALLELISM` +option in `cmake`. + +Example: + +``` +cd .build +conan install .. --output-folder . --build missing --settings build_type=Debug +cmake -DCMAKE_BUILD_TYPE=Debug -Dcoverage=ON -DCODE_COVERAGE_REPORT_FORMAT=html-details -DCODE_COVERAGE_EXTRA_ARGS="--json coverage_report.json --json-pretty" -DCODE_COVERAGE_TEST_PARALLELISM=2 -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake .. +cmake --build . --target coverage_report +``` After `coverage_report` target is completed, the generated coverage report can be found inside the build directory, named as `coverage_report`, with added @@ -310,7 +329,7 @@ report format. | `unity` | ON | Configure a unity build. | | `san` | N/A | Enable a sanitizer with Clang. Choices are `thread` and `address`. | -[Unity builds][6] may be faster for the first build +[Unity builds][7] may be faster for the first build (at the cost of much more memory) since they concatenate sources into fewer translation units. Non-unity builds may be faster for incremental builds, and can be helpful for detecting `#include` omissions. @@ -349,8 +368,8 @@ conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_HAS_STD_INVOKE_R ### call to 'async_teardown' is ambiguous If you are compiling with an early version of Clang 16, then you might hit -a [regression][7] when compiling C++20 that manifests as an [error in a Boost -header][8]. You can workaround it by adding this preprocessor definition: +a [regression][8] when compiling C++20 that manifests as an [error in a Boost +header][9]. You can workaround it by adding this preprocessor definition: ``` conan profile update 'env.CXXFLAGS="-DBOOST_ASIO_DISABLE_CONCEPTS"' default @@ -398,9 +417,10 @@ If you want to experiment with a new package, follow these steps: [2]: https://en.cppreference.com/w/cpp/compiler_support/20 [3]: https://docs.conan.io/en/latest/getting_started.html [5]: https://gcovr.com/en/stable/getting-started.html -[6]: https://en.wikipedia.org/wiki/Unity_build -[7]: https://github.com/boostorg/beast/issues/2648 -[8]: https://github.com/boostorg/beast/issues/2661 +[6]: https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/ +[7]: https://en.wikipedia.org/wiki/Unity_build +[8]: https://github.com/boostorg/beast/issues/2648 +[9]: https://github.com/boostorg/beast/issues/2661 [build_type]: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html [runtime]: https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html [toolchain]: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html diff --git a/Builds/CMake/RippledCov.cmake b/Builds/CMake/RippledCov.cmake index 79f5d1c4852..7a43989db01 100644 --- a/Builds/CMake/RippledCov.cmake +++ b/Builds/CMake/RippledCov.cmake @@ -17,7 +17,14 @@ if (coverage) set(CODE_COVERAGE_FORMAT html-details) endif() - set (GCOVR_ADDITIONAL_ARGS + if (DEFINED CODE_COVERAGE_EXTRA_ARGS) + set(GCOVR_ADDITIONAL_ARGS ${CODE_COVERAGE_EXTRA_ARGS}) + separate_arguments(GCOVR_ADDITIONAL_ARGS) + else() + set(GCOVR_ADDITIONAL_ARGS "") + endif() + + list (APPEND GCOVR_ADDITIONAL_ARGS --exclude-throw-branches --exclude-noncode-lines --exclude-unreachable-branches -s ) From 3699211a0a88387746c88945d38e069bd68731c6 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Fri, 15 Dec 2023 18:02:17 +0000 Subject: [PATCH 14/23] Change how we use CODECOV_TOKEN --- .github/workflows/nix.yml | 3 +-- BUILD.md | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 8d1fa3c809e..bca2c49e0fa 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -219,9 +219,8 @@ jobs: retention-days: 30 - name: upload coverage report uses: codecov/codecov-action@v3 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: files: coverage_report.xml fail_ci_if_error: true verbose: true + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/BUILD.md b/BUILD.md index b6dc4e11713..6d703be27cb 100644 --- a/BUILD.md +++ b/BUILD.md @@ -262,7 +262,6 @@ It patches their CMake to correctly import its dependencies. generator. Pass `--help` to see the rest of the command line options. - ### Coverage report Coverage report is an additional feature intended for compilers GCC and Clang From 94b441fe2c7ec973ff2273234791f8325e038297 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Fri, 15 Dec 2023 21:07:01 +0000 Subject: [PATCH 15/23] Update BUILD.md --- BUILD.md | 58 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/BUILD.md b/BUILD.md index 6d703be27cb..611d8f41545 100644 --- a/BUILD.md +++ b/BUILD.md @@ -262,18 +262,18 @@ It patches their CMake to correctly import its dependencies. generator. Pass `--help` to see the rest of the command line options. -### Coverage report +## Coverage report -Coverage report is an additional feature intended for compilers GCC and Clang -(including Apple Clang). It is generated by the build target `coverage_report`, +Coverage report is intended for the developers using compilers GCC +or Clang (including Apple Clang). It is generated by the build target `coverage_report`, which is only enabled when `coverage` option is set, e.g. with -`--options coverage=True` in `conan` or `-Dcoverage=ON` in `cmake` +`--options coverage=True` in `conan` or `-Dcoverage=ON` variable in `cmake` -Prerequisites for coverage report are: +Prerequisites for the coverage report: - [gcovr tool][5] (can be installed e.g. with [pip][6]) -- `gcov` for GCC (installed with compiler by default) or -- `llvm-cov` for Clang (installed with compiler by default) +- `gcov` for GCC (installed with the compiler by default) or +- `llvm-cov` for Clang (installed with the compiler by default) - `Debug` build type Coverage report is created when the following steps are completed, in order: @@ -282,39 +282,41 @@ Coverage report is created when the following steps are completed, in order: option mentioned above 2. completed run of unit tests, which populates coverage capture data 3. completed run of `gcovr` tool (which internally invokes either `gcov` or `llvm-cov`) - to assemble both instrumentation data and coverage capture data into a single report + to assemble both instrumentation data and coverage capture data into a coverage report -All of the above steps are automated into a single target `coverage_report` -but the user can also invoke them separately. The instrumented `rippled` binary can -be used for regular development work, at the cost of extra disk space utilisation -and a small performance hit (to store coverage capture). In case of a spurious failure -of unit tests, it is possile to re-run `coverage_report` target without rebuilding -the `rippled` binary (since it is simply a dependency of the coverage report). +Above steps are automated into a single target `coverage_report`. The instrumented +`rippled` binary can be also used for regular development or testing work, at +the cost of extra disk space utilisation and a small performance hit +(to store coverage capture). In case of a spurious failure of unit tests, it is +possile to re-run `coverage_report` target without rebuilding the `rippled` binary +(since it is simply a dependency of the coverage report target). -The default coverage report format is Cobertura XML (used in CI), but the user +The default coverage report format is `html-details`, but the user can override it to any of the formats listed in `Builds/CMake/CodeCoverage.cmake` -by setting `CODE_COVERAGE_REPORT_FORMAT` option in `cmake`, -or as `cmake` option. It is also possible to generate more than one format at a time -by setting `CODE_COVERAGE_EXTRA_ARGS` option in `cmake`. +by setting `CODE_COVERAGE_REPORT_FORMAT` variable in `cmake`. It is also possible +to generate more than one format at a time by setting `CODE_COVERAGE_EXTRA_ARGS` +variable in `cmake`. The specific command line used to run the `gcovr` tool will be +displayed if `CODE_COVERAGE_VERBOSE` variable is set. -The code coverage tool by default runs parallel unit tests with `--unittest-jobs` -set to the number of available CPU cores. This may cause spurious test errors on Apple. -User can override unit test parallelism with `CODE_COVERAGE_TEST_PARALLELISM` -option in `cmake`. +By default, the code coverage tool runs parallel unit tests with `--unittest-jobs` + set to the number of available CPU cores. This may cause spurious test +errors on Apple. Developers can override the number of unit test jobs with +`CODE_COVERAGE_TEST_PARALLELISM` variable in `cmake`. -Example: +Example use with all cmake variables set: ``` cd .build conan install .. --output-folder . --build missing --settings build_type=Debug -cmake -DCMAKE_BUILD_TYPE=Debug -Dcoverage=ON -DCODE_COVERAGE_REPORT_FORMAT=html-details -DCODE_COVERAGE_EXTRA_ARGS="--json coverage_report.json --json-pretty" -DCODE_COVERAGE_TEST_PARALLELISM=2 -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake .. +cmake -DCMAKE_BUILD_TYPE=Debug -Dcoverage=ON -DCODE_COVERAGE_REPORT_FORMAT=html-details -DCODE_COVERAGE_EXTRA_ARGS="--json coverage_report.json --json-pretty --txt coverage_report.txt" -DCODE_COVERAGE_VERBOSE=ON -DCODE_COVERAGE_TEST_PARALLELISM=2 -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake .. cmake --build . --target coverage_report ``` -After `coverage_report` target is completed, the generated coverage report -can be found inside the build directory, named as `coverage_report`, with added -suitable extension for the report format, or as a directory for `html-details` -report format. +After `coverage_report` target is completed, the generated coverage report will be +stored inside the build directory, as either of: + +- file named `coverage_report.*`, with a suitable extension for the report format, or +- directory named `coverage_report`, with `index.html` and other files inside, for `html-details` or `html-nested` report formats. ## Options From 36481f4a3798fc0db8d9f67db3670d3fa5251497 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Thu, 4 Jan 2024 12:02:41 +0000 Subject: [PATCH 16/23] Cleanup workflow and cmake files, remove coverage_core_only --- .github/actions/build/action.yml | 7 +++---- .github/workflows/nix.yml | 5 +++-- BUILD.md | 30 ++++++++++++++++-------------- Builds/CMake/RippledCov.cmake | 24 ++++-------------------- Builds/CMake/RippledSettings.cmake | 12 ++++++++---- CMakeLists.txt | 9 +++++---- 6 files changed, 39 insertions(+), 48 deletions(-) diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 1687824c5f3..896ef2082db 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -32,7 +32,6 @@ runs: --config ${{ inputs.configuration }} \ --parallel ${NUM_PROCESSORS:-$(nproc)} \ --target ${{ inputs.cmake-target }} - [[ -n "${{ inputs.artifact }}" ]] \ - && [[ -e "${build_dir}/${{ inputs.artifact }}" ]] \ - && mv "${build_dir}/${{ inputs.artifact }}" ./ \ - || echo + if [[ -n "${{ inputs.artifact }}" ]]; then \ + mv "${build_dir}/${{ inputs.artifact }}" ./ ;\ + fi diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index bca2c49e0fa..a5af7c05c94 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -205,10 +205,11 @@ jobs: generator: Ninja configuration: ${{ matrix.configuration }} cmake-args: >- - -DCODE_COVERAGE_REPORT_FORMAT=xml + -Dcoverage=ON + -Dcoverage_format=xml + -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_CXX_FLAGS="-O0" -DCMAKE_C_FLAGS="-O0" - -Dcoverage=ON cmake-target: coverage_report artifact: coverage_report.xml - name: archive coverage report diff --git a/BUILD.md b/BUILD.md index 611d8f41545..6631c78b1b3 100644 --- a/BUILD.md +++ b/BUILD.md @@ -271,7 +271,7 @@ which is only enabled when `coverage` option is set, e.g. with Prerequisites for the coverage report: -- [gcovr tool][5] (can be installed e.g. with [pip][6]) +- [gcovr tool][8] (can be installed e.g. with [pip][9]) - `gcov` for GCC (installed with the compiler by default) or - `llvm-cov` for Clang (installed with the compiler by default) - `Debug` build type @@ -289,26 +289,28 @@ Above steps are automated into a single target `coverage_report`. The instrument the cost of extra disk space utilisation and a small performance hit (to store coverage capture). In case of a spurious failure of unit tests, it is possile to re-run `coverage_report` target without rebuilding the `rippled` binary -(since it is simply a dependency of the coverage report target). +(since it is simply a dependency of the coverage report target). It is also possible +to select only specific tests for the purpose of coverage report, by setting `coverage_test` +variable in `cmake` The default coverage report format is `html-details`, but the user can override it to any of the formats listed in `Builds/CMake/CodeCoverage.cmake` -by setting `CODE_COVERAGE_REPORT_FORMAT` variable in `cmake`. It is also possible -to generate more than one format at a time by setting `CODE_COVERAGE_EXTRA_ARGS` +by setting `coverage_format` variable in `cmake`. It is also possible +to generate more than one format at a time by setting `coverage_extra_args` variable in `cmake`. The specific command line used to run the `gcovr` tool will be displayed if `CODE_COVERAGE_VERBOSE` variable is set. By default, the code coverage tool runs parallel unit tests with `--unittest-jobs` set to the number of available CPU cores. This may cause spurious test errors on Apple. Developers can override the number of unit test jobs with -`CODE_COVERAGE_TEST_PARALLELISM` variable in `cmake`. +`coverage_test_parallelism` variable in `cmake`. Example use with all cmake variables set: ``` cd .build conan install .. --output-folder . --build missing --settings build_type=Debug -cmake -DCMAKE_BUILD_TYPE=Debug -Dcoverage=ON -DCODE_COVERAGE_REPORT_FORMAT=html-details -DCODE_COVERAGE_EXTRA_ARGS="--json coverage_report.json --json-pretty --txt coverage_report.txt" -DCODE_COVERAGE_VERBOSE=ON -DCODE_COVERAGE_TEST_PARALLELISM=2 -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake .. +cmake -DCMAKE_BUILD_TYPE=Debug -Dcoverage=ON -Dcoverage_test=JSONRPC -Dcoverage_test_parallelism=1 -Dcoverage_format=html-details -Dcoverage_extra_args="--json coverage_report.json --json-pretty --txt coverage_report.txt" -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake .. cmake --build . --target coverage_report ``` @@ -330,7 +332,7 @@ stored inside the build directory, as either of: | `unity` | ON | Configure a unity build. | | `san` | N/A | Enable a sanitizer with Clang. Choices are `thread` and `address`. | -[Unity builds][7] may be faster for the first build +[Unity builds][5] may be faster for the first build (at the cost of much more memory) since they concatenate sources into fewer translation units. Non-unity builds may be faster for incremental builds, and can be helpful for detecting `#include` omissions. @@ -369,8 +371,8 @@ conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_HAS_STD_INVOKE_R ### call to 'async_teardown' is ambiguous If you are compiling with an early version of Clang 16, then you might hit -a [regression][8] when compiling C++20 that manifests as an [error in a Boost -header][9]. You can workaround it by adding this preprocessor definition: +a [regression][6] when compiling C++20 that manifests as an [error in a Boost +header][7]. You can workaround it by adding this preprocessor definition: ``` conan profile update 'env.CXXFLAGS="-DBOOST_ASIO_DISABLE_CONCEPTS"' default @@ -417,11 +419,11 @@ If you want to experiment with a new package, follow these steps: [1]: https://github.com/conan-io/conan-center-index/issues/13168 [2]: https://en.cppreference.com/w/cpp/compiler_support/20 [3]: https://docs.conan.io/en/latest/getting_started.html -[5]: https://gcovr.com/en/stable/getting-started.html -[6]: https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/ -[7]: https://en.wikipedia.org/wiki/Unity_build -[8]: https://github.com/boostorg/beast/issues/2648 -[9]: https://github.com/boostorg/beast/issues/2661 +[5]: https://en.wikipedia.org/wiki/Unity_build +[6]: https://github.com/boostorg/beast/issues/2648 +[7]: https://github.com/boostorg/beast/issues/2661 +[8]: https://gcovr.com/en/stable/getting-started.html +[9]: https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/ [build_type]: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html [runtime]: https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html [toolchain]: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html diff --git a/Builds/CMake/RippledCov.cmake b/Builds/CMake/RippledCov.cmake index 7a43989db01..c1f42ed4e7f 100644 --- a/Builds/CMake/RippledCov.cmake +++ b/Builds/CMake/RippledCov.cmake @@ -2,26 +2,10 @@ coverage report target #]===================================================================] -ProcessorCount(PROCESSOR_COUNT) - if (coverage) - if (DEFINED CODE_COVERAGE_TEST_PARALLELISM) - set(TEST_PARALLELISM ${CODE_COVERAGE_TEST_PARALLELISM}) - else() - set(TEST_PARALLELISM ${PROCESSOR_COUNT}) - endif() - - if (DEFINED CODE_COVERAGE_REPORT_FORMAT) - set(CODE_COVERAGE_FORMAT ${CODE_COVERAGE_REPORT_FORMAT}) - else() - set(CODE_COVERAGE_FORMAT html-details) - endif() - - if (DEFINED CODE_COVERAGE_EXTRA_ARGS) - set(GCOVR_ADDITIONAL_ARGS ${CODE_COVERAGE_EXTRA_ARGS}) + set(GCOVR_ADDITIONAL_ARGS ${coverage_extra_args}) + if (NOT GCOVR_ADDITIONAL_ARGS STREQUAL "") separate_arguments(GCOVR_ADDITIONAL_ARGS) - else() - set(GCOVR_ADDITIONAL_ARGS "") endif() list (APPEND GCOVR_ADDITIONAL_ARGS @@ -31,9 +15,9 @@ if (coverage) setup_target_for_coverage_gcovr( NAME coverage_report - FORMAT ${CODE_COVERAGE_FORMAT} + FORMAT ${coverage_format} EXECUTABLE rippled - EXECUTABLE_ARGS -u --unittest-jobs ${TEST_PARALLELISM} --quiet --unittest-log + EXECUTABLE_ARGS --unittest$<$:=${coverage_test}> --unittest-jobs ${coverage_test_parallelism} --quiet --unittest-log EXCLUDE "src/test" "${CMAKE_BINARY_DIR}/proto_gen" "${CMAKE_BINARY_DIR}/proto_gen_grpc" DEPENDENCIES rippled ) diff --git a/Builds/CMake/RippledSettings.cmake b/Builds/CMake/RippledSettings.cmake index c8195c7b922..1a50b7366ff 100644 --- a/Builds/CMake/RippledSettings.cmake +++ b/Builds/CMake/RippledSettings.cmake @@ -2,6 +2,8 @@ declare user options/settings #]===================================================================] +ProcessorCount(PROCESSOR_COUNT) + option (assert "Enables asserts, even in release builds" OFF) option (reporting "Build rippled with reporting mode enabled" OFF) @@ -17,15 +19,17 @@ endif () if (is_gcc OR is_clang) option (coverage "Generates coverage info." OFF) option (profile "Add profiling flags" OFF) + set (coverage_test_parallelism "${PROCESSOR_COUNT}" CACHE STRING + "Unit tests parallelism for the purpose of coverage report.") + set (coverage_format "html-details" CACHE STRING + "Output format of the coverage report.") + set (coverage_extra_args "" CACHE STRING + "Additional arguments to pass to gcovr.") set (coverage_test "" CACHE STRING "On gcc & clang, the specific unit test(s) to run for coverage. Default is all tests.") if (coverage_test AND NOT coverage) set (coverage ON CACHE BOOL "gcc/clang only" FORCE) endif () - option (coverage_core_only - "Include only src/ripple files when generating coverage report. \ - Set to OFF to include all sources in coverage report." - ON) option (wextra "compile with extra gcc/clang warnings enabled" ON) else () set (profile OFF CACHE BOOL "gcc/clang only" FORCE) diff --git a/CMakeLists.txt b/CMakeLists.txt index d87f5a5603d..bc03e0b182b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,10 +29,6 @@ if(Git_FOUND) endif() #git include (ProcessorCount) -if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - include (CodeCoverage) - include (RippledCov) -endif() if(thread_safety_analysis) add_compile_options(-Wthread-safety -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -DRIPPLE_ENABLE_THREAD_SAFETY_ANNOTATIONS) @@ -131,6 +127,11 @@ if(reporting) ) endif() +if (coverage) + include (CodeCoverage) + include (RippledCov) +endif() + ### include(RippledCore) From b2c923ab1cf70a0a833cd6d6a0d078470f50afd9 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Thu, 4 Jan 2024 14:56:27 +0000 Subject: [PATCH 17/23] Update BUILD.md --- BUILD.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/BUILD.md b/BUILD.md index 6631c78b1b3..a996dca9af2 100644 --- a/BUILD.md +++ b/BUILD.md @@ -271,7 +271,7 @@ which is only enabled when `coverage` option is set, e.g. with Prerequisites for the coverage report: -- [gcovr tool][8] (can be installed e.g. with [pip][9]) +- [gcovr tool][gcovr] (can be installed e.g. with [pip][python-pip]) - `gcov` for GCC (installed with the compiler by default) or - `llvm-cov` for Clang (installed with the compiler by default) - `Debug` build type @@ -305,12 +305,12 @@ By default, the code coverage tool runs parallel unit tests with `--unittest-job errors on Apple. Developers can override the number of unit test jobs with `coverage_test_parallelism` variable in `cmake`. -Example use with all cmake variables set: +Example use with cmake variables set: ``` cd .build conan install .. --output-folder . --build missing --settings build_type=Debug -cmake -DCMAKE_BUILD_TYPE=Debug -Dcoverage=ON -Dcoverage_test=JSONRPC -Dcoverage_test_parallelism=1 -Dcoverage_format=html-details -Dcoverage_extra_args="--json coverage_report.json --json-pretty --txt coverage_report.txt" -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake .. +cmake -DCMAKE_BUILD_TYPE=Debug -Dcoverage=ON -Dcoverage_test_parallelism=2 -Dcoverage_format=html-details -Dcoverage_extra_args="--json coverage_report.json" -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake .. cmake --build . --target coverage_report ``` @@ -422,8 +422,8 @@ If you want to experiment with a new package, follow these steps: [5]: https://en.wikipedia.org/wiki/Unity_build [6]: https://github.com/boostorg/beast/issues/2648 [7]: https://github.com/boostorg/beast/issues/2661 -[8]: https://gcovr.com/en/stable/getting-started.html -[9]: https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/ +[gcovr]: https://gcovr.com/en/stable/getting-started.html +[python-pip]: https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/ [build_type]: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html [runtime]: https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html [toolchain]: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html From 2918c8a08149d2dab8455528aaebb005d53fe94b Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Thu, 4 Jan 2024 18:48:48 +0000 Subject: [PATCH 18/23] More minor cleanup --- .github/actions/build/action.yml | 5 ---- .github/workflows/nix.yml | 13 +++++---- BUILD.md | 44 +++++++++++++++--------------- Builds/CMake/CodeCoverage.cmake | 14 +++++----- Builds/CMake/RippledCov.cmake | 40 +++++++++++++++------------ Builds/CMake/RippledSanity.cmake | 2 ++ Builds/CMake/RippledSettings.cmake | 2 ++ CMakeLists.txt | 8 ++---- bin/ci/ubuntu/build-and-test.sh | 2 +- 9 files changed, 68 insertions(+), 62 deletions(-) diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 896ef2082db..79bbe9af075 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -8,8 +8,6 @@ inputs: default: null cmake-target: default: all - artifact: - default: null # An implicit input is the environment variable `build_dir`. runs: using: composite @@ -32,6 +30,3 @@ runs: --config ${{ inputs.configuration }} \ --parallel ${NUM_PROCESSORS:-$(nproc)} \ --target ${{ inputs.cmake-target }} - if [[ -n "${{ inputs.artifact }}" ]]; then \ - mv "${build_dir}/${{ inputs.artifact }}" ./ ;\ - fi diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index a5af7c05c94..02fcc742b6c 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -210,18 +210,21 @@ jobs: -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_CXX_FLAGS="-O0" -DCMAKE_C_FLAGS="-O0" - cmake-target: coverage_report - artifact: coverage_report.xml + cmake-target: coverage + - name: build + shell: bash + run: | + mv "${build_dir}/coverage.xml" ./ - name: archive coverage report uses: actions/upload-artifact@v3 with: - name: coverage-report.xml - path: coverage_report.xml + name: coverage.xml + path: coverage.xml retention-days: 30 - name: upload coverage report uses: codecov/codecov-action@v3 with: - files: coverage_report.xml + files: coverage.xml fail_ci_if_error: true verbose: true token: ${{ secrets.CODECOV_TOKEN }} diff --git a/BUILD.md b/BUILD.md index a996dca9af2..5217e0947b8 100644 --- a/BUILD.md +++ b/BUILD.md @@ -264,9 +264,9 @@ It patches their CMake to correctly import its dependencies. ## Coverage report -Coverage report is intended for the developers using compilers GCC -or Clang (including Apple Clang). It is generated by the build target `coverage_report`, -which is only enabled when `coverage` option is set, e.g. with +The coverage report is intended for developers using compilers GCC +or Clang (including Apple Clang). It is generated by the build target `coverage`, +which is only enabled when the `coverage` option is set, e.g. with `--options coverage=True` in `conan` or `-Dcoverage=ON` variable in `cmake` Prerequisites for the coverage report: @@ -276,49 +276,49 @@ Prerequisites for the coverage report: - `llvm-cov` for Clang (installed with the compiler by default) - `Debug` build type -Coverage report is created when the following steps are completed, in order: +A coverage report is created when the following steps are completed, in order: 1. `rippled` binary built with instrumentation data, enabled by the `coverage` option mentioned above 2. completed run of unit tests, which populates coverage capture data -3. completed run of `gcovr` tool (which internally invokes either `gcov` or `llvm-cov`) - to assemble both instrumentation data and coverage capture data into a coverage report +3. completed run of the `gcovr` tool (which internally invokes either `gcov` or `llvm-cov`) + to assemble both instrumentation data and the coverage capture data into a coverage report -Above steps are automated into a single target `coverage_report`. The instrumented -`rippled` binary can be also used for regular development or testing work, at -the cost of extra disk space utilisation and a small performance hit +The above steps are automated into a single target `coverage`. The instrumented +`rippled` binary can also be used for regular development or testing work, at +the cost of extra disk space utilization and a small performance hit (to store coverage capture). In case of a spurious failure of unit tests, it is -possile to re-run `coverage_report` target without rebuilding the `rippled` binary +possible to re-run the `coverage` target without rebuilding the `rippled` binary (since it is simply a dependency of the coverage report target). It is also possible -to select only specific tests for the purpose of coverage report, by setting `coverage_test` -variable in `cmake` +to select only specific tests for the purpose of the coverage report, by setting +the `coverage_test` variable in `cmake` The default coverage report format is `html-details`, but the user can override it to any of the formats listed in `Builds/CMake/CodeCoverage.cmake` -by setting `coverage_format` variable in `cmake`. It is also possible -to generate more than one format at a time by setting `coverage_extra_args` +by setting the `coverage_format` variable in `cmake`. It is also possible +to generate more than one format at a time by setting the `coverage_extra_args` variable in `cmake`. The specific command line used to run the `gcovr` tool will be -displayed if `CODE_COVERAGE_VERBOSE` variable is set. +displayed if the `CODE_COVERAGE_VERBOSE` variable is set. By default, the code coverage tool runs parallel unit tests with `--unittest-jobs` set to the number of available CPU cores. This may cause spurious test errors on Apple. Developers can override the number of unit test jobs with -`coverage_test_parallelism` variable in `cmake`. +the `coverage_test_parallelism` variable in `cmake`. -Example use with cmake variables set: +Example use with some cmake variables set: ``` cd .build conan install .. --output-folder . --build missing --settings build_type=Debug -cmake -DCMAKE_BUILD_TYPE=Debug -Dcoverage=ON -Dcoverage_test_parallelism=2 -Dcoverage_format=html-details -Dcoverage_extra_args="--json coverage_report.json" -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake .. -cmake --build . --target coverage_report +cmake -DCMAKE_BUILD_TYPE=Debug -Dcoverage=ON -Dcoverage_test_parallelism=2 -Dcoverage_format=html-details -Dcoverage_extra_args="--json coverage.json" -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake .. +cmake --build . --target coverage ``` -After `coverage_report` target is completed, the generated coverage report will be +After the `coverage` target is completed, the generated coverage report will be stored inside the build directory, as either of: -- file named `coverage_report.*`, with a suitable extension for the report format, or -- directory named `coverage_report`, with `index.html` and other files inside, for `html-details` or `html-nested` report formats. +- file named `coverage.`_extension_ , with a suitable extension for the report format, or +- directory named `coverage`, with the `index.html` and other files inside, for the `html-details` or `html-nested` report formats. ## Options diff --git a/Builds/CMake/CodeCoverage.cmake b/Builds/CMake/CodeCoverage.cmake index 52f95faa4ed..d2af481d8a3 100644 --- a/Builds/CMake/CodeCoverage.cmake +++ b/Builds/CMake/CodeCoverage.cmake @@ -87,12 +87,12 @@ # - fix append_coverage_compiler_flags_to_target to correctly add flags # - replace "-fprofile-arcs -ftest-coverage" with "--coverage" (equivalent) # -# 2023-12-15, Bronek Kozicki +# 2024-01-04, 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 +# - replace both functions setup_target_for_coverage_gcovr_* with a single setup_target_for_coverage_gcovr # - add support for all gcovr output formats # # USAGE: @@ -159,12 +159,12 @@ option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE) # Check prereqs find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) -if (DEFINED CODE_COVERAGE_GCOV_TOOL) +if(DEFINED CODE_COVERAGE_GCOV_TOOL) set(GCOV_TOOL "${CODE_COVERAGE_GCOV_TOOL}") -elseif (DEFINED ENV{CODE_COVERAGE_GCOV_TOOL}) +elseif(DEFINED ENV{CODE_COVERAGE_GCOV_TOOL}) set(GCOV_TOOL "$ENV{CODE_COVERAGE_GCOV_TOOL}") elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") - if (APPLE) + if(APPLE) execute_process( COMMAND xcrun -f llvm-cov OUTPUT_VARIABLE LLVMCOV_PATH OUTPUT_STRIP_TRAILING_WHITESPACE @@ -175,7 +175,7 @@ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") if(LLVMCOV_PATH) set(GCOV_TOOL "${LLVMCOV_PATH} gcov") endif() -elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") +elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") find_program( GCOV_PATH gcov ) set(GCOV_TOOL "${GCOV_PATH}") endif() @@ -313,7 +313,7 @@ function(setup_target_for_coverage_gcovr) endif() endif() - if ((Coverage_FORMAT STREQUAL "cobertura") + 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 ) diff --git a/Builds/CMake/RippledCov.cmake b/Builds/CMake/RippledCov.cmake index c1f42ed4e7f..cca509672e3 100644 --- a/Builds/CMake/RippledCov.cmake +++ b/Builds/CMake/RippledCov.cmake @@ -2,23 +2,29 @@ coverage report target #]===================================================================] -if (coverage) - set(GCOVR_ADDITIONAL_ARGS ${coverage_extra_args}) - if (NOT GCOVR_ADDITIONAL_ARGS STREQUAL "") - separate_arguments(GCOVR_ADDITIONAL_ARGS) - endif() +if(NOT coverage) + message(FATAL_ERROR "Code coverage not enabled! Aborting ...") +endif() - list (APPEND GCOVR_ADDITIONAL_ARGS - --exclude-throw-branches - --exclude-noncode-lines - --exclude-unreachable-branches -s ) +# The instructions for these commands come from the `CodeCoverage` module, +# which was copied from https://github.com/bilke/cmake-modules, commit fb7d2a3, +# then locally changed (see CHANGES: section in `CodeCoverage.cmake`) - setup_target_for_coverage_gcovr( - NAME coverage_report - FORMAT ${coverage_format} - EXECUTABLE rippled - EXECUTABLE_ARGS --unittest$<$:=${coverage_test}> --unittest-jobs ${coverage_test_parallelism} --quiet --unittest-log - EXCLUDE "src/test" "${CMAKE_BINARY_DIR}/proto_gen" "${CMAKE_BINARY_DIR}/proto_gen_grpc" - DEPENDENCIES rippled - ) +set(GCOVR_ADDITIONAL_ARGS ${coverage_extra_args}) +if(NOT GCOVR_ADDITIONAL_ARGS STREQUAL "") + separate_arguments(GCOVR_ADDITIONAL_ARGS) endif() + +list(APPEND GCOVR_ADDITIONAL_ARGS + --exclude-throw-branches + --exclude-noncode-lines + --exclude-unreachable-branches -s) + +setup_target_for_coverage_gcovr( + NAME coverage + FORMAT ${coverage_format} + EXECUTABLE rippled + EXECUTABLE_ARGS --unittest$<$:=${coverage_test}> --unittest-jobs ${coverage_test_parallelism} --quiet --unittest-log + EXCLUDE "src/test" "${CMAKE_BINARY_DIR}/proto_gen" "${CMAKE_BINARY_DIR}/proto_gen_grpc" + DEPENDENCIES rippled +) diff --git a/Builds/CMake/RippledSanity.cmake b/Builds/CMake/RippledSanity.cmake index 1d217196e75..3dd5fb782fd 100644 --- a/Builds/CMake/RippledSanity.cmake +++ b/Builds/CMake/RippledSanity.cmake @@ -2,6 +2,8 @@ convenience variables and sanity checks #]===================================================================] +include(ProcessorCount) + if (NOT ep_procs) ProcessorCount(ep_procs) if (ep_procs GREATER 1) diff --git a/Builds/CMake/RippledSettings.cmake b/Builds/CMake/RippledSettings.cmake index 1a50b7366ff..d2ac2dc1838 100644 --- a/Builds/CMake/RippledSettings.cmake +++ b/Builds/CMake/RippledSettings.cmake @@ -2,6 +2,8 @@ declare user options/settings #]===================================================================] +include(ProcessorCount) + ProcessorCount(PROCESSOR_COUNT) option (assert "Enables asserts, even in release builds" OFF) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc03e0b182b..efd9e864645 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,8 +28,6 @@ if(Git_FOUND) endif() endif() #git -include (ProcessorCount) - if(thread_safety_analysis) add_compile_options(-Wthread-safety -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -DRIPPLE_ENABLE_THREAD_SAFETY_ANNOTATIONS) add_compile_options("-stdlib=libc++") @@ -127,9 +125,9 @@ if(reporting) ) endif() -if (coverage) - include (CodeCoverage) - include (RippledCov) +if(coverage) + include(CodeCoverage) + include(RippledCov) endif() ### diff --git a/bin/ci/ubuntu/build-and-test.sh b/bin/ci/ubuntu/build-and-test.sh index 7ae75f2b16a..2c1734863fb 100755 --- a/bin/ci/ubuntu/build-and-test.sh +++ b/bin/ci/ubuntu/build-and-test.sh @@ -44,7 +44,7 @@ if [[ ${NINJA_BUILD:-} == true ]]; then fi coverage=false -if [[ "${TARGET}" == "coverage_report" ]] ; then +if [[ "${TARGET}" == "coverage" ]] ; then echo "coverage option detected." coverage=true fi From c91416dcaac533299f799b55b0c4c2871fcd2693 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Thu, 4 Jan 2024 19:37:26 +0000 Subject: [PATCH 19/23] Set gcovr parallelism --- Builds/CMake/RippledCov.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Builds/CMake/RippledCov.cmake b/Builds/CMake/RippledCov.cmake index cca509672e3..e0027de426c 100644 --- a/Builds/CMake/RippledCov.cmake +++ b/Builds/CMake/RippledCov.cmake @@ -18,7 +18,8 @@ endif() list(APPEND GCOVR_ADDITIONAL_ARGS --exclude-throw-branches --exclude-noncode-lines - --exclude-unreachable-branches -s) + --exclude-unreachable-branches -s + -j ${coverage_test_parallelism}) setup_target_for_coverage_gcovr( NAME coverage From 6d9624ce0c83023df2a611de0504e34e6871e3b8 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Fri, 19 Jan 2024 11:46:07 +0000 Subject: [PATCH 20/23] Do not enable coverage target on Windows --- Builds/CMake/RippledCov.cmake | 44 +++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/Builds/CMake/RippledCov.cmake b/Builds/CMake/RippledCov.cmake index e0027de426c..bcd581a660b 100644 --- a/Builds/CMake/RippledCov.cmake +++ b/Builds/CMake/RippledCov.cmake @@ -6,26 +6,30 @@ if(NOT coverage) message(FATAL_ERROR "Code coverage not enabled! Aborting ...") endif() -# The instructions for these commands come from the `CodeCoverage` module, -# which was copied from https://github.com/bilke/cmake-modules, commit fb7d2a3, -# then locally changed (see CHANGES: section in `CodeCoverage.cmake`) +if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + message(WARNING "Code coverage on Windows is not supported, ignoring 'coverage' flag") +else() + # The instructions for these commands come from the `CodeCoverage` module, + # which was copied from https://github.com/bilke/cmake-modules, commit fb7d2a3, + # then locally changed (see CHANGES: section in `CodeCoverage.cmake`) -set(GCOVR_ADDITIONAL_ARGS ${coverage_extra_args}) -if(NOT GCOVR_ADDITIONAL_ARGS STREQUAL "") - separate_arguments(GCOVR_ADDITIONAL_ARGS) -endif() + set(GCOVR_ADDITIONAL_ARGS ${coverage_extra_args}) + if(NOT GCOVR_ADDITIONAL_ARGS STREQUAL "") + separate_arguments(GCOVR_ADDITIONAL_ARGS) + endif() -list(APPEND GCOVR_ADDITIONAL_ARGS - --exclude-throw-branches - --exclude-noncode-lines - --exclude-unreachable-branches -s - -j ${coverage_test_parallelism}) + list(APPEND GCOVR_ADDITIONAL_ARGS + --exclude-throw-branches + --exclude-noncode-lines + --exclude-unreachable-branches -s + -j ${coverage_test_parallelism}) -setup_target_for_coverage_gcovr( - NAME coverage - FORMAT ${coverage_format} - EXECUTABLE rippled - EXECUTABLE_ARGS --unittest$<$:=${coverage_test}> --unittest-jobs ${coverage_test_parallelism} --quiet --unittest-log - EXCLUDE "src/test" "${CMAKE_BINARY_DIR}/proto_gen" "${CMAKE_BINARY_DIR}/proto_gen_grpc" - DEPENDENCIES rippled -) + setup_target_for_coverage_gcovr( + NAME coverage + FORMAT ${coverage_format} + EXECUTABLE rippled + EXECUTABLE_ARGS --unittest$<$:=${coverage_test}> --unittest-jobs ${coverage_test_parallelism} --quiet --unittest-log + EXCLUDE "src/test" "${CMAKE_BINARY_DIR}/proto_gen" "${CMAKE_BINARY_DIR}/proto_gen_grpc" + DEPENDENCIES rippled + ) +endif() From 28a26d78fee0e54ea071d0d072a178ce7b1720cb Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Mon, 22 Jan 2024 18:56:10 +0000 Subject: [PATCH 21/23] Move include(CodeCoverage) --- Builds/CMake/RippledCov.cmake | 2 ++ CMakeLists.txt | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Builds/CMake/RippledCov.cmake b/Builds/CMake/RippledCov.cmake index bcd581a660b..50f87c70230 100644 --- a/Builds/CMake/RippledCov.cmake +++ b/Builds/CMake/RippledCov.cmake @@ -9,6 +9,8 @@ endif() if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") message(WARNING "Code coverage on Windows is not supported, ignoring 'coverage' flag") else() + include(CodeCoverage) + # The instructions for these commands come from the `CodeCoverage` module, # which was copied from https://github.com/bilke/cmake-modules, commit fb7d2a3, # then locally changed (see CHANGES: section in `CodeCoverage.cmake`) diff --git a/CMakeLists.txt b/CMakeLists.txt index efd9e864645..d324008ac40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,7 +126,6 @@ if(reporting) endif() if(coverage) - include(CodeCoverage) include(RippledCov) endif() From edbe54b9ffd17277f5c152b85f02119bcc99e1d1 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Mon, 22 Jan 2024 19:01:25 +0000 Subject: [PATCH 22/23] Reformat RippledSettings.cmake --- Builds/CMake/RippledSettings.cmake | 176 ++++++++++++++--------------- 1 file changed, 88 insertions(+), 88 deletions(-) diff --git a/Builds/CMake/RippledSettings.cmake b/Builds/CMake/RippledSettings.cmake index d2ac2dc1838..fae09cc5d3f 100644 --- a/Builds/CMake/RippledSettings.cmake +++ b/Builds/CMake/RippledSettings.cmake @@ -6,125 +6,125 @@ include(ProcessorCount) ProcessorCount(PROCESSOR_COUNT) -option (assert "Enables asserts, even in release builds" OFF) +option(assert "Enables asserts, even in release builds" OFF) -option (reporting "Build rippled with reporting mode enabled" OFF) +option(reporting "Build rippled with reporting mode enabled" OFF) -option (tests "Build tests" ON) +option(tests "Build tests" ON) -option (unity "Creates a build using UNITY support in cmake. This is the default" ON) -if (unity) - if (NOT is_ci) - set (CMAKE_UNITY_BUILD_BATCH_SIZE 15 CACHE STRING "") - endif () -endif () -if (is_gcc OR is_clang) - option (coverage "Generates coverage info." OFF) - option (profile "Add profiling flags" OFF) - set (coverage_test_parallelism "${PROCESSOR_COUNT}" CACHE STRING +option(unity "Creates a build using UNITY support in cmake. This is the default" ON) +if(unity) + if(NOT is_ci) + set(CMAKE_UNITY_BUILD_BATCH_SIZE 15 CACHE STRING "") + endif() +endif() +if(is_gcc OR is_clang) + option(coverage "Generates coverage info." OFF) + option(profile "Add profiling flags" OFF) + set(coverage_test_parallelism "${PROCESSOR_COUNT}" CACHE STRING "Unit tests parallelism for the purpose of coverage report.") - set (coverage_format "html-details" CACHE STRING + set(coverage_format "html-details" CACHE STRING "Output format of the coverage report.") - set (coverage_extra_args "" CACHE STRING + set(coverage_extra_args "" CACHE STRING "Additional arguments to pass to gcovr.") - set (coverage_test "" CACHE STRING + set(coverage_test "" CACHE STRING "On gcc & clang, the specific unit test(s) to run for coverage. Default is all tests.") - if (coverage_test AND NOT coverage) - set (coverage ON CACHE BOOL "gcc/clang only" FORCE) - endif () - option (wextra "compile with extra gcc/clang warnings enabled" ON) -else () - set (profile OFF CACHE BOOL "gcc/clang only" FORCE) - set (coverage OFF CACHE BOOL "gcc/clang only" FORCE) - set (wextra OFF CACHE BOOL "gcc/clang only" FORCE) -endif () -if (is_linux) - option (BUILD_SHARED_LIBS "build shared ripple libraries" OFF) - option (static "link protobuf, openssl, libc++, and boost statically" ON) - option (perf "Enables flags that assist with perf recording" OFF) - option (use_gold "enables detection of gold (binutils) linker" ON) - option (use_mold "enables detection of mold (binutils) linker" ON) -else () + if(coverage_test AND NOT coverage) + set(coverage ON CACHE BOOL "gcc/clang only" FORCE) + endif() + option(wextra "compile with extra gcc/clang warnings enabled" ON) +else() + set(profile OFF CACHE BOOL "gcc/clang only" FORCE) + set(coverage OFF CACHE BOOL "gcc/clang only" FORCE) + set(wextra OFF CACHE BOOL "gcc/clang only" FORCE) +endif() +if(is_linux) + option(BUILD_SHARED_LIBS "build shared ripple libraries" OFF) + option(static "link protobuf, openssl, libc++, and boost statically" ON) + option(perf "Enables flags that assist with perf recording" OFF) + option(use_gold "enables detection of gold (binutils) linker" ON) + option(use_mold "enables detection of mold (binutils) linker" ON) +else() # we are not ready to allow shared-libs on windows because it would require # export declarations. On macos it's more feasible, but static openssl # produces odd linker errors, thus we disable shared lib builds for now. - set (BUILD_SHARED_LIBS OFF CACHE BOOL "build shared ripple libraries - OFF for win/macos" FORCE) - set (static ON CACHE BOOL "static link, linux only. ON for WIN/macos" FORCE) - set (perf OFF CACHE BOOL "perf flags, linux only" FORCE) - set (use_gold OFF CACHE BOOL "gold linker, linux only" FORCE) - set (use_mold OFF CACHE BOOL "mold linker, linux only" FORCE) -endif () -if (is_clang) - option (use_lld "enables detection of lld linker" ON) -else () - set (use_lld OFF CACHE BOOL "try lld linker, clang only" FORCE) -endif () -option (jemalloc "Enables jemalloc for heap profiling" OFF) -option (werr "treat warnings as errors" OFF) -option (local_protobuf + set(BUILD_SHARED_LIBS OFF CACHE BOOL "build shared ripple libraries - OFF for win/macos" FORCE) + set(static ON CACHE BOOL "static link, linux only. ON for WIN/macos" FORCE) + set(perf OFF CACHE BOOL "perf flags, linux only" FORCE) + set(use_gold OFF CACHE BOOL "gold linker, linux only" FORCE) + set(use_mold OFF CACHE BOOL "mold linker, linux only" FORCE) +endif() +if(is_clang) + option(use_lld "enables detection of lld linker" ON) +else() + set(use_lld OFF CACHE BOOL "try lld linker, clang only" FORCE) +endif() +option(jemalloc "Enables jemalloc for heap profiling" OFF) +option(werr "treat warnings as errors" OFF) +option(local_protobuf "Force a local build of protobuf instead of looking for an installed version." OFF) -option (local_grpc +option(local_grpc "Force a local build of gRPC instead of looking for an installed version." OFF) # this one is a string and therefore can't be an option -set (san "" CACHE STRING "On gcc & clang, add sanitizer instrumentation") -set_property (CACHE san PROPERTY STRINGS ";undefined;memory;address;thread") -if (san) - string (TOLOWER ${san} san) - set (SAN_FLAG "-fsanitize=${san}") - set (SAN_LIB "") - if (is_gcc) - if (san STREQUAL "address") - set (SAN_LIB "asan") - elseif (san STREQUAL "thread") - set (SAN_LIB "tsan") - elseif (san STREQUAL "memory") - set (SAN_LIB "msan") - elseif (san STREQUAL "undefined") - set (SAN_LIB "ubsan") - endif () - endif () - set (_saved_CRL ${CMAKE_REQUIRED_LIBRARIES}) - set (CMAKE_REQUIRED_LIBRARIES "${SAN_FLAG};${SAN_LIB}") - check_cxx_compiler_flag (${SAN_FLAG} COMPILER_SUPPORTS_SAN) - set (CMAKE_REQUIRED_LIBRARIES ${_saved_CRL}) - if (NOT COMPILER_SUPPORTS_SAN) - message (FATAL_ERROR "${san} sanitizer does not seem to be supported by your compiler") - endif () -endif () -set (container_label "" CACHE STRING "tag to use for package building containers") -option (packages_only +set(san "" CACHE STRING "On gcc & clang, add sanitizer instrumentation") +set_property(CACHE san PROPERTY STRINGS ";undefined;memory;address;thread") +if(san) + string(TOLOWER ${san} san) + set(SAN_FLAG "-fsanitize=${san}") + set(SAN_LIB "") + if(is_gcc) + if(san STREQUAL "address") + set(SAN_LIB "asan") + elseif(san STREQUAL "thread") + set(SAN_LIB "tsan") + elseif(san STREQUAL "memory") + set(SAN_LIB "msan") + elseif(san STREQUAL "undefined") + set(SAN_LIB "ubsan") + endif() + endif() + set(_saved_CRL ${CMAKE_REQUIRED_LIBRARIES}) + set(CMAKE_REQUIRED_LIBRARIES "${SAN_FLAG};${SAN_LIB}") + check_cxx_compiler_flag(${SAN_FLAG} COMPILER_SUPPORTS_SAN) + set(CMAKE_REQUIRED_LIBRARIES ${_saved_CRL}) + if(NOT COMPILER_SUPPORTS_SAN) + message(FATAL_ERROR "${san} sanitizer does not seem to be supported by your compiler") + endif() +endif() +set(container_label "" CACHE STRING "tag to use for package building containers") +option(packages_only "ONLY generate package building targets. This is special use-case and almost \ certainly not what you want. Use with caution as you won't be able to build \ any compiled targets locally." OFF) -option (have_package_container +option(have_package_container "Sometimes you already have the tagged container you want to use for package \ building and you don't want docker to rebuild it. This flag will detach the \ dependency of the package build from the container build. It's an advanced \ use case and most likely you should not be touching this flag." OFF) # the remaining options are obscure and rarely used -option (beast_no_unit_test_inline +option(beast_no_unit_test_inline "Prevents unit test definitions from being inserted into global table" OFF) -option (single_io_service_thread +option(single_io_service_thread "Restricts the number of threads calling io_service::run to one. \ This can be useful when debugging." OFF) -option (boost_show_deprecated +option(boost_show_deprecated "Allow boost to fail on deprecated usage. Only useful if you're trying\ to find deprecated calls." OFF) -option (beast_hashers +option(beast_hashers "Use local implementations for sha/ripemd hashes (experimental, not recommended)" OFF) -if (WIN32) - option (beast_disable_autolink "Disables autolinking of system libraries on WIN32" OFF) -else () - set (beast_disable_autolink OFF CACHE BOOL "WIN32 only" FORCE) -endif () -if (coverage) - message (STATUS "coverage build requested - forcing Debug build") - set (CMAKE_BUILD_TYPE Debug CACHE STRING "build type" FORCE) -endif () +if(WIN32) + option(beast_disable_autolink "Disables autolinking of system libraries on WIN32" OFF) +else() + set(beast_disable_autolink OFF CACHE BOOL "WIN32 only" FORCE) +endif() +if(coverage) + message(STATUS "coverage build requested - forcing Debug build") + set(CMAKE_BUILD_TYPE Debug CACHE STRING "build type" FORCE) +endif() From 2450117db03779bba4857ffd07e645c0b4ac553d Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Mon, 22 Jan 2024 19:15:11 +0000 Subject: [PATCH 23/23] Minor CMake --- Builds/CMake/RippledCov.cmake | 47 ++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/Builds/CMake/RippledCov.cmake b/Builds/CMake/RippledCov.cmake index 50f87c70230..ce7536e8eeb 100644 --- a/Builds/CMake/RippledCov.cmake +++ b/Builds/CMake/RippledCov.cmake @@ -8,30 +8,31 @@ endif() if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") message(WARNING "Code coverage on Windows is not supported, ignoring 'coverage' flag") -else() - include(CodeCoverage) - - # The instructions for these commands come from the `CodeCoverage` module, - # which was copied from https://github.com/bilke/cmake-modules, commit fb7d2a3, - # then locally changed (see CHANGES: section in `CodeCoverage.cmake`) + return() +endif() - set(GCOVR_ADDITIONAL_ARGS ${coverage_extra_args}) - if(NOT GCOVR_ADDITIONAL_ARGS STREQUAL "") - separate_arguments(GCOVR_ADDITIONAL_ARGS) - endif() +include(CodeCoverage) - list(APPEND GCOVR_ADDITIONAL_ARGS - --exclude-throw-branches - --exclude-noncode-lines - --exclude-unreachable-branches -s - -j ${coverage_test_parallelism}) +# The instructions for these commands come from the `CodeCoverage` module, +# which was copied from https://github.com/bilke/cmake-modules, commit fb7d2a3, +# then locally changed (see CHANGES: section in `CodeCoverage.cmake`) - setup_target_for_coverage_gcovr( - NAME coverage - FORMAT ${coverage_format} - EXECUTABLE rippled - EXECUTABLE_ARGS --unittest$<$:=${coverage_test}> --unittest-jobs ${coverage_test_parallelism} --quiet --unittest-log - EXCLUDE "src/test" "${CMAKE_BINARY_DIR}/proto_gen" "${CMAKE_BINARY_DIR}/proto_gen_grpc" - DEPENDENCIES rippled - ) +set(GCOVR_ADDITIONAL_ARGS ${coverage_extra_args}) +if(NOT GCOVR_ADDITIONAL_ARGS STREQUAL "") + separate_arguments(GCOVR_ADDITIONAL_ARGS) endif() + +list(APPEND GCOVR_ADDITIONAL_ARGS + --exclude-throw-branches + --exclude-noncode-lines + --exclude-unreachable-branches -s + -j ${coverage_test_parallelism}) + +setup_target_for_coverage_gcovr( + NAME coverage + FORMAT ${coverage_format} + EXECUTABLE rippled + EXECUTABLE_ARGS --unittest$<$:=${coverage_test}> --unittest-jobs ${coverage_test_parallelism} --quiet --unittest-log + EXCLUDE "src/test" "${CMAKE_BINARY_DIR}/proto_gen" "${CMAKE_BINARY_DIR}/proto_gen_grpc" + DEPENDENCIES rippled +)