Skip to content
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
aec131b
ci: Use ccache to cache build objects for speeding up building
bthomee Dec 3, 2025
30d2f70
Print ccache statistics
bthomee Dec 3, 2025
89ea91a
Update CI images
bthomee Dec 3, 2025
5ca0577
Cache the ccache dir
bthomee Dec 3, 2025
efd2a33
Use env var for the ccache dir
bthomee Dec 3, 2025
ac71a5f
Update name of step
bthomee Dec 3, 2025
73ef462
Merge branch 'develop' into bthomee/ccache
bthomee Dec 4, 2025
a07399d
Merge branch 'develop' into bthomee/ccache
bthomee Dec 4, 2025
22ee2f5
Merge branch 'develop' into bthomee/ccache
bthomee Dec 4, 2025
6942b03
Merge branch 'develop' into bthomee/ccache
bthomee Dec 5, 2025
b38c500
Merge branch 'develop' into bthomee/ccache
bthomee Dec 8, 2025
b343926
Tweaks
bthomee Dec 8, 2025
ac96150
Add include(Ccache) to CMakeLists.txt
bthomee Dec 8, 2025
dd3c7d5
Improve build-test-config, enable ccache for MSVC
bthomee Dec 9, 2025
9cb4b78
Define stats log within a step
bthomee Dec 9, 2025
22517d6
Remove log stats as it segfaults on Debian, improve ccache command on…
bthomee Dec 9, 2025
a5b944a
Use multiple COMMAND statements for pipes
bthomee Dec 9, 2025
a621f02
Remove OUTPUT_QUIET and temporarily only run on Windows
bthomee Dec 9, 2025
4fed8fd
Debug
bthomee Dec 9, 2025
4efef6a
Debug
bthomee Dec 9, 2025
5570cc3
Use bash to extract ccache target on Windows
bthomee Dec 10, 2025
4f2b96f
Debug
bthomee Dec 10, 2025
1ada914
Debug
bthomee Dec 10, 2025
d1b928b
Move ccache include statements before compilers are defined
bthomee Dec 11, 2025
d3f1bbd
Merge branch 'develop' into bthomee/ccache
bthomee Dec 11, 2025
dde20ec
Debug
bthomee Dec 11, 2025
9c6fb66
Enable all OSes again in matrix
bthomee Dec 11, 2025
e18eb78
Merge branch 'develop' into bthomee/ccache
bthomee Dec 11, 2025
e234117
Simplify Ccache.cmake
bthomee Dec 11, 2025
a724ef4
Use redis as remote cache for windows only at the moment
bthomee Dec 12, 2025
40516a4
Fix prepare-runner path
bthomee Dec 12, 2025
2c9556c
Merge branch 'develop' into bthomee/ccache
bthomee Dec 12, 2025
7d7e774
Remove unavailable conditional
bthomee Dec 12, 2025
69fc941
Set redis endpoint
bthomee Dec 12, 2025
d426525
Improve log message
bthomee Dec 13, 2025
9e4f769
Use HTTP storage backend
bthomee Dec 15, 2025
9a91e42
Use HTTP storage backend
bthomee Dec 15, 2025
a423a18
Merge branch 'develop' into bthomee/ccache
bthomee Dec 15, 2025
2e218fb
Enable macOS and verbose cache stats
bthomee Dec 15, 2025
0adec9c
Enable linux
bthomee Dec 15, 2025
543e023
Update secret name
bthomee Dec 15, 2025
b1478f8
Improve comments and trigger
bthomee Dec 16, 2025
b2c896e
Use DNS name for cache endpoint
bthomee Dec 16, 2025
163faa7
Use log file for ccache to debug issues
bthomee Dec 16, 2025
40cbe13
Fix url suffix
bthomee Dec 16, 2025
f54db31
Move ccache log file into temp directory
bthomee Dec 16, 2025
8c0543f
Use runner.xxx instead of github.xxx
bthomee Dec 16, 2025
923e44d
The runner.xxx is only available in steps
bthomee Dec 16, 2025
e260a4f
The runner.xxx is only available in steps
bthomee Dec 16, 2025
364f04f
Add sloppiness to increase cache hits
bthomee Dec 16, 2025
bc70a96
Improve comments describing the ccache env vars
bthomee Dec 16, 2025
d387880
Improve ccache enabled statement
bthomee Dec 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/scripts/strategy-matrix/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
56 changes: 28 additions & 28 deletions .github/scripts/strategy-matrix/linux.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand Down
41 changes: 32 additions & 9 deletions .github/workflows/reusable-build-test-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ 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') }}
CCACHE_ENABLED: ${{ github.event_name == 'pull_request' }}
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' }}
Expand All @@ -79,7 +80,7 @@ jobs:
- name: Prepare runner
uses: XRPLF/actions/.github/actions/prepare-runner@99685816bb60a95a66852f212f382580e180df3a
with:
disable_ccache: false
disable_ccache: ${{ env.CCACHE_ENABLED == 'false' }}

