mod key;
mod snapshot;
mod units;
mod wrapper;
use std::env;
use std::process::exit;
const WRAPPER_MARKER: &str = "CARGO_TURBO_WRAPPER";
fn main() {
if env::var_os(WRAPPER_MARKER).is_some() {
exit(wrapper::run());
}
let args: Vec<String> = env::args().skip(1).skip_while(|a| a == "turbo").collect();
match args.first().map(String::as_str) {
Some("--help") | Some("-h") | None => {
print_help();
exit(0);
}
Some("--version") | Some("-V") => {
println!("cargo-turbo {}", env!("CARGO_PKG_VERSION"));
exit(0);
}
Some("clean") => exit(snapshot::clean()),
Some("status") => exit(snapshot::status()),
Some("prepare") => exit(prepare(&args[1..])),
Some("store") => exit(store(&args[1..])),
_ => exit(run_build(&args)),
}
}
fn run_build(args: &[String]) -> i32 {
let plan = match key::Plan::resolve(args) {
Ok(plan) => plan,
Err(e) => {
eprintln!("cargo-turbo: {e}");
return snapshot::forward_plain(args);
}
};
let (hit, mut freshness) = snapshot::restore(&plan);
if hit == snapshot::Hit::None {
freshness = match env::var("CARGO_TURBO_FRESHNESS").as_deref() {
Ok("checksum") => snapshot::Freshness::Checksum,
_ => snapshot::Freshness::Mtime,
};
units::seed(&plan, freshness);
}
let status = snapshot::forward(&plan, args, freshness);
if status == 0 {
if hit != snapshot::Hit::Exact {
snapshot::save(&plan, freshness);
}
units::record(&plan, freshness, hit != snapshot::Hit::Exact);
}
status
}
fn prepare(args: &[String]) -> i32 {
let plan = match key::Plan::resolve(args) {
Ok(plan) => plan,
Err(e) => {
eprintln!("cargo-turbo: {e}");
return 0;
}
};
let seeded = units::seed(&plan, snapshot::Freshness::Mtime);
if seeded == 0 {
eprintln!("cargo-turbo: nothing to supply");
}
0
}
fn store(args: &[String]) -> i32 {
let plan = match key::Plan::resolve(args) {
Ok(plan) => plan,
Err(e) => {
eprintln!("cargo-turbo: {e}");
return 0;
}
};
units::record(&plan, snapshot::Freshness::Mtime, true);
eprintln!("cargo-turbo: stored the third-party units of this build");
0
}
fn print_help() {
println!(
"\
cargo turbo — faster cold Rust builds, without patching cargo or rustc
USAGE:
cargo turbo <cargo-command> [args…] run a cargo command, accelerated
cargo turbo status what is stored, and how much space
cargo turbo clean remove every snapshot and unit
FOR A BUILD THIS CANNOT RUN ITSELF:
cargo turbo prepare <cargo-args…> supply prebuilt dependencies, then stop
cargo turbo store <cargo-args…> add this build's dependencies to the store
Use these when cargo is invoked by a script or another build tool. Pass the
same arguments the build will use, since they say which profile and target it
is for. Between the two, run the build however you already do.
cargo turbo prepare build --release --target x86_64-unknown-linux-musl
./my-build-script
cargo turbo store build --release --target x86_64-unknown-linux-musl
EXAMPLES:
cargo turbo check --workspace
cargo turbo build --release
WHAT IT DOES:
Restores a previously recorded target directory when the inputs that
produced it are unchanged, supplies dependencies other projects on this
machine have already built, and gives each rustc invocation a share of the
machine based on how many others are running at that moment.
Cargo still decides what is stale, so an edited file is always rebuilt.
ENVIRONMENT:
CARGO_TURBO_DIR where snapshots live (default: cache dir)
CARGO_TURBO_JOBS cores to divide between invocations (default: all)
CARGO_TURBO_THREADS set to 0 to leave rustc single-threaded
CARGO_TURBO_NEAR set to 0 to require an exact key, never a near match
CARGO_TURBO_KEEP snapshots kept per workspace and profile (default: 5)
CARGO_TURBO_FRESHNESS set to checksum to judge freshness by content instead
of timestamps: better for a cache unpacked over a
fresh clone, worse for sharing between projects
CARGO_TURBO_OFF set to 1 to forward to cargo unchanged
CARGO_TURBO_TIME set to report how long each phase of this tool took"
);
}