Skip to main content

A high-performance local compiler cache daemon

Project description

zccache

Linux macOS Windows PyPI crates.io: zccache-core crates.io: zccache-cli crates.io: zccache-daemon Rust Workspace Version

C/C++ clang clang++ clang-tidy IWYU

Rust rustc clippy rustfmt

Emscripten emcc em++ wasm-ld

A blazing fast compiler cache for C/C++ and Rust

New Project

Inspired by sccache, but optimized for local-first use with aggressive file metadata caching and filesystem watching.

Quick Install

curl -LsSf https://github.com/zackees/zccache/releases/latest/download/install.sh | sh
powershell -ExecutionPolicy Bypass -c "irm https://github.com/zackees/zccache/releases/latest/download/install.ps1 | iex"

Verify:

zccache --version

Performance

50 files per benchmark, median of 5 trials. Run it yourself: ./perf

Cache Hit (warm cache)

Benchmark Bare Compiler sccache zccache vs sccache vs bare
C++ single-file 11.705s 1.576s 0.050s 32x 236x
C++ multi-file 11.553s 11.530s 0.017s 695x 696x
C++ response-file (single) 12.540s 1.558s 0.047s 33x 267x
C++ response-file (multi) 12.049s 12.434s 0.019s 669x 648x
Rust build 6.592s 8.604s 0.045s 193x 148x
Rust check 3.716s 5.922s 0.049s 121x 76x

Cache Miss (cold compile)

Benchmark Bare Compiler sccache zccache vs sccache vs bare
C++ single-file 12.641s 20.632s 13.430s 1.5x 0.9x
C++ multi-file 11.358s 11.759s 12.867s 0.9x 0.9x
C++ response-file (single) 12.063s 20.607s 14.087s 1.5x 0.9x
C++ response-file (multi) 13.030s 25.303s 13.975s 1.8x 0.9x
Rust build 7.119s 10.023s 8.507s 1.2x 0.8x
Rust check 4.289s 7.056s 5.060s 1.4x 0.8x
Benchmark details
  • Single-file = 50 sequential clang++ -c unit.cpp invocations
  • Multi-file = one clang++ -c *.cpp invocation (sccache cannot cache these — its "warm" time is a full recompile)
  • Response-file = args via nested .rsp files: 200 -D defines + 50 -I paths + 30 warning flags (~283 expanded args)
  • Rust build = --emit=dep-info,metadata,link (cargo build)
  • Rust check = --emit=dep-info,metadata (cargo check)
  • Cold = first compile (empty cache). Warm = median of 5 subsequent runs.
  • sccache gets cache hits but each hit still costs ~170ms subprocess overhead. zccache serves hits in ~1ms via in-process IPC.

Why is zccache so much faster on warm hits?

The difference comes from architecture, not better caching:

sccache zccache
IPC model Subprocess per invocation (fork + exec + connect) Persistent daemon, single IPC message per compile
Cache lookup Client hashes inputs, sends to server, server checks disk Daemon has inputs in memory (file watcher + metadata cache)
On hit Server reads artifact from disk, sends back via IPC Daemon hardlinks cached file to output path (1 syscall)
Multi-file Compiles every file (no multi-file cache support) Parallel per-file cache lookups, only misses go to the compiler
Per-hit cost ~170ms (process spawn + hash + disk I/O + IPC) ~1ms (in-memory lookup + hardlink)

Architecture enhancements that make the difference:

  • Filesystem watcher — a background notify watcher tracks file changes in real time, so the daemon already knows whether inputs are dirty before you even invoke a compile. No redundant stat/hash work on hit.
  • In-memory metadata cache — file sizes, mtimes, and content hashes live in a lock-free DashMap. Cache key computation is a memory lookup, not disk I/O.
  • Single-roundtrip IPC — each compile is one length-prefixed bincode message over a Unix socket (or named pipe on Windows). No subprocess spawning, no repeated handshakes.
  • Hardlink delivery — cache hits are served by hardlinking the cached artifact to the output path — a single syscall instead of reading + writing the file contents.
  • Multi-file fast path — when a build system passes N source files in one invocation, zccache checks all N against the cache in parallel, serves hits immediately, and batches only the misses into a single compiler process.

Broader tool coverage — zccache supports modes that other compiler caches don't:

Mode Description
Multi-file compilation clang++ -c a.cpp b.cpp c.cpp — per-file caching with parallel lookups
Response files Nested .rsp files with hundreds of flags — fully expanded and cached
clang-tidy Static analysis results cached and replayed
include-what-you-use IWYU output cached per translation unit
Emscripten (emcc/em++) WebAssembly compilation cached end-to-end
wasm-ld WebAssembly linking cached
rustfmt Formatting results cached
clippy Lint results cached
Rust check & build cargo check and cargo build with extern crate content hashing