- name: Print build environment
uses: ./.github/actions/print-env
Expand Down Expand Up @@ -116,6 +117,17 @@ jobs:
${CMAKE_ARGS} \
..

- name: Restore ccache
if: ${{ env.CCACHE_ENABLED == 'true' }}
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You always download cache, add files to it (while building new code), and then upload a bigger cache.

This will eventually grow the cache size, and make it useless

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I had hoped it would be more like Bazel/BuildBuddy where the least recently used files would be dropped automatically once a certain time/size limit was reached, but here the caches are considered as a whole unit and dropped entirely.

My original idea was to use ccache for caching across PRs, so unchanged files wouldn't need to be built again. It seems like that is not possible with the current set up. Should a separate cache be used per PR?

Per actions/cache#1071, one comment states "This functioning is expected and cache is built on the principle that "each key uniquely identifies a cache". if a cache contents have changed and you need to update it, its key should also reflect that.". So would this mean that each commit that modifies some source files needs its own cache? That entirely defeats the purpose...

Copy link
Contributor

@mathbunnyru mathbunnyru Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should a separate cache be used per PR?

I don't know if that would work well in rippled's case, because it depends on how active people are pushing their PRs.
I think if there are many active PRs and they override the same cache, it's rarely going to work.

Clio doesn't create caches on PRs, only on commits on develop.
This also solves the problem with fork/non-fork.
And we add a commit hash to the cache id.

with:
path: ${{ env.CCACHE_DIR }}
key: ${{ inputs.config_name }}

- name: Show ccache statistics before building
if: ${{ env.CCACHE_ENABLED == 'true' }}
run: ccache --show-stats ${{ runner.debug && '-vv' || '' }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will all be zeroes and only show ccache size limit, so I don't think it's needed and gives useful information

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will still show the size of the cache, even though the hits and misses are not shown (because they are zero), e.g.

Local storage:
  Cache size (GB): 0.43 / 5.00 ( 8.64%)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This information is also shown after the build finishes (with new files included), and on previous upload (without them), that's why it's not that needed


- name: Build the binary
working-directory: ${{ inputs.build_dir }}
env:
Expand All @@ -129,14 +141,25 @@ jobs:
--parallel "${BUILD_NPROC}" \
--target "${CMAKE_TARGET}"

- name: Show and reset ccache statistics after building
if: ${{ env.CCACHE_ENABLED == 'true' }}
run: |
ccache --show-stats ${{ runner.debug && '-vv' || '' }}
ccache --zero-stats

- name: Save ccache
if: ${{ env.CCACHE_ENABLED == 'true' }}
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work when PR is created from fork?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes:

  • Everyone has 10GB by default.
  • Even if writing fails, the step succeeds. This is apparently a feature (although several developers have filed tickets to complain that they'd like the step to fail the pipeline if saving doesn't work).

Now, if you think it'd be better to not enable this by default in forks, I can make the change. I'm fine either way.

with:
path: ${{ env.CCACHE_DIR }}
key: ${{ inputs.config_name }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will happen if 2 PRs run simultaneously and write to the same cache key?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that the first one to attempt the write will succeed, while the second one will fail to write with the "Unable to reserve cache with key ..., another job may be creating this cache" message.


- name: Upload rippled artifact (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: rippled-${{ inputs.config_name }}
path: ${{ env.BUILD_DIR }}/rippled
path: ${{ inputs.build_dir }}/rippled
retention-days: 3
if-no-files-found: error

Expand All @@ -153,7 +176,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: |
./rippled --version | grep libvoidstar
Expand Down Expand Up @@ -188,7 +211,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 }}
Expand All @@ -201,7 +224,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
Expand Down
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
45 changes: 45 additions & 0 deletions cmake/Ccache.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
find_program(CCACHE_PATH "ccache")
if (CCACHE_PATH)
if (MSVC)
# Chocolatey uses a shim executable that we cannot use directly, in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who installed ccache on Windows?
Is it part of deployment scripts?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's part of the Terraform script that deploys the Windows runners, using chocolatey to install ccache. Unfortunately it cannot be installed via pip.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we do it in prepare-runner?
The same way we use brew for Mac, we'll be using cholocatey for Windows

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in XRPLF/actions#42.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have to update the usage here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I will in a follow-up PR.

I'm currently first considering taking advantage of ccache supporting Redis as a remote cache, so I can rip out the largely useless GitHub cache.

# which case we have to find the executable it points to. If we cannot
# find the target executable then we cannot use ccache.
message(STATUS "Ccache path: ${CCACHE_PATH}")
if ("${CCACHE_PATH}" MATCHES "chocolatey")
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 ()

# 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. When running in
# CI the /Zi option will have already been stripped out, in which case
# the following will be a no-op, see XrplCompiler.cmake.
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>")
else ()
# For Linux and macOS we can use the ccache binary directly.
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PATH}")
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PATH}")
endif ()
message(STATUS "Using ccache: ${CCACHE_PATH}")
endif ()
Loading