Skip to main content

Instant tools. Instant builds. One command.

Project description

Soldr / Rust

ChatGPT Image Apr 19, 2026, 09_43_32 PM

A tool to download rust tool sets and aggressive cache your build. 2× faster cross-PR builds via content-addressed caching that swatinem's per-key cache cannot share. GH and local builds. Just add soldr before all your build commands.

Third-party comparison (soldr vs Swatinem/rust-cache vs ...): published from zackees/setup-soldr — see its comparison-cluster workflow and the rendered page once the migration in soldr#674 completes. The legacy https://zackees.github.io/soldr/ page is being repurposed for soldr-internal per-scenario regression history (no third-party comparison surface lives on this repo anymore).

CI Autonomous Release

Performance

soldr vs sccache vs bare cargo - Rust workload soldr vs sccache vs bare cargo - Rust+C workload

performance details

Cold builds are a wash; warm and cross-worktree share are where soldr's wrapper architecture pays off. Full historical trend + interactive view: zackees.github.io/soldr. For the swatinem/rust-cache comparison (GHA target-dir caching, a different layer) see PERF.md.

Instant tools. Instant builds. One command.

soldr = crgx + zccache in a single tool.

Where correct builds meet instant builds.

The point of soldr is not to invent some brand-new primitive. The point is to combine the pieces that already work into one tool that people can actually rely on every day.

zccache is already excellent. crgx already proved the value of instant Rust tooling. soldr turns those into one front door:

  • get the right Rust tool for the job
  • get the right Windows ABI without thinking about it
  • get transparent compilation caching without separate setup

That is the same reason uv is compelling. uv did not win because it invented packaging, virtual environments, or Python installation. It won because it made the whole workflow feel like one tool instead of a pile of separate ones.

soldr aims for the same outcome in the Rust toolchain world.

Current release line:

  • 0.5.x is the secure front-door, tool-fetch, and built-in zccache-backed cache release line
  • 1.0.0-rc remains reserved for broader release hardening and bootstrap validation
  • the supported external integration boundary remains the soldr executable, not the internal Rust crates; see docs/API_BOUNDARY.md
  • practical integration examples for local builds and GitHub Actions live in INTEGRATION.md

Install from npm

npm install -g @zackees/soldr
soldr --version

The npm package is a small launcher that downloads the matching soldr GitHub Release binary for your OS and architecture during install, verifies it against the published SHA256SUMS file, and exposes the soldr command.

GitHub Actions setup

The current GitHub Actions entry point is the public setup-soldr action:

- uses: zackees/setup-soldr@v0
  with:
    cache: true

- run: soldr cargo build --locked --release
- run: soldr cargo test --locked

That action:

  • installs soldr
  • bootstraps rustup into the cached runner-local root when the runner does not already have it
  • preinstalls the exact Rust toolchain from rust-toolchain.toml by default via rustup
  • restores a cacheable runner-local root for Soldr, Cargo, and rustup state
  • restores and saves the Soldr-owned zccache compilation artifact cache under SOLDR_CACHE_DIR by default; set build-cache: false to disable it
  • restores and saves a zccache-owned Rust artifact plan cache by default for no-op CI fast paths; set target-cache: false to disable it or target-cache-mode: full to opt into explicit whole-target caching
  • puts soldr on PATH for later steps

For existing workflows where rewriting every cargo ... command is high-friction, opt into Cargo PATH shims:

- uses: zackees/setup-soldr@v0
  with:
    tool-shims: cargo

- run: cargo build --locked --release
- run: cargo test --locked

The shim mode is off by default. When enabled, the action resolves the real Cargo binary before prepending its shim directory, then exports that real path for Soldr so cargo ... can safely trampoline into soldr cargo ... without recursive PATH lookup.

If your project pins Rust in rust-toolchain.toml, let the action read that file or pass the exact value with toolchain:. Do not preinstall a different generic toolchain such as stable and assume soldr will reconcile it later. The action exports RUSTUP_TOOLCHAIN after installation so later cargo, rustc, and soldr cargo ... steps stay on the toolchain it just installed instead of asking rustup to resolve a pinned file lazily.

On GitHub-hosted runners, this means you usually do not need a separate toolchain setup action for the normal path. The action still uses rustup under the hood today, but it bootstraps rustup itself when the runner does not already have it. On runners without rustup, the action downloads and installs it into the cached runner-local root before provisioning the requested toolchain.

