compile-cache-testclient¶
A standalone client and validation harness for the compile cache. This is test
infrastructure, not a shipped product: no install() rule names it, no package
carries it, it is not built by default, and it is not supported for general
use. It is documented here for contributors working on the canonicalization
contract. If you are looking for something to run, you want
fastcache-cc or
fastcache-compile-node.
It is the reference localizer. It links the same PathCanon /
CompileValue code the server uses, so the canonicalization parity contract is
exercised rather than reimplemented — if the client and server ever disagree
about how a path is canonicalized, this is what catches it.
Building¶
Not built by default. It is built by the linux and clang-tidy CI jobs,
though, so that it cannot quietly stop compiling — which is exactly what happened
before (issue #84).
cmake --preset clang-debug -DFASTCACHED_BUILD_TESTCLIENT=ON
cmake --build --preset clang-debug --target compile-cache-testclient
Usage¶
compile-cache-testclient <store|fetch|drop> --port N [--key K] [--prefetch-group C]
--srcroot P --buildtree Q [--compiler cl|clang-cl] [--source F] [--out OBJ]
Run compile-cache-testclient --help for the generated reference; it is
rendered from the same option table the parser matches against, so it cannot
fall out of step with what the tool accepts.
Options take their value either as the next argument or joined with =, the
same as the daemon's own parser. An unrecognised option is an error rather than
something silently ignored.
| Flag | Default |
|---|---|
--host |
127.0.0.1 |
--port |
none — required |
--key |
empty |
--prefetch-group |
default |
--srcroot, --buildtree |
empty |
--compiler |
cl on Windows, cc elsewhere |
--source |
empty |
--out |
store: a temp path; fetch: skip writing when empty |
store¶
Compiles the source, captures the object file and the compiler's dependency
record, frames them as a CompileValue, and STOREs it through a running
fastcached — carrying the producer's source-root and build-tree layout.
Both driver families work, and the difference is not cosmetic: an MSVC driver is
asked for /showIncludes and reports on its own output, while a GNU driver is
asked for -MD -MF and writes a depfile. The stored region is tagged with
whichever grammar produced it (PathCanon knows both), so a value stored by
either can be localized by either. The family is chosen from the --compiler
name, not from the host — clang-cl takes MSVC spellings on Linux too.
fetch¶
FETCHes the canonical value, localizes every path to the consumer's layout, optionally writes the object out, and verifies that each localized dependency path resolves on disk. A path that does not resolve is a failure.
Which paths are checked comes from the launcher's own
Cc::ReplayedDependencyPaths, so this tool asks exactly the question a real
cache hit asks. That matters in both directions: it understands a depfile as
well as /showIncludes (a scanner that knew only the latter reported
includePathsChecked=0 on POSIX and validated nothing while still exiting 0),
and it does not report a toolchain path outside both roots, or a canonical
token the region walker declined to localize, as missing — neither is this
build's to have.
drop¶
Sends one CACHE-DROP for --key: the endpoint removes the key from its own tier and
nowhere else. It exists so an end-to-end case can take a stored object away while the
launcher's direct-mode manifest that points at it stays — the state an operator creates
by removing a wrong object, and one no launcher run can produce on its own.
Exit codes¶
| Code | Meaning |
|---|---|
0 |
Success |
2 |
Usage error, socket failure, malformed value, or localization failure |
3 |
The compiler failed during store |
4 |
FETCH miss, or DROP miss — there was nothing to remove, which is an answer rather than a failure |
5 |
FETCH hit, but at least one localized header path did not resolve on disk |
Code 5 is the interesting one: it means the cache returned an entry whose
dependency paths do not exist on the consuming machine — exactly the corruption
the canonicalization layer exists to prevent.
Cross-depth validation¶
run-crossdepth.ps1 proves the core value-portability guarantee: an object
compiled at a deep checkout path (mimicking a CI runner nested deeper) is
usable when fetched from a shallow checkout. That is the scenario that
poisons a build tool's dependency database when absolute paths from a
different checkout depth are replayed verbatim.
# Synthetic: generated source, no project files involved.
pwsh src/apps/compile-cache-testclient/run-crossdepth.ps1 -Synthetic
# Rooted at real checkouts. Validates the real per-machine paths WITHOUT
# compiling or reading any project source: a generated tree is laid under a
# throwaway subfolder of each root and removed afterwards.
pwsh src/apps/compile-cache-testclient/run-crossdepth.ps1 `
-CheckoutRoots "D:\proj","D:\repo\proj"
Privacy rule¶
This tool and its harness must never print, log, or persist project-private information — no project source, no proprietary header names, no absolute checkout paths — into anything under version control. The harness prints generic status and counts only; its working files live in temp directories and throwaway subfolders that are cleaned up afterwards.