Install

curl -LsSf https://github.com/zackees/zccache/releases/latest/download/install.sh | sh
powershell -ExecutionPolicy Bypass -c "irm https://github.com/zackees/zccache/releases/latest/download/install.ps1 | iex"

This installs the standalone native Rust binaries (zccache, zccache-daemon, and zccache-fp) directly from GitHub Releases.

Default install locations:

  • Linux/macOS user install: ~/.local/bin
  • Linux/macOS global install: /usr/local/bin
  • Windows user install: %USERPROFILE%\.local\bin
  • Windows global install: %ProgramFiles%\zccache\bin

Global install examples:

curl -LsSf https://github.com/zackees/zccache/releases/latest/download/install.sh | sudo sh -s -- --global
powershell -ExecutionPolicy Bypass -c "$env:ZCCACHE_INSTALL_MODE='global'; irm https://github.com/zackees/zccache/releases/latest/download/install.ps1 | iex"

Each GitHub release also publishes standalone per-platform archives:

  • Linux: zccache-vX.Y.Z-x86_64-unknown-linux-musl.tar.gz, zccache-vX.Y.Z-aarch64-unknown-linux-musl.tar.gz
  • macOS: zccache-vX.Y.Z-x86_64-apple-darwin.tar.gz, zccache-vX.Y.Z-aarch64-apple-darwin.tar.gz
  • Windows: zccache-vX.Y.Z-x86_64-pc-windows-msvc.zip, zccache-vX.Y.Z-aarch64-pc-windows-msvc.zip

PyPI remains available if you prefer pip install zccache; those wheels also install the native binaries directly onto your PATH. Pre-built wheels are available for:

Platform Architecture
Linux x86_64, aarch64
macOS x86_64, Apple Silicon
Windows x86_64

Verify the install:

zccache --version

Rust crates are also published on crates.io. The main installable/runtime crates are:

  • zccache-cli
  • zccache-daemon
  • zccache-core
  • zccache-hash
  • zccache-protocol
  • zccache-fscache
  • zccache-artifact

Use it as a drop-in replacement for sccache — just substitute zccache:

Integration Summary

RUSTC_WRAPPER=zccache cargo build
export CC="zccache clang"
export CXX="zccache clang++"
  • Rust: set RUSTC_WRAPPER=zccache or add rustc-wrapper = "zccache" to .cargo/config.toml.
  • Bash: export RUSTC_WRAPPER, CC, and CXX once in your shell or CI environment.
  • Python: pass RUSTC_WRAPPER, CC, and CXX through subprocess env when invoking cargo or clang.
  • First commands to check: zccache --version, zccache start, zccache status.
Rust zccache integration

Use zccache as Cargo's compiler wrapper:

# one-off invocation
RUSTC_WRAPPER=zccache cargo build
RUSTC_WRAPPER=zccache cargo check

# optional: start the daemon explicitly
zccache start

Add to .cargo/config.toml for automatic use:

[build]
rustc-wrapper = "zccache"

Recommended project-local config:

[build]
rustc-wrapper = "zccache"

[env]
ZCCACHE_DIR = { value = "/tmp/.zccache", force = false }

Supports --emit=metadata (cargo check), --emit=dep-info,metadata,link (cargo build), extern crate content hashing, and cacheable crate types such as lib, rlib, and staticlib. Proc-macro and binary crates are passed through without caching, matching the usual sccache behavior.

Useful Rust workflow commands:

# inspect status
zccache status

# clear local cache
zccache clear

# validate wrapper is active
RUSTC_WRAPPER=zccache cargo clean
RUSTC_WRAPPER=zccache cargo check
zccache status
Bash integration

For shell-driven builds, export the wrapper once in your session or CI step:

export RUSTC_WRAPPER=zccache
export CC="zccache clang"
export CXX="zccache clang++"

zccache start
cargo build
ninja

If you want this active in interactive shells, add it to ~/.bashrc:

export RUSTC_WRAPPER=zccache
export PATH="$HOME/.local/bin:$PATH"

For per-build stats in Bash:

eval "$(zccache session-start --stats)"
cargo build
zccache session-end "$ZCCACHE_SESSION_ID"
Python integration

Python projects can use zccache when invoking Rust or C/C++ toolchains through subprocess, build backends, or extension-module builds.

import os
import subprocess

env = os.environ.copy()
env["RUSTC_WRAPPER"] = "zccache"
env["CC"] = "zccache clang"
env["CXX"] = "zccache clang++"

subprocess.run(["cargo", "build", "--release"], check=True, env=env)

This is useful for:

  • setuptools-rust
  • maturin
  • scikit-build-core
  • custom Python build/test harnesses that shell out to cargo, clang, or clang++

Example with maturin:

RUSTC_WRAPPER=zccache maturin build

Example with Python driving cargo check:

subprocess.run(["cargo", "check"], check=True, env=env)

C/C++ build system integration (ninja, meson, cmake, make)

zccache is a drop-in compiler wrapper. Point your build system's compiler at zccache <real-compiler> and it handles the rest:

# meson native file
[binaries]
c = ['zccache', '/usr/bin/clang']
cpp = ['zccache', '/usr/bin/clang++']
# CMake
set(CMAKE_C_COMPILER_LAUNCHER zccache)
set(CMAKE_CXX_COMPILER_LAUNCHER zccache)

The first build (cold cache) runs at near-bare speed. Subsequent rebuilds (ninja -t clean && ninja, or touching source files) serve cached artifacts via hardlinks in under a second.

Single-roundtrip IPC: In drop-in mode, zccache sends a single CompileEphemeral message that combines session creation, compilation, and session teardown — eliminating 2 of 3 IPC roundtrips per invocation.

Session stats: Track hit rates per-build with --stats:

eval $(zccache session-start --stats --log build.log)
export ZCCACHE_SESSION_ID=...
# ... build runs ...
zccache session-stats $ZCCACHE_SESSION_ID   # query mid-build
zccache session-end $ZCCACHE_SESSION_ID     # final stats

Persistent cache: Artifacts are stored in ~/.zccache/artifacts/ and survive daemon restarts. No need to re-warm the cache after a reboot.

Compile journal (build replay): Every compile and link command is recorded to ~/.zccache/logs/compile_journal.jsonl as a JSONL file with enough detail to replay the entire build:

{"ts":"2026-03-17T10:30:00.123Z","outcome":"hit","compiler":"/usr/bin/clang++","args":["-c","foo.cpp","-o","foo.o"],"cwd":"/project/build","env":[["CC","clang"]],"exit_code":0,"session_id":"uuid","latency_ns":1234567}

Fields: ts (ISO 8601 UTC), outcome (hit/miss/error/link_hit/link_miss), compiler (full path), args (full argument list), cwd, env (omitted when inheriting daemon env), exit_code, session_id (null for ephemeral), latency_ns (wall-clock nanoseconds). One JSON object per line — pipe through jq to filter, or replay builds by extracting compiler + args + cwd.

Per-session compile journal: Pass --journal <path> to session-start to write a dedicated JSONL log containing only the commands from that session. The path must end in .jsonl:

result=$(zccache session-start --journal build.jsonl)
session_id=$(echo "$result" | jq -r .session_id)
export ZCCACHE_SESSION_ID=$session_id

# ... build runs ...

# Inspect this session's commands only (no noise from other sessions)
jq . build.jsonl

zccache session-end $session_id

The session journal uses the same JSONL schema as the global journal. Entries are written to both the global and session journals simultaneously. The session file handle is released when session-end is called.

Multi-file compilation (fast path)

When a build system passes multiple source files to a single compiler invocation (e.g. gcc -c a.cpp b.cpp c.cpp -o ...), zccache treats this as a fast path:

  1. Each source file is checked against the cache in parallel.
  2. Cache hits are served immediately — their .o files are written from the cache.
  3. Remaining cache misses are batched into a single compiler process, preserving the compiler's own process-reuse and memory-sharing benefits.
  4. The outputs of the batched compilation are cached individually for future hits.

This hybrid approach means the first build populates the cache per-file, and subsequent builds serve as many files as possible from cache while still letting the compiler handle misses efficiently in bulk.

Recommendation: Configure your build system to pass multiple source files per compiler invocation whenever possible. This gives zccache the best opportunity to parallelize cache lookups and minimize compiler launches.

Concurrency

The daemon uses lock-free concurrent data structures (DashMap) for artifact and metadata lookups, so parallel compilation requests from multiple build workers never serialize on a global lock.

Status

Early development — architecture and scaffolding phase.

Goals

  • Extremely fast on local machines (daemon keeps caches warm)
  • Portable across Linux, macOS, and Windows
  • Correct under heavy parallel compilation (no stale cache hits)
  • Simple deployment (single binary)

Tool Compatibility

zccache works as a drop-in wrapper for these compilers and tools:

Architecture

See docs/ARCHITECTURE.md for the full system design.

Key components

Crate Purpose
zccache-cli Command-line interface (zccache binary)
zccache-daemon Daemon process (IPC server, orchestration)
zccache-core Shared types, errors, config, path utilities
zccache-protocol IPC message types and serialization
zccache-ipc Transport layer (Unix sockets / named pipes)
zccache-hash blake3 hashing and cache key computation
zccache-fscache In-memory file metadata cache
zccache-artifact Disk-backed artifact store with redb index
zccache-watcher File watcher abstraction (notify backend)
zccache-compiler Compiler detection and argument parsing
zccache-test-support Test utilities and fixtures

