sccache 0.15.0

Sccache is a ccache-like tool. It is used as a compiler wrapper and avoids compilation when possible. Sccache has the capability to utilize caching in remote storage environments, including various cloud storage options, or alternatively, in local storage.
Documentation
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project

sccache is a ccache-like compiler caching tool written in Rust (edition 2024, MSRV 1.85.0). It wraps a compiler invocation, hashes its inputs, and either returns a cached artifact or runs the compiler and caches the result. It supports C/C++, Rust, CUDA (nvcc / clang), HIP, NVC++, MSVC, and Wind River Diab. It also implements icecream-style distributed compilation with auth/TLS/sandboxing.

## Common commands

Build:
```
cargo build --release                        # default = all storage backends
cargo build --release --no-default-features --features=s3,redis  # subset
cargo build --release --features=openssl/vendored --features=dist-server --bin sccache-dist
```

Lint / format (must pass in CI):
```
cargo fmt -- --check
cargo clippy --locked --all-targets -- -D warnings -A unknown-lints -A clippy::type_complexity -A clippy::new-without-default
npx --yes @taplo/cli fmt --check             # TOML formatting
```

Tests — integration tests start a real sccache server, so they must run sequentially:
```
cargo test --locked --lib --bins --tests
cargo test --locked --features 'dist-tests' -- --test-threads 1
cargo test --test sccache_cargo                  # run a single integration test file
cargo test --test system test_name -- --nocapture
```

Distributed tests (`tests/dist.rs`, gated by `dist-tests`) require Docker and `icecc-create-env` on PATH — they will be silently skipped or fail otherwise. The helper script `scripts/run-tests.sh` wraps the canonical invocation.

Debug a running server: `SCCACHE_ERROR_LOG=/tmp/sccache.log SCCACHE_LOG=debug sccache`, or run in foreground with `SCCACHE_START_SERVER=1 SCCACHE_NO_DAEMON=1 sccache`.

## Architecture

**Client / server split.** The `sccache` binary is both client and server. Each invocation is a thin client that connects to a long-lived per-user server (default `127.0.0.1:4226`, override via `SCCACHE_SERVER_PORT` or `SCCACHE_SERVER_UDS`); the server holds the in-memory state (compiler info cache, dist client, stats) and idles out after 10 minutes. Client/server protocol lives in `src/protocol.rs` (length-delimited bincode); `src/client.rs` and `src/server.rs` are the two endpoints; `src/commands.rs` dispatches CLI subcommands; `src/cmdline.rs` is the clap definitions.

**Compile pipeline (`src/compiler/`).** `compiler.rs` defines the core traits (`Compiler`, `CompilerHasher`, `Compilation`). Per-compiler frontends live in sibling files: `gcc.rs`, `clang.rs`, `msvc.rs`, `diab.rs`, `tasking_vx.rs`, `nvcc.rs`, `nvhpc.rs`, `cicc.rs`, `cudafe.rs`, `ptxas.rs`, `rust.rs`. `c.rs` is the shared C-family pipeline (preprocess → hash → cache lookup → compile-and-store). `args.rs` is a generic argument-parsing DSL used by every frontend. `preprocessor_cache.rs` implements the optional ccache-style "direct mode" cache that hashes preprocessor inputs to skip the preprocess step entirely. Adding a new compiler means implementing the traits in `compiler.rs` and wiring detection into `get_compiler_info` (server.rs).

**Storage backends (`src/cache/`).** `cache.rs` defines the `Storage` trait and `storage_from_config`, the factory that picks a backend from `Config`. `disk.rs` is the always-available local backend (built on `lru_disk_cache/`). Cloud backends — `s3.rs`, `gcs.rs`, `azure.rs`, `redis.rs`, `memcached.rs`, `gha.rs`, `webdav.rs`, `oss.rs`, `cos.rs` — are each behind a Cargo feature and most are thin adapters over `opendal`. `multilevel.rs` composes backends into an L1→L2 hierarchy with backfill (see `docs/MultiLevel.md`); `readonly.rs` wraps any backend to disable writes. New backends: implement `Storage`, gate behind a feature in `Cargo.toml`, register in `storage_from_config`.

**Distributed compilation (`src/dist/`, `src/bin/sccache-dist/`).** Two separate binaries share types here: the `sccache` client (feature `dist-client`) and the standalone `sccache-dist` scheduler/server binary (feature `dist-server`). `dist/mod.rs` defines the wire types; `dist/http.rs` is the HTTP transport; `dist/pkg.rs` packages local toolchains icecream-style; `dist/client_auth.rs` handles OAuth flows. The `dist-client`/`dist-server` features are independent — code that depends on both must be gated `#[cfg(all(feature = "dist-client", feature = "dist-server"))]` or sit behind `dist-tests`.

**Configuration (`src/config.rs`).** Single `Config` struct that merges file (`~/.config/sccache/config` or `%APPDATA%`) with environment variables; cache backend selection cascades — env wins over file, and an explicit backend disables disk fallback. See `docs/Configuration.md`.

**Hashing model.** What goes into the cache key: compiler binary digest, normalized arguments, preprocessed source (or direct-mode inputs), and selected env vars. `SCCACHE_BASEDIRS` strips absolute path prefixes before hashing so caches are sharable across checkouts. `SCCACHE_C_CUSTOM_CACHE_BUSTER` mixes in an extra namespace string. See `docs/Caching.md`.

## Repo conventions

- Workspace is single-crate plus `tests/integration/randomize_readdir`; `tests/test-crate` is excluded (it is a fixture, not a member).
- Lints are declared in `[workspace.lints.clippy]` in `Cargo.toml` — when adding code, respect those (no `cloned_instead_of_copied`, prefer `String::new()` over `"".to_string()`, etc.).
- Cargo features are heavily used to slice the build; when touching code that imports an optional dep, gate it with the matching `#[cfg(feature = "...")]`. `scripts/freebsd-ci-test.sh` and `scripts/run-tests.sh` enumerate the feature combinations CI exercises.
- The `unstable` feature gates code that requires nightly Rust.