The public action lives in zackees/setup-soldr and is generated from this repository's root action source. This repository dogfoods zackees/setup-soldr@v0 in setup-soldr-action.yml. For fuller examples and fallback patterns, see INTEGRATION.md.

Native vs cross targets

soldr cargo --target ... runs the build through soldr/zccache, but it does not fetch a target's Rust standard library. If the active toolchain does not already have that target installed, the canonical failure is error[E0463]: can't find crate for core/std (or compiler_builtins) at the first compile step.

Native host targets work by default because rustup installs the host triple as part of the toolchain. Cross targets must be declared explicitly. Building aarch64-pc-windows-msvc from a Windows x86 runner, for example, requires provisioning aarch64-pc-windows-msvc before any soldr cargo --target aarch64-pc-windows-msvc invocation.

Two equivalent ways to declare a cross target: declaratively via rust-toolchain.toml's [toolchain].targets (preferred — setup-soldr honors it during toolchain install), or imperatively via soldr rustup target add / soldr toolchain prepare (see #331 and PR #333).

# rust-toolchain.toml — declarative (preferred)
[toolchain]
channel = "1.94.1"
targets = ["aarch64-pc-windows-msvc"]
# CLI — imperative
soldr rustup target add aarch64-pc-windows-msvc
soldr cargo build --target aarch64-pc-windows-msvc
# Orchestrated
soldr toolchain prepare
soldr cargo build --target aarch64-pc-windows-msvc

The canonical multi-platform GitHub Actions tutorial lives in zackees/setup-soldr#90.

For Linux → Windows cross-compilation (GNU via cargo-zigbuild, MSVC via cargo-xwin), see docs/CROSS_COMPILE.md.

CI cache lineage

GitHub Actions caches are not shared across arbitrary sibling feature branches. A workflow run can restore caches from its own branch, the default branch, and for pull requests the PR base branch. It cannot directly restore caches created on another feature branch.

That means Soldr treats main as the canonical warm-cache source:

  • CI runs on pushes to main and feature branches.
  • A feature-branch push can save a branch-local cache entry in its own branch scope.
  • Later pushes and PRs for that same branch restore that branch-local cache first.
  • If the feature branch has no exact cache yet, GitHub falls back to the main cache lineage through the same stable keys.
  • The heavy cache-producing CI runs on branch pushes, not pull_request, so each feature branch gets one useful cache lineage instead of a duplicate PR merge-ref lineage.

In practice this gives the exact parent/child model we want: main acts as the shared parent cache, feature branches read from that parent on miss, and each feature branch may also save its own preferred child cache when the workflow runs on push. Pull requests then reflect the branch-push CI state instead of creating a second heavy cache path. This repository is the first reference implementation of that pattern. For the full wiring and rollout notes, see docs/CI_CACHE.md.

Why soldr exists

On Windows, the real problem is not "how do I cache builds?" or "how do I download a tool binary?" in isolation.

The real problem is that the execution path is messy:

  • the wrong cargo can win on PATH
  • the wrong Windows target can get selected
  • GNU can leak in where MSVC should have been used
  • users end up debugging their toolchain instead of shipping code

soldr exists to make that path boring.

When you run soldr, the tool should do the obvious thing:

  • pick MSVC on Windows by default
  • fetch the tool you asked for
  • cache it locally
  • fetch and manage zccache so Rust builds get transparent caching without manual wrapper setup

If soldr solves that one problem well, it becomes a super tool: the command you reach for first, because it makes the rest of the stack behave.

  • Tool acquisition (the crgx half): Need maturin, cargo-dylint, or any crate binary? soldr fetches a pre-built binary from GitHub Releases in seconds. No cargo install from source. Cached locally for instant reuse. On 0.5.x, this is still an upstream trust decision rather than a repo-side trust guarantee; see docs/TRUST_BOUNDARIES.md.

  • Compilation caching (the zccache half): soldr cargo ... now fetches and manages a pinned zccache release for Rust builds. soldr owns the zccache daemon/session wiring and keeps managed zccache artifacts under Soldr's cache root.

# Build through soldr's front door:
soldr cargo build --release
soldr cargo test
soldr --no-cache cargo test
soldr purge
SOLDR_RUSTC_WRAPPER=sccache soldr cargo build
SOLDR_RUSTC_WRAPPER=none soldr cargo build

