Skip to content

Cache the cvc5 artifacts required to test the Pythonic API - #119

Merged
daniel-larraz merged 1 commit into
cvc5:mainfrom
daniel-larraz:ci-cache-cvc5-artifacts
Aug 12, 2026
Merged

Cache the cvc5 artifacts required to test the Pythonic API#119
daniel-larraz merged 1 commit into
cvc5:mainfrom
daniel-larraz:ci-cache-cvc5-artifacts

Conversation

@daniel-larraz

Copy link
Copy Markdown
Contributor

Building cvc5 from scratch on every CI run is wasteful when its code has not
changed. This caches the artifacts the tests actually need, keyed on the cvc5
commit, and skips the build when they can be restored.

On a cache hit the job goes from around 14 minutes to under half a minute.

What is cached

The Python bindings package and the cvc5 shared libraries it links against.
The bindings embed an absolute rpath into the build tree, and the workspace
path is stable across runs, so they can be restored and used in place without
relinking.

Skipping the build additionally requires a hit on the dependencies cache: in a
shared build, which --python-bindings requires, some dependencies, libpoly
among them, are built as shared libraries under deps/install/lib and are
loaded at run time.

The cache is keyed on the cvc5 commit, so it can never serve bindings that do
not match the cvc5 revision that was just checked out. A pythonic API change
alone always hits; an upstream cvc5 commit always rebuilds.

Skipping the dependency installation

Everything the install-dependencies action provides is needed to build cvc5:
the compilers and headers, ccache, and the num_proc variable. The libraries
the cached artifacts load at run time are either part of the runner image,
libgmp10 and libstdc++, or come from the cached build/deps, so the action is
skipped along with the build.

Note that this relies on the bindings not being linked against CLN, whose
runtime package is not part of the runner image. The production build does not
use CLN: --gpl only permits GPL dependencies, it does not select the CLN
implementation, which is what --cln does. The Check the cached cvc5 artifacts step guards this: if cvc5 ever links a new system library, it fails
on cache-hit runs with a clear message instead of failing inside the tests.

Two related fixes

The cache keys track the configuration cvc5 is built with, now defined once in
the CVC5_CONFIG variable, rather than the workflow file, so that unrelated
changes to the workflow do not discard the cached artifacts.

The workflow also set up a ccache cache and configured it, but cvc5 only uses
ccache if the compiler launchers are passed to CMake, which its own CI does but
this workflow did not, so nothing was ever cached: every stored entry was
around 13 KiB, holding just the configuration and the statistics. Passing the
launchers takes the stored cache to around 24 MiB. This matters because the
artifacts cache turns over whenever the cvc5 default branch advances, and a
working ccache makes those rebuilds incremental.

Testing

Verified on the fork. The run against the final tree restored both caches,
skipped the dependency installation and the build, and passed the test suite
against the restored bindings in 24 seconds, compared to around 14 minutes for
the cold builds that preceded it.

🤖 Generated with Claude Code

Building cvc5 from scratch on every CI run is wasteful when its code has
not changed. Cache the artifacts the tests actually need, keyed on the
cvc5 commit, and skip the build when they can be restored.

The cached artifacts are the Python bindings package and the cvc5 shared
libraries it links against. The bindings embed an absolute rpath into the
build tree, which is stable across runs, so they can be restored and used
in place.

Skipping the build additionally requires a hit on the dependencies cache:
in a shared build, which --python-bindings requires, some dependencies,
libpoly among them, are built as shared libraries under deps/install/lib
and are loaded at run time.

Installing the build dependencies is skipped along with the build. All
that action provides is needed to build cvc5: the compilers and headers,
ccache, and the num_proc variable. The libraries the cached artifacts load
at run time are either part of the runner image, libgmp10 and libstdc++,
or come from the cached build/deps. Note that this relies on the bindings
not being linked against CLN, whose runtime package is not part of the
runner image: --gpl only permits GPL dependencies, it does not select the
CLN implementation, which is what --cln does.

The cache keys track the configuration cvc5 is built with, now defined
once in the CVC5_CONFIG variable, rather than the workflow file, so that
unrelated changes to the workflow do not discard the cached artifacts.

Finally, actually use ccache. The workflow set up a ccache cache and
configured it, but cvc5 only uses ccache if the compiler launchers are
passed to CMake, which its own CI does but this workflow did not, so
nothing was ever cached. This matters because the artifacts cache turns
over whenever the cvc5 default branch advances; a working ccache makes
those rebuilds incremental.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@alex-ozdemir alex-ozdemir left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank goodness :)

@daniel-larraz
daniel-larraz merged commit 4c0ce75 into cvc5:main Aug 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants