diff --git a/.github/scripts/strategy-matrix/generate.py b/.github/scripts/strategy-matrix/generate.py index 79530a1d757..c3d2da1f9fb 100755 --- a/.github/scripts/strategy-matrix/generate.py +++ b/.github/scripts/strategy-matrix/generate.py @@ -232,6 +232,8 @@ def generate_strategy_matrix(all: bool, config: Config) -> list: f"-{architecture['platform'][architecture['platform'].find('/') + 1 :]}" ) config_name += f"-{build_type.lower()}" + if "-Dcoverage=ON" in cmake_args: + config_name += "-coverage" if "-Dunity=ON" in cmake_args: config_name += "-unity" diff --git a/.github/scripts/strategy-matrix/linux.json b/.github/scripts/strategy-matrix/linux.json index 748ee031c97..331f4e33f6c 100644 --- a/.github/scripts/strategy-matrix/linux.json +++ b/.github/scripts/strategy-matrix/linux.json @@ -15,196 +15,196 @@ "distro_version": "bookworm", "compiler_name": "gcc", "compiler_version": "12", - "image_sha": "0525eae" + "image_sha": "ca4517d" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "gcc", "compiler_version": "13", - "image_sha": "0525eae" + "image_sha": "ca4517d" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "gcc", "compiler_version": "14", - "image_sha": "0525eae" + "image_sha": "ca4517d" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "gcc", "compiler_version": "15", - "image_sha": "0525eae" + "image_sha": "ca4517d" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "clang", "compiler_version": "16", - "image_sha": "0525eae" + "image_sha": "ca4517d" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "clang", "compiler_version": "17", - "image_sha": "0525eae" + "image_sha": "ca4517d" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "clang", "compiler_version": "18", - "image_sha": "0525eae" + "image_sha": "ca4517d" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "clang", "compiler_version": "19", - "image_sha": "0525eae" + "image_sha": "ca4517d" }, { "distro_name": "debian", "distro_version": "bookworm", "compiler_name": "clang", "compiler_version": "20", - "image_sha": "0525eae" + "image_sha": "ca4517d" }, { "distro_name": "debian", "distro_version": "trixie", "compiler_name": "gcc", "compiler_version": "14", - "image_sha": "0525eae" + "image_sha": "ca4517d" }, { "distro_name": "debian", "distro_version": "trixie", "compiler_name": "gcc", "compiler_version": "15", - "image_sha": "0525eae" + "image_sha": "ca4517d" }, { "distro_name": "debian", "distro_version": "trixie", "compiler_name": "clang", "compiler_version": "20", - "image_sha": "0525eae" + "image_sha": "ca4517d" }, { "distro_name": "debian", "distro_version": "trixie", "compiler_name": "clang", "compiler_version": "21", - "image_sha": "0525eae" + "image_sha": "ca4517d" }, { "distro_name": "rhel", "distro_version": "8", "compiler_name": "gcc", "compiler_version": "14", - "image_sha": "e1782cd" + "image_sha": "ca4517d" }, { "distro_name": "rhel", "distro_version": "8", "compiler_name": "clang", "compiler_version": "any", - "image_sha": "e1782cd" + "image_sha": "ca4517d" }, { "distro_name": "rhel", "distro_version": "9", "compiler_name": "gcc", "compiler_version": "12", - "image_sha": "e1782cd" + "image_sha": "ca4517d" }, { "distro_name": "rhel", "distro_version": "9", "compiler_name": "gcc", "compiler_version": "13", - "image_sha": "e1782cd" + "image_sha": "ca4517d" }, { "distro_name": "rhel", "distro_version": "9", "compiler_name": "gcc", "compiler_version": "14", - "image_sha": "e1782cd" + "image_sha": "ca4517d" }, { "distro_name": "rhel", "distro_version": "9", "compiler_name": "clang", "compiler_version": "any", - "image_sha": "e1782cd" + "image_sha": "ca4517d" }, { "distro_name": "rhel", "distro_version": "10", "compiler_name": "gcc", "compiler_version": "14", - "image_sha": "e1782cd" + "image_sha": "ca4517d" }, { "distro_name": "rhel", "distro_version": "10", "compiler_name": "clang", "compiler_version": "any", - "image_sha": "e1782cd" + "image_sha": "ca4517d" }, { "distro_name": "ubuntu", "distro_version": "jammy", "compiler_name": "gcc", "compiler_version": "12", - "image_sha": "e1782cd" + "image_sha": "ca4517d" }, { "distro_name": "ubuntu", "distro_version": "noble", "compiler_name": "gcc", "compiler_version": "13", - "image_sha": "e1782cd" + "image_sha": "ca4517d" }, { "distro_name": "ubuntu", "distro_version": "noble", "compiler_name": "gcc", "compiler_version": "14", - "image_sha": "e1782cd" + "image_sha": "ca4517d" }, { "distro_name": "ubuntu", "distro_version": "noble", "compiler_name": "clang", "compiler_version": "16", - "image_sha": "e1782cd" + "image_sha": "ca4517d" }, { "distro_name": "ubuntu", "distro_version": "noble", "compiler_name": "clang", "compiler_version": "17", - "image_sha": "e1782cd" + "image_sha": "ca4517d" }, { "distro_name": "ubuntu", "distro_version": "noble", "compiler_name": "clang", "compiler_version": "18", - "image_sha": "e1782cd" + "image_sha": "ca4517d" }, { "distro_name": "ubuntu", "distro_version": "noble", "compiler_name": "clang", "compiler_version": "19", - "image_sha": "e1782cd" + "image_sha": "ca4517d" } ], "build_type": ["Debug", "Release"], diff --git a/.github/workflows/reusable-build-test-config.yml b/.github/workflows/reusable-build-test-config.yml index 43acfab5421..b5db436ee42 100644 --- a/.github/workflows/reusable-build-test-config.yml +++ b/.github/workflows/reusable-build-test-config.yml @@ -66,8 +66,31 @@ jobs: container: ${{ inputs.image != '' && inputs.image || null }} timeout-minutes: 60 env: - ENABLED_VOIDSTAR: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }} - ENABLED_COVERAGE: ${{ contains(inputs.cmake_args, '-Dcoverage=ON') }} + # Enable ccache only for PR commits, merge_group, most pushes, and + # scheduled builds in the XRPLF organization. We do not enable ccache for + # PRs from forks as they do not have access to our remote cache storage. + # We further do not enable ccache for push events to the master or a + # release branch, to protect against the rare case that the output + # produced by ccache is not identical to a regular compilation. + CCACHE_ENABLED: ${{ github.repository_owner == 'XRPLF' && (github.event_name == 'pull_request' || github.event_name == 'merge_group' || ( github.event_name == 'push' && !(github.base_ref == 'master' || startsWith(github.base_ref, 'release'))) || github.event_name == 'schedule') }} + # Use a namespace to keep the objects separate for each configuration. + CCACHE_NAMESPACE: ${{ inputs.config_name }} + # Ccache supports both Redis and HTTP endpoints. + # * For Redis, use the following format: redis://ip:port, see + # https://github.com/ccache/ccache/wiki/Redis-storage. Note that TLS is + # not directly supported by ccache, and requires use of a proxy. + # * For HTTP use the following format: http://ip:port/cache when using + # nginx as backend or http://ip:port|layout=bazel when using Bazel + # Remote Cache, see https://github.com/ccache/ccache/wiki/HTTP-storage. + # Note that HTTPS is not directly supported by ccache. + CCACHE_REMOTE_ONLY: true + CCACHE_REMOTE_STORAGE: http://cache.dev.ripplex.io:8080|layout=bazel + # Ignore the creation and modification timestamps on files, since the + # header files are copied into separate directories by CMake, which will + # otherwise result in cache misses. + CCACHE_SLOPPINESS: include_file_ctime,include_file_mtime + COVERAGE_ENABLED: ${{ contains(inputs.cmake_args, '-Dcoverage=ON') }} + VOIDSTAR_ENABLED: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }} steps: - name: Cleanup workspace (macOS and Windows) if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }} @@ -79,7 +102,11 @@ jobs: - name: Prepare runner uses: XRPLF/actions/prepare-runner@2ece4ec6ab7de266859a6f053571425b2bd684b6 with: - disable_ccache: false + disable_ccache: ${{ env.CCACHE_ENABLED == 'false' }} + + - name: Set ccache log file + if: ${{ env.CCACHE_ENABLED == 'true' && runner.debug }} + run: echo "CCACHE_LOGFILE=${{ runner.temp }}/ccache.log" >> "${GITHUB_ENV}" - name: Print build environment uses: ./.github/actions/print-env @@ -129,14 +156,21 @@ jobs: --parallel "${BUILD_NPROC}" \ --target "${CMAKE_TARGET}" + - name: Show ccache statistics + if: ${{ env.CCACHE_ENABLED == 'true' }} + run: | + ccache --show-stats -vv + if [ '${{ runner.debug }}' = '1' ]; then + cat "${CCACHE_LOGFILE}" + curl ${CCACHE_REMOTE_STORAGE%|*}/status + fi + - name: Upload the binary (Linux) if: ${{ github.repository_owner == 'XRPLF' && runner.os == 'Linux' }} uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - env: - BUILD_DIR: ${{ inputs.build_dir }} with: name: xrpld-${{ inputs.config_name }} - path: ${{ env.BUILD_DIR }}/xrpld + path: ${{ inputs.build_dir }}/xrpld retention-days: 3 if-no-files-found: error @@ -153,7 +187,7 @@ jobs: fi - name: Verify presence of instrumentation (Linux) - if: ${{ runner.os == 'Linux' && env.ENABLED_VOIDSTAR == 'true' }} + if: ${{ runner.os == 'Linux' && env.VOIDSTAR_ENABLED == 'true' }} working-directory: ${{ inputs.build_dir }} run: | ./xrpld --version | grep libvoidstar @@ -188,7 +222,7 @@ jobs: netstat -an - name: Prepare coverage report - if: ${{ !inputs.build_only && env.ENABLED_COVERAGE == 'true' }} + if: ${{ !inputs.build_only && env.COVERAGE_ENABLED == 'true' }} working-directory: ${{ inputs.build_dir }} env: BUILD_NPROC: ${{ steps.nproc.outputs.nproc }} @@ -201,7 +235,7 @@ jobs: --target coverage - name: Upload coverage report - if: ${{ github.repository_owner == 'XRPLF' && !inputs.build_only && env.ENABLED_COVERAGE == 'true' }} + if: ${{ github.repository_owner == 'XRPLF' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }} uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 with: disable_search: true diff --git a/.github/workflows/upload-conan-deps.yml b/.github/workflows/upload-conan-deps.yml index ec283e564c8..0a96c018298 100644 --- a/.github/workflows/upload-conan-deps.yml +++ b/.github/workflows/upload-conan-deps.yml @@ -72,7 +72,7 @@ jobs: - name: Prepare runner uses: XRPLF/actions/prepare-runner@2ece4ec6ab7de266859a6f053571425b2bd684b6 with: - disable_ccache: false + disable_ccache: true - name: Print build environment uses: ./.github/actions/print-env diff --git a/CMakeLists.txt b/CMakeLists.txt index ade9c2f9958..70bc02c66d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,9 @@ elseif(MSVC) add_compile_options(/wd4068) # Ignore unknown pragmas endif() +# Enable ccache to speed up builds. +include(Ccache) + # make GIT_COMMIT_HASH define available to all sources find_package(Git) if(Git_FOUND) diff --git a/cmake/Ccache.cmake b/cmake/Ccache.cmake new file mode 100644 index 00000000000..092212075ce --- /dev/null +++ b/cmake/Ccache.cmake @@ -0,0 +1,51 @@ +find_program(CCACHE_PATH "ccache") +if (NOT CCACHE_PATH) + return() +endif () + +# For Linux and macOS we can use the ccache binary directly. +if (NOT MSVC) + set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PATH}") + set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PATH}") + message(STATUS "Found ccache: ${CCACHE_PATH}") + return() +endif () + +# For Windows more effort is required. The code below is a modified version of +# https://github.com/ccache/ccache/wiki/MS-Visual-Studio#usage-with-cmake. +if ("${CCACHE_PATH}" MATCHES "chocolatey") + message(DEBUG "Ccache path: ${CCACHE_PATH}") + # Chocolatey uses a shim executable that we cannot use directly, in which + # case we have to find the executable it points to. If we cannot find the + # target executable then we cannot use ccache. + find_program(BASH_PATH "bash") + if (NOT BASH_PATH) + message(WARNING "Could not find bash.") + return() + endif () + + execute_process( + COMMAND bash -c "export LC_ALL='en_US.UTF-8'; ${CCACHE_PATH} --shimgen-noop | grep -oP 'path to executable: \\K.+' | head -c -1" + OUTPUT_VARIABLE CCACHE_PATH) + + if (NOT CCACHE_PATH) + message(WARNING "Could not find ccache target.") + return() + endif () + file(TO_CMAKE_PATH "${CCACHE_PATH}" CCACHE_PATH) +endif () +message(STATUS "Found ccache: ${CCACHE_PATH}") + +# Tell cmake to use ccache for compiling with Visual Studio. +file(COPY_FILE + ${CCACHE_PATH} ${CMAKE_BINARY_DIR}/cl.exe + ONLY_IF_DIFFERENT) +set(CMAKE_VS_GLOBALS + "CLToolExe=cl.exe" + "CLToolPath=${CMAKE_BINARY_DIR}" + "TrackFileAccess=false" + "UseMultiToolTask=true") + +# By default Visual Studio generators will use /Zi, which is not compatible with +# ccache, so tell it to use /Z7 instead. +set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$:Embedded>")