Building

cargo build --workspace

Testing

cargo test --workspace

Documentation

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

zccache-1.1.19-py3-none-win_arm64.whl (4.3 MB view details)

Uploaded Python 3Windows ARM64

zccache-1.1.19-py3-none-win_amd64.whl (4.6 MB view details)

Uploaded Python 3Windows x86-64

zccache-1.1.19-py3-none-musllinux_1_2_x86_64.whl (5.5 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

zccache-1.1.19-py3-none-musllinux_1_2_aarch64.whl (5.0 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

zccache-1.1.19-py3-none-manylinux_2_17_x86_64.whl (5.3 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

zccache-1.1.19-py3-none-manylinux_2_17_aarch64.whl (4.9 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

zccache-1.1.19-py3-none-macosx_11_0_arm64.whl (4.6 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

zccache-1.1.19-py3-none-macosx_10_12_x86_64.whl (4.8 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file zccache-1.1.19-py3-none-win_arm64.whl.

File metadata

File hashes

Hashes for zccache-1.1.19-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 b16f033088200035e3b74e5404f8acaab40d2c78f8eda3c6b8c6ae634aa7470c
MD5 ccaf44323978e8a344a29d37e51d8a4b
BLAKE2b-256 82e4a1a21a0cd6769bf418c8698739432c5e2ffb128f54dabe661dd68f147122

See more details on using hashes here.

File details

Details for the file zccache-1.1.19-py3-none-win_amd64.whl.

File metadata

File hashes

Hashes for zccache-1.1.19-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 b08a083acabecafd8402a47f3415cc0024706ba114ca6a9d02b1f2a68dd95997
MD5 3fbcb92c0d44c1679630aacf2988c6cc
BLAKE2b-256 4deeb91ca7e340eec0b8cae48b0a4d2778f6002b8bb124963429674a5a1f4d9a

See more details on using hashes here.

File details

Details for the file zccache-1.1.19-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for zccache-1.1.19-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 3f19907c1d1e9c9afe3a9d40ea63cbac1c9af3bd7f0f0f56f17598082ffe821b
MD5 abda252269221261838f76e6330a821f
BLAKE2b-256 70985d504d4e1f429fcd38aaaf700861ff1180b48030648f86e2b6759c18262a

See more details on using hashes here.

File details

Details for the file zccache-1.1.19-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for zccache-1.1.19-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 211dfcd7dd5f8aee5fa80bcc08b0000ece336e3392582bae76e2e7707f0129ae
MD5 5010b865d0e8dd74dc81e8951f771642
BLAKE2b-256 d2078adf0ce9d048c5e5984ba09b159eb99b0d2b544c007785d0c08996419948

See more details on using hashes here.

File details

Details for the file zccache-1.1.19-py3-none-manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for zccache-1.1.19-py3-none-manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 8c6b892522612c83fb23e7e6708d84ef3cd47a5b0dae1625280fa02ac3af5c30
MD5 8f70f7ee7aeb914a2bb229ace2884aa1
BLAKE2b-256 dd0109742dade548b7d096ae16ca6652735dd86823a3ffe8e240224ab07af565

See more details on using hashes here.

File details

Details for the file zccache-1.1.19-py3-none-manylinux_2_17_aarch64.whl.

File metadata

File hashes

Hashes for zccache-1.1.19-py3-none-manylinux_2_17_aarch64.whl
Algorithm Hash digest
SHA256 9d516317d367359d10ab723aa20d2e6cd5bcd968ecd3aab506b92dd3c1b4c25d
MD5 8149452bf9139a2beac0da314f33d08e
BLAKE2b-256 ab98362f1461d16f562972f6587c81e8b0a5befb0535233e22ca3754fdf10eec

See more details on using hashes here.

File details

Details for the file zccache-1.1.19-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for zccache-1.1.19-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 038962a7cbec49c3d5992e73cb373e30c3e3f69ac50174a5705dd228d3946d48
MD5 3c37d0fbdcf598f89d8c688727140fb9
BLAKE2b-256 1d74a4633ef94936cb0831d9041f69b65f25682a4f6e9768ed48e334281c2f22

See more details on using hashes here.

File details

Details for the file zccache-1.1.19-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for zccache-1.1.19-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 80d0833fb2ddef6a611986c7ec6f67a609fc1e1db02de42c8bc3ff3710eb6fba
MD5 bbb7a161f381ade27973dc591a1a7449
BLAKE2b-256 40df1cabb54926893e23ba76b682cc6c0d05a26791f70621e0ebe5dc63fd7688

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page