# Shorthand: drop the `cargo` prefix for cargo's built-in verbs and for
# any cargo subcommand soldr already prebuilds. `soldr cargo <verb>` is
# preserved as the explicit escape hatch (always works), and the
# collision verbs `clean`, `config`, and `version` keep their
# soldr-native meaning. See docs/API.md "Cargo Verb Shorthand" for the
# full list.
soldr build --release          # == soldr cargo build --release
soldr test --workspace         # == soldr cargo test --workspace
soldr clippy -- -D warnings    # == soldr cargo clippy -- -D warnings
soldr nextest run              # == soldr cargo nextest run

# Fetch and run any Rust tool instantly:
soldr maturin build --release
soldr cargo-dylint check
soldr rustfmt src/main.rs

How it works

soldr is a chameleon binary: one executable that picks its role from argv[1] on every invocation. Three roles:

flowchart TD
    A["soldr &lt;argv[1]&gt; ..."] --> B{"classify argv[1]"}
    B -->|"path to rustc"| C["<b>Cache mode</b><br/>invoked as RUSTC_WRAPPER by cargo.<br/>hash inputs, query cache,<br/>forward to real rustc on miss."]
    B -->|"built-in verb<br/>cargo · rustup · status · cache · ..."| D["<b>Dispatch mode</b><br/>run internal handler,<br/>or exec a toolchain binary<br/>resolved via rustup."]
    B -->|"anything else<br/>maturin · cargo-nextest · cbindgen · ..."| E["<b>Tool-fetch mode</b><br/>resolve via known_tools,<br/>download from GitHub Releases,<br/>exec the fetched binary."]

When you run soldr cargo build, the two other modes both come into play. soldr acts as the dispatch-mode front door, then cargo re-invokes soldr once per crate as the RUSTC_WRAPPER — that second soldr is the cache-mode instance that talks to the managed zccache daemon:

sequenceDiagram
    autonumber
    participant U as User
    participant S1 as soldr (front door)
    participant C as cargo
    participant S2 as soldr (RUSTC_WRAPPER)
    participant Z as zccache daemon
    participant R as real rustc

    U->>S1: soldr cargo build --release
    S1->>S1: dispatch mode: cargo verb
    S1->>Z: start managed zccache if needed
    S1->>C: exec cargo (RUSTC_WRAPPER=soldr)
    loop per crate
        C->>S2: soldr [path-to-rustc] [args]
        S2->>Z: query cache (hash of inputs)
        alt cache hit
            Z-->>S2: cached artifact
            S2-->>C: emit artifact, exit 0
        else cache miss
            Z->>R: forward to rustc
            R-->>Z: fresh artifact
            Z->>Z: store keyed by input hash
            Z-->>S2: artifact
            S2-->>C: emit artifact, exit 0
        end
    end
    C-->>S1: build complete
    S1-->>U: exit

Tool fetches are much simpler — no cargo, no rustc, no wrapper handshake:

soldr maturin build --release
  +-- maturin cached?  --> run instantly
  +-- not cached?      --> download pre-built binary (2s) --> run

Linker speed (the other half of fast CI)

