Repository navigation
cargo-rail v0.30.0
Cargo-Rail 0.30.0 pairs with cargo-rail-action v10.1.0, which installs it by default.
Highlights
- Compiler reuse covers much more work. One deduplicated local store (
local-cas-v3);
workspace-member Clippy results are stored and replayed;
crates that use a procedural macro directly are reused, bound to everything the macro was observed to read;
registry crates that read package files outsidesrc/are reused;
and registry and git dependencies reuse under an explicitCARGO_TARGET_DIR. - Every stable, beta, and nightly compiler at or above the compiler adapter's minimum now reuses results,
including nightly Cargo's separate metadata and per-unit build directories. - Planning can skip unrelated work exactly.
cargo rail plan evidencerecords which workspace files each compiled unit read;
cargo rail plan --evidencethen skips build, Clippy, and test work for a change no unit reads.
cargo rail plan --caseschecks CI routes before a migration,
andrequire_target_kindsrequires every workspace target of a kind. - Unify and Surface are faster and clearer. Compiler evidence is reused across runs with build scripts and procedural macros,
shared dependencies compile once, failures report one cause and one recovery,
andcargo rail config migratereduces configuration to intentional policy. - Native caching is qualified in CI on IBM Z, IBM POWER, and RISC-V runners.
Upgrade notes
- Caches start cold once. Action keys, registry dependency results, stored compiler evidence,
and results of units that load a procedural macro changed identity; remote caches start cold too.
Before the first build,cargo rail cache clean --scope localremoves the current and retiredlocal-cas-v2stores;
then runcargo rail cache setup. cargo install cargo-railomits the remote cache providers. Add--features s3,azureto a source install that needs them;
release archives include both.- Independent compiler adapter packs must be republished (native input protocol 4); earlier packs are rejected.
- Planning evidence is contract v2; v1 evidence is rejected. Plans remain contract v9.
- Machine output:
--diagnostics-fileis schema 17, andsurface --prepareoutput is contract 3. - Library API breaks struct literals and exhaustive matches for
CargoPrerequisiteConfig,DependencyProof,
EvidenceCacheSummary,RailError,UnifyIssueKind, andIssueSeverity.
Install
Download the archive for your host and SHA256SUMS from this release.
Compare the archive's SHA-256 (shasum -a 256 on macOS, sha256sum on Linux) with its line in SHA256SUMS,
then verify its build provenance:
gh attestation verify cargo-rail-<target>.zip -R loadingalias/cargo-railKeep every file in the archive's cargo-rail/ directory together; it includes the compiler driver used for reuse.
A source build is cargo install cargo-rail --locked --version 0.30.0.
In GitHub Actions, use loadingalias/cargo-rail-action@v10.
All changes
-
Report every Cargo metadata failure with one named cause, one recovery,
and the exact reproduction command.
Named causes are a staleCargo.lock, an unloadable manifest, an unavailable target orrustc,
and a missing Cargo executable.
Cargo's output stays withheld when a credential capability is active, except for manifest failures,
which Cargo reports before it contacts a registry.
config validatenow resolves an existing lockfile with--locked, so a stale lockfile fails validation.
It reports whether it checked the Cargo workspace or only the schema,
in text and in the JSONevidencefield, and addshelpto each issue. -
Workspace-member
cargo clippyresults are now stored and replayed,
so Clippy aftercargo cleanrestores the member diagnostics instead of linting every member again.
A Clippy result binds theclippy-driverbytes, the arguments Clippy appends, the environment it reads,
every configuration file candidate it checks up to the one it loads, and the manifests, lockfile,
and Cargo configuration thatclippy::cargolints read throughcargo metadata.
A cold miss runs a new resolution phase of the compiler driver beside Clippy to record the crates it
selects.
That phase needs the new native input protocol,
so independent compiler adapter packs from earlier releases are rejected until they are republished.
Under--root-portability remap, a Clippy result is shared across checkout roots: paths below the repository, the Cargo home,
and the compiler sysroot are bound relative to those roots.
Linked Clippy output, such as a member's build script, aSYSROOToverride,
and a configuration file outside the repository keep running Clippy normally. -
On hosts whose kernel stamps file changes with a coarse clock, such as IBM Z,
a capture waits until a just-changed input is settled,
and the digest memo measures age from the change time, which no user can set back.
A same-size rewrite within one clock tick can no longer reuse a stale digest
or hide from revalidation.
The same wait applies to the directories that bind a followed root link
and to the native compiler driver's runtime layout, so a link replaced within one tick is rejected.
Cache setup, the distributed worker,
and the compiler driver likewise settle each installed component, certificate,
and compiler library before binding its generation. -
Cold compilations on macOS start rustc sooner.
Each cache miss used to stage a fresh copy of the native input driver, probe it,
and rehash the compiler library before running the compiler;
macOS also scanned every new driver copy on its first launch.
The driver is now staged once per store and re-authenticated on every use,
one successful probe is recorded under the exact driver and compiler-library digests,
and the library digest is memoized by its stable file generation.
Across cross-target Clippy, the wrapper's work
before rustc fell from a median of 1,069 ms to 137 ms per miss. -
unify.compiler_targetsaccepts"all"(the default), an exact target list, or"none".
"none"keeps every resolution target but acquires no compiler evidence,
so a host that cannot compile a foreign target can still run Unify without deleting that target.
An empty list, which earlier releases printed as the default, still selects every target,
andconfig printnow writes"all".
Unify checks each target that needs new evidence before acquisition: an uninstalled target library,
or a doctest target whose linker cannot link a probe, stops with the target, the cause,
and the recovery choices.
unify doctorreports per-target readiness and the targets left unobserved. -
Add
cargo rail config migrateto reduce a configuration file to intentional policy.
It removes a setting only when removing it leaves the effective policy unchanged,
which covers explicit defaults, savedconfig printoutput, and older spellings such asunify.compiler_targets = [].
Comments, ordering, and every other setting are kept.
A file containing only defaults is deleted when no other configuration file would take its place.
The command previews by default;--checkexits 1 when a migration is pending,
andconfig migrate applyrevalidates drift before writing.
apply --planaccepts the saved JSON preview. -
Replace the local compiler cache with one deduplicated
local-cas-v3store: identical outputs are stored once,
a miss no longer scans the whole store, and a full store collects to 90% of its budget,
least recently used first.
cargo build,cargo test, andcargo clippynow share dependency results,
and terminal width affects a result only when it rendered diagnostics.
On Linux and macOS, unchanged input files are not rehashed.
cache profilesreports each profile's usage against its budget,cache setupapplies a lowered budget immediately,
andcache clean --scope localpreviews and removes the retired v2 store.
Cache keys changed, so the first build and remote caches start cold once after upgrading. -
Reject invalid configuration before any Git or Cargo subprocess starts,
for explicit and discovered policy alike.
config validate,print,explain,locate, andcleannow read the Cargo workspace root's policy, like consuming commands,
and independent configuration errors are reported together. -
Unify and Surface keep compiler evidence
and the sysroot fingerprint memo in the enrolled workspace's cache profile instead of rewriting the
unbound default store on every run.
An explicitCARGO_RAIL_CACHE_DIRstill selects its own store,
a workspace without a profile still uses the default store,
and a command that cannot read its enrollment rehashes instead of writing either store. -
Registry and git dependencies reuse results under an explicit
CARGO_TARGET_DIRor build directory.
Cargo compiles those packages inside their unpacked source,
so the wrapper found no enrolled workspace and every one of them bypassed;
it now uses the workspace Cargo started in (PWD). -
Handle dependencies that only a feature enables when Unify and Surface acquire compiler evidence.
Cargo's default resolution omits them,
but a view that enables the feature compiles them and runs their build scripts.
Unify no longer fails with "absent from the captured package graph"
for an optional local path dependency,
and views that run such a build script are now stored and reused.
The extra all-features resolution is loaded only
when the lockfile names packages the default resolution lacks. -
Keep Unify and Surface compiler evidence reusable in workspaces with Git dependencies.
A Git source pinned to its exact resolved commit now identifies its content
as a registry checksum does.
Before, one Git dependency made every view in the workspace miss withexternal_source_digest_unavailable.
Other external sources without a checksum still bypass reuse. -
Runtime evidence recognizes the
linux-vdso64.so.1image that IBM Z and 64-bit IBM POWER kernels map,
so native reuse no longer rejects every executable probe on those hosts. -
Unify and Surface compiler evidence now binds each view to the locked packages its package can
reach, instead of the wholeCargo.lock.
Updating a dependency that only one member uses reacquires that member's views and reuses the rest.
A lockfile whose references Cargo-Rail cannot resolve exactly, or a v1 lockfile,
still binds the whole file.
Stored evidence starts cold once after upgrading, because its keys changed. -
Every stable, beta, and nightly compiler at
or above the compiler adapter's minimum now reuses results:
the compiler driver builds against each compiler's internal API,
and CI builds and tests it against the current stable, beta, and nightly.
cargo rail cache readyinstallsrustc-devfor the workspace-selected rustup toolchain when it is missing,
so the compiler driver can be prepared for that toolchain.
Nightly Cargo builds rlibs without embedded metadata
(-Z embed-metadata=no)
and passes each linked dependency as an rlib and its rmeta; the native cache binds that pair,
so crates that link a library reuse results instead of bypassing,
and a result without its rmeta is refused.
Planning evidence locates a fresh binary's own dep-info in nightly Cargo's per-unit build
directories instead of widening to Cargo's dependency superset. -
Make the remote cache providers and the cache benchmark optional Cargo features.
cargo install cargo-railno longer builds the AWS and Azure SDKs: 88 of 327 dependency packages existed only for them.
On Apple silicon a clean release build ofcargo-railused 32% less CPU,
and the binary shrank from 45 MB to 31 MB.
Native release archives still include both providers.
Add--features s3for S3 and R2 or--features azurefor Azure Blob to a source build that needs a remote cache;
a build without the provider rejects its URL during setup and names the missing feature.
Thebenchmarklibrary module and its embedded workload now require thebenchfeature,
as the benchmark binary already did. -
cargo rail plan --cases FILEcompares reviewed path cases with planner decisions before a CI migration.
Each case is planned as an unreferenced commit on top ofHEAD, so the worktree, index, refs,
and untracked files neither change nor affect the result.
The report marks each required item as direct or conservatively expanded and names the reasons.
A false negative names the missing work ID and exits1. -
Keep package-wide planner work when target selectors cover only part of the selected packages,
and compareplan --allagainstHEAD.
Bind a--configoverride into release drift checks, and fail Surface closed when compiler facts are absent. -
Keep every Cargo unit in scope when one change edits both a target root and a non-Rust file
that no evidence attributes: the unattributed file now widens Cargo work to the workspace instead of
only the edited package.
Packaging work also selects each workspace member whose directory holds a changed file. -
cargo rail plan evidence --work WORK_ID --output FILE -- CARGO_ARGSrecords portable planning evidence from the ordinary build ofHEAD:
the workspace files each compiled unit read, and each build script's rerun inputs.
With that evidence,cargo rail planskipscargo.build,cargo.clippy, orcargo.testfor a change that no recorded unit reads, such as a README,
and selects the readers of a changed input and their dependents.
Recording runs Cargo with a recorder asRUSTC_WRAPPERand changes neither outputs nor freshness,
so it can replace the job's build step; fresh units are read from the dep-info Cargo keeps.
An unobserved member or unit, an untracked read,
or a missing build-script input leaves the work item incomplete.The evidence contract is now
planning-evidence-v2,
which adds directory inputs for build-script rerun directories and package sources.
Plans listplanning-evidence-v2identities, and v1 evidence is rejected.
--evidencecan be repeated, one file per work item; each file is validated separately,
so a stale or foreign file widens only the work it describes.
An added or changedclippy.tomlor.clippy.tomlnow selectscargo.clippy. -
A Cargo prerequisite edge can require every workspace target of a kind:
require_target_kinds = ["cdylib"]builds each plugin library that a test loads at run time,
so a new plugin needs no configuration edit.
A kind that selects no workspace target is rejected.
The library'sCargoPrerequisiteConfigadds the publicrequire_target_kindsfield, which breaks struct literals. -
Run build scripts during Unify
and Surface compiler evidence with the environment plain Cargo gives them.
Cargo-Rail's private session variables, such asCARGO_RAIL_COMPILER_OBSERVATION_DIRECTORY, no longer reach build scripts;
each view's wrappers read a private context file instead.
Unify views also keep a stable workspace-wrapper path, which Cargo hashes into each unit's-C metadata,
so compiled units and native cache results stay reusable across runs. -
Crates that depend directly on a procedural macro, such as
async-traitorpaste,
are now stored and reused like crates that use a macro through a re-export.
On every miss, the compiler driver observes what each loaded macro reads through the C library and,
on Linux, through the kernel.
A result then binds every file, directory listing, absent path, and variable the macro read,
so a hit stays valid even when the macro reads an input that no build script declares,
which Cargo's own freshness misses.
A macro that writes files, opens network connections, starts an unmodeled process,
reads outside the repository, or cannot be observed keeps compiling normally
and names the reason (procedural_macro_*).
Linux kernels older than 5.5, containers that block seccomp user notification,
and hosts other than Linux and macOS keep macro consumers on the normal compiler path.
This needs native input protocol 4,
so independent compiler adapter packs from earlier releases are rejected until they are republished,
and results of units that load a procedural macro start cold once.
Cache hits are also faster: captured source trees
and dependency directories each keep one digest record, native search directories reuse it,
and Rust library selection resolves each directory once.
A workspace-member Clippy hit in this repository fell from a median of 330 ms to 130–185 ms. -
Compiler results for registry crates that read a package file outside their source directory,
such as#![doc = include_str!("../README.md")], are now stored and reused instead of bypassing,
because the whole unpacked package is part of their key.
Registry dependency results start cold once.
cache statusreportsrecent_evictionsand a budget-pressure line when collection evicts results within a day of their last use,
which means the budget did not hold the working set in use. -
cargo rail plan --verifynow rejects a saved plan whoseinputs.platformdiffers from the current host.
Before, a plan's platform label was checked only through its target identity,
so a plan re-signed with another platform label still verified. -
Compile each shared dependency once when Unify and Surface acquire compiler evidence.
Views now run one Cargo process at a time in a shared sandbox,
and Cargo applies its own job parallelism, includingbuild.jobs,CARGO_BUILD_JOBS, and an inherited jobserver.
Before, parallel views each rebuilt the shared dependency graph in a private sandbox.
On a 14-package workspace with 20 evidence views,
a cold Unify check used about 5.5 times less CPU with the same decisions.
The--diagnostics-fileschema is now version 17: it removesconfigured_work_permits,max_nonwaiting_cargo_views, and thework_permit_*counters, and addsdependency_compilations,repeated_dependency_compilations, andartifact_high_water_bytestocompiler_acquisition.
A repeated compilation now means the same unit configuration compiled again;
a dependency rebuilt with other features is a different unit.
surface --prepareoutput is contract version 3: itsacquisitionobject removeswork_permits. -
Surface fact reuse now follows the same input proof as Unify evidence.
A stored fact set records the files and environment variables rustc read for its units
and the declared rerun inputs of every build script in its view, and is reused only while they hold.
This fixes stale Surface reports after a change to a file included from outside the package,
and lets Surface reuse facts in workspaces with build scripts and proc macros.
Non-empty fact sets stored by earlier versions are not reused.
Unify and Surface also reuse evidence in a workspace below its repository root;
rustc invocations there were recorded against the wrong root and never matched their Cargo units. -
Compile each unit once when Surface acquires typed compiler facts.
Typed views, including doctest views, now share one sandbox and a stable workspace wrapper.
Before each view, Cargo-Rail removes only that view's package from the sandbox,
so Cargo recompiles the targets whose facts the view needs and keeps every other unit fresh.
Before, each view used a new wrapper path, which Cargo hashes into-C metadata,
so every view recompiled every workspace member in its graph.
On a 14-package workspace, a coldsurfacerun fell from 287 to 148 compiler invocations
and from 124 s to 84 s of CPU, with an identical report. -
Cargo-Rail now finds its release components beside the real executable
when it runs through a symlink.
Before, on macOS,cargo rail cache setupthrough a launcher symlink onPATHreported the compiler worker as unavailable
and asked for a reinstall. -
Typed doctest collection stages a private copy of
rustdocinstead of a symlink.
Whererustdocfinds its compiler library through an ELFDT_RPATH, as on IBM Z,
the symlink loaded the shared toolchain's library,
so doctests compiled with the sharedrustcand produced no compiler facts. -
Reuse Unify compiler evidence in workspaces with build scripts and proc macros.
Each view records thererun-if-changedpaths andrerun-if-env-changedvalues of every build script in its Cargo graph,
and is reused while Cargo would keep those scripts' output.
A changed declared input reruns only the affected views.
Views are stored as they complete, so a failed or interrupted run keeps them for the retry,
and a corrupt stored view no longer hides valid ones.
evidence_cacheentries addpublication_bypasses, which name why a view was not stored.
Stored compiler evidence starts cold once after upgrading.
The library'sDependencyProofandEvidenceCacheSummaryadd public fields, which breaks struct literals. -
Report a failed Unify compiler-evidence view with one cause, one recovery section,
and the view's Cargo command as a reproduction.
JSON errors addfailure_class:build_script,source,toolchain,cargo_rail, orcargofor compiler evidence, andlockfile,manifest,toolchain, orcargofor Cargo metadata.
JSON errors no longer contain Cargo or build-script output.
Text mode shows the last lines of a failing build script's stderr,
with inherited environment values replaced by their names,
and Cargo's complete output with--verboseunless a Cargo credential capability is active.
A build-script failure names the environment variables the script declares, never their values.
Unify keeps progress on stderr in JSON mode, reports Cargo file-lock waits as they happen,
and prints aStill running:line when a phase is silent for 30 seconds.
An interrupted compiler acquisition reports theinterruptedclass and the phase it stopped.
--diagnostics-fileoutput addsprogress_phaseswith per-phase durations.
The library addsRailError::FailureandFailureClass.
AddingRailError::Failurebreaks exhaustive matches onRailError. -
cargo rail unifynames every pending edit class on one screen: dependencies, inherited package fields,
pruned features, and therust-versionit writes.
Declarations that Unify keeps on purpose are no longer reported as warnings;--explaingroups them by reason,
and JSON reports them with kindPreservedand severityInfo.
A build script that cannot find a native tool through thecc,cmake, orpkg-configcrates,
or source that reads a missing file, now names that tool or file and the recovery.
Identical compiler errors from one view appear once.
Afterunify apply, the next step no longer names this repository's own test profile.
The library'sUnifyIssueKind::PreservedandIssueSeverity::Infovariants break exhaustive matches. -
Upgrades now explain what earlier releases removed.
A removed command such ascargo rail runorcargo rail release finalizenames the release that removed it and what to run instead.
A removed configuration key names its release and replacement in every command,
andcargo rail config migratepreviews and applies its removal alongside default pruning.
Every unknown or removed key in a file is reported at once.
Planning a change that migrates such keys away no longer fails on the base commit's policy. -
cargo rail config validatereports each independent configuration error as its own issue,
so the summary count and JSONerrorsmatch the listed errors. -
On Windows, a Unify compiler-evidence view whose source reads a missing file now names that file
and its recovery, as on other hosts, instead of reporting only the compiler error.