soldr caches rustc invocations. It does not cache the linker step. If your build links many binaries (multiple tests/*.rs files, several [[bin]] targets, examples, benches), the dominant cost is often ld, and zccache will not help with that.

On Linux, switch to the mold linker for ~5-10x faster linking. Add to your repo's .cargo/config.toml:

[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold"]

[target.x86_64-unknown-linux-musl]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold"]

Then in CI, install mold before any cargo step:

- name: Install mold linker
  run: |
    sudo apt-get update
    sudo apt-get install -y --no-install-recommends mold

macOS uses ld64, which is already fast and rarely worth swapping. Windows uses MSVC's linker, which mold does not target.

If you also have many separate test binaries, consider consolidating them under one tests/<name>.rs entry point with sub-modules. Fewer linker invocations is itself a multiplicative win on top of mold.

Design goals

  • One obvious command: Fetch tools, pick the right Windows target, and run through managed zccache through the same entry point.
  • Front-door builds: soldr cargo ... is the primary build UX.
  • Invisible caching: soldr cargo ... uses a soldr-managed zccache by default, with soldr --no-cache cargo ... as the opt-out.
  • Real cache controls: soldr status, soldr cache, and soldr clean report and manage the soldr-managed zccache state, while soldr purge removes all Soldr-managed cache artifacts for bug clearing and benchmarking.
  • One cache boundary: soldr keeps its own tools, zccache session state, and managed zccache artifacts under ~/.soldr/ by default. Use SOLDR_CACHE_DIR to move that root.
  • Disposable-worktree friendly on Windows: for build orchestration, soldr can relocate itself under ~/.soldr/runtime/soldr-self/ so RUSTC_WRAPPER does not keep using a worktree-local soldr.exe; stale runtime copies are cleaned up periodically.
  • Pre-built first: Download a pre-built binary before compiling from source. Fall back gracefully.
  • Cargo-compatible: soldr preserves normal cargo arguments instead of forcing a separate workflow.
  • Cross-platform: Linux, macOS, Windows (x86_64 + aarch64).
  • MSVC by default on Windows: Always targets x86_64-pc-windows-msvc (or aarch64-pc-windows-msvc) unless the active project explicitly selects another target in .cargo/config.toml, .cargo/config, or rust-toolchain.toml. MSVC links against vcruntime140.dll which ships with every modern Windows install. The GNU target requires shipping libgcc_s_seh-1.dll and libwinpthread-1.dll with every binary, which is extra baggage for no benefit. This matches the Rust ecosystem default: rustup, cargo-binstall, and nearly all published release binaries target MSVC. crgx gets this wrong by baking the target at compile time, causing it to look for GNU binaries when compiled under MSYS2.

Architecture

Monocrate. A single Rust crate soldr-cli under crates/soldr-cli/, with four module trees inside it. The earlier four-crate workspace (soldr-core / soldr-fetch / soldr-cache / soldr-cli) was collapsed in 2026-05; the regression guard crates/soldr-cli/tests/monocrate_guard.rs fails the build if anyone reintroduces a second crate.

soldr/
|-- crates/
|   `-- soldr-cli/
|       |-- src/
|       |   |-- core/            # Shared types, config, cache paths (formerly soldr-core)
|       |   |-- fetch/           # Binary resolution + download (formerly soldr-fetch)
|       |   |-- cache_lib/       # RUSTC_WRAPPER + daemon IPC (formerly soldr-cache)
|       |   `-- main.rs + cli/   # Mode detection, dispatch, cargo front door
|       `-- tests/
|-- src/soldr/                    # Python package (maturin bin bindings)
`-- tests/
Module Role
src/core/ Shared types, config (~/.soldr/config.toml), target-triple resolution (MSVC default on Windows), cache paths, error types. No I/O beyond config files.
src/fetch/ Binary resolution. known_tools registry, trust (SHA-256 pins + SOLDR_TRUST_MODE enforcement), rustup auto-bootstrap, resolution chain (local cache → repo lookup → GitHub Releases → extract).
src/cache_lib/ RUSTC_WRAPPER mode: hash inputs (blake3), check ~/.soldr/cache/, daemon IPC (Unix socket / Windows named pipe), LRU eviction, soldr save / soldr load archive transport, auto-GC.
src/main.rs + cli/ Mode detection (chameleon dispatch), clap for built-ins, exec for tool fetch, cargo front door (soldr cargo ...).

A thin src/lib.rs re-exports pub mod core; pub mod fetch; pub mod cache_lib; so the library integration tests can keep use soldr_cli::core::*-style imports. This is not a supported public Rust library API.

Prior art

Built on lessons from:

Security And Verification

  • SECURITY.md describes the current hardening posture and release policy.
  • docs/API_BOUNDARY.md defines the supported machine-facing integration boundary.
  • docs/PYPI_TRUSTED_PUBLISHING.md describes the optional Trusted Publishing path for hardened PyPI wheels.
  • .github/workflows/release-auto.yml is the only release workflow: when a reviewed version bump lands on main, it derives the version from Cargo.toml, reruns the release gate, and performs final publication through the release environment where the release credentials live.
  • RELEASE.md documents the intended maximum-security release setup and owner workflow.
  • docs/RELEASE_VERIFICATION.md explains how to verify published release artifacts.
  • docs/TRUST_BOUNDARIES.md inventories the external systems and artifacts soldr currently trusts, including the current 0.5.x limits of runtime fetched-binary trust.

License

BSD-3-Clause.

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.

soldr-0.7.92-py3-none-win_arm64.whl (9.3 MB view details)

Uploaded Python 3Windows ARM64

soldr-0.7.92-py3-none-win_amd64.whl (10.1 MB view details)

Uploaded Python 3Windows x86-64

soldr-0.7.92-py3-none-manylinux_2_39_x86_64.whl (9.9 MB view details)

Uploaded Python 3manylinux: glibc 2.39+ x86-64

soldr-0.7.92-py3-none-manylinux_2_39_aarch64.whl (9.3 MB view details)

Uploaded Python 3manylinux: glibc 2.39+ ARM64

soldr-0.7.92-py3-none-macosx_11_0_arm64.whl (9.0 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

File details

Details for the file soldr-0.7.92-py3-none-win_arm64.whl.

File metadata

  • Download URL: soldr-0.7.92-py3-none-win_arm64.whl
  • Upload date:
  • Size: 9.3 MB
  • Tags: Python 3, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for soldr-0.7.92-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 e7d2406375901b84b9ed0bda8803b3c2ec83548dc8c6176e352bbc6998b5c3e3
MD5 700e59d8e2a41971e752e9aa890c6bbb
BLAKE2b-256 60c21c817ea320aff2a76605a70412f94eb5dec70d3a77eac470671752381fbb

See more details on using hashes here.

Provenance

The following attestation bundles were made for soldr-0.7.92-py3-none-win_arm64.whl:

Publisher: release-auto.yml on zackees/soldr

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file soldr-0.7.92-py3-none-win_amd64.whl.

File metadata

  • Download URL: soldr-0.7.92-py3-none-win_amd64.whl
  • Upload date:
  • Size: 10.1 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for soldr-0.7.92-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 dc49943975bb77bdab876c9345503abf6a5fae96590dc01bd91dc0896efab2f2
MD5 9d9780476d25e004b593bca11c05dacb
BLAKE2b-256 a253f569e35ab3c47c5b2b3bf519db6a097a9b7bcfe3110a7fb6b0d13c1a2faf

See more details on using hashes here.

Provenance

The following attestation bundles were made for soldr-0.7.92-py3-none-win_amd64.whl:

Publisher: release-auto.yml on zackees/soldr

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file soldr-0.7.92-py3-none-manylinux_2_39_x86_64.whl.

File metadata

File hashes

Hashes for soldr-0.7.92-py3-none-manylinux_2_39_x86_64.whl
Algorithm Hash digest
SHA256 5efc6d947f25094182915784d532278e6b46868b30f1c0ad2eb20ec6b7974d33
MD5 3cb9a78d262f8b050416e59affc2cd79
BLAKE2b-256 d28307eef6315c4ce344e6b009f3bb41e46a1f894b273164a91ea6372534ea05

See more details on using hashes here.

Provenance

The following attestation bundles were made for soldr-0.7.92-py3-none-manylinux_2_39_x86_64.whl:

Publisher: release-auto.yml on zackees/soldr

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file soldr-0.7.92-py3-none-manylinux_2_39_aarch64.whl.

File metadata

File hashes

Hashes for soldr-0.7.92-py3-none-manylinux_2_39_aarch64.whl
Algorithm Hash digest
SHA256 bbf4deba6bf16e36b16b0c91293da06bacb93681a4ae9c2b1a4cdf431ab8ba3d
MD5 58e474a85eac53b4a0f46f25cd1ec77c
BLAKE2b-256 6de743498063184fe85d5fe80cff988c9ad23cec301b920d758a985f4d417c4d

See more details on using hashes here.

Provenance

The following attestation bundles were made for soldr-0.7.92-py3-none-manylinux_2_39_aarch64.whl:

Publisher: release-auto.yml on zackees/soldr

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file soldr-0.7.92-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for soldr-0.7.92-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 d5768d39d0dd476893304e1a886564c3a24d873f4bb0f6cf20d725c7b52387aa
MD5 6e1343c003079afcbd5c61140179ae42
BLAKE2b-256 311bbed512dd8d7a0c10ea8e00543dd7f5a43d23427a8ea953fc130b0c088de2

See more details on using hashes here.

Provenance

The following attestation bundles were made for soldr-0.7.92-py3-none-macosx_11_0_arm64.whl:

Publisher: release-auto.yml on zackees/soldr

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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