[bldr]docs
Build APIbldr/rust-tools

CargoConfig

How a Cargo is configured. image and source are required, so

interface in bldr/rust-tools

How a Cargo is configured. image and source are required, so omitting either is a compile error rather than a failure at build time.

Properties

binary: boolean | CargoBinaryOptions | WithId<CargoBinaryOptions>[]

property

The binaries this crate produces, registered as output directories.

  • omitted — none, because a crate that produces no binary is ordinary and guessing a [[bin]] name would be worse than saying nothing;
  • an options object — one output at <scope>/binary;
  • a list — one per entry at <scope>/binary/<id>.

Declaring them here is also what lets Cargo.binary be asked for one by name rather than re-described at every call: the set is known, so an unknown name is an error with the real list in it.

See CargoBinaryOptions, WithId.

cache: false

property

Set false to run every command with a cold /target, instead of the per-command incremental cache volume this builder mounts by default.

The crates a command compiles are not a cache: they are the fetch step's output, an input like the source tree, and are mounted either way.

A cache cannot change what a build produces — its content never reaches an invocation cache key — so this exists for the case where that guarantee is the thing under test, not for correctness in ordinary builds.

check: boolean | CargoOptions | WithId<CargoOptions>[]

property

The check targets to register on scope, automatically.

Every crate wants one and almost none wants a different one, so it is a default rather than a line in each member's build file. Eight members wrote the identical check registration by hand before this existed.

  • omitted — one target at <scope>/check, with the default options;
  • false — none, for a member whose sources cannot be checked in isolation;
  • an options object — one target at <scope>/check, with those options;
  • a list — one target per entry at <scope>/check/<id>, for a crate that must compile several ways (feature combinations, target triples) and wants each to fail separately.

A list rather than a map keyed by name, because a map and a single options object cannot be told apart without guessing at their contents — { features: … } and { features: { … } } differ only in a nesting level. Array.isArray needs no guess, and the name rides along as id.

See CargoOptions, WithId.

clippy: boolean | CargoClippyOptions | WithId<CargoClippyOptions>[]

property

The cargo clippy gates to register on scope, in the same shapes as check — true for one at <scope>/clippy with the defaults, an options object to configure it, a list for one per entry at <scope>/clippy/<id>.

Opt-in rather than on by default, unlike check: clippy is a style gate whose findings move with the toolchain, so switching it on for every crate at once would turn a rustup bump into a repo-wide build failure. A crate opts in when its lints are clean and it intends to keep them that way.

See CargoClippyOptions, WithId.

coverage: boolean | CargoCoverageOptions | WithId<CargoCoverageOptions>[]

property

The coverage-data outputs to register on scope.

  • omitted or false — none;
  • true — one output at <scope>/coverage, with the defaults;
  • an options object — one output at <scope>/coverage, measured that way;
  • a list — one per entry at <scope>/coverage/<id>, for a crate whose coverage is worth measuring under more than one feature set.

Opt-in, like clippy and fmt rather than default-on like check — and for a blunter reason than either. Instrumented code is markedly slower to compile and slower to run: every crate in the graph is rebuilt with -C instrument-coverage, and each test binary writes a profile as it goes. Switching that on for every Rust member in the repo would roughly double what a full build costs, permanently, to produce a number most of those members have nobody to read. A crate opts in when someone is actually using the figure.

The output is data, not a gate. It is registered as an output directory, not a test, so it never fails a build for being low — and failing tests do not suppress it either, since coverage of a red run is still the measurement that was asked for. Whether the tests passed is the test target's answer, and duplicating that verdict here would only create a second place for it to disagree with itself.

See CargoCoverageOptions, WithId.

defaults: CargoOptions

property

Options every command inherits, unless it overrides them.

For the settings that are a property of the crate rather than of one command. A crate that only ever builds for one target triple says so once here, instead of repeating it on check, test, doc and binary and getting it wrong on the fifth.

See CargoOptions.

defaults: { target: "x86_64-unknown-linux-musl" },
binary:   { binaryName: "init", profile: "release" },   // musl, inherited
test:     { bins: true },                              // musl too

Merged per key, not deeply: a command that names features replaces the default list rather than adding to it, because a half-inherited feature set is far harder to reason about than an explicit one.

dependencies: CargoDependency[]

property

Sibling crates to build against — see CargoDependency.

Each one is mounted and patched in, so the crate's own manifest can keep depending on it by version alone and stay publishable. Pass another Cargo directly, or any { crateName, source } for a crate that has no builder of its own.

dependencies: [protoLib, { crateName: "helper", source: helper.rootDirectory }],

Works for a single crate and for a workspace alike: the patches are written at config level rather than into a manifest, so a source tree that already declares its own [patch.crates-io] is left untouched.

doc: boolean | CargoDocOptions | WithId<CargoDocOptions>[]

property

The rustdoc output to register on scope, in the same shapes as check. Registered as a documentation output, so a consumer can find it by role rather than by guessing its name.

See CargoDocOptions, WithId.

environment: Record<string, string>

property

Environment variables set on every cargo pod this builder runs — the pod-level sibling of mounts, for values that belong to the build rather than the image (BLDR_PROTO_DIR pointing at a mounted proto tree, say). Image-wide env — PATH, anything an image layer's own commands need — stays on CargoToolchainOptions.env.

fmt: boolean | CargoOptions | WithId<CargoOptions>[]

property

The cargo fmt --all --check gates to register on scope, in the same shapes as clippy, and opt-in for the same reason.

Check only — this never rewrites the source tree. A build runs on a content-addressed copy of the sources, so formatting them there would produce a tree nobody sees; the useful answer is whether what is committed is formatted.

See CargoOptions, WithId.

lsp: boolean | CargoOptions | WithId<CargoOptions>[]

property

The editor language servers to register, in the same shapes as check.

On by default, because an editor wants one for every Rust crate and the analyzer has to agree with the build about toolchain, source layout and manifest location — which this builder already knows and an editor does not. A list is for a crate whose feature combinations disagree enough that one analyzer view would be wrong for half of them.

See CargoOptions, WithId.

manifestDir: string

property

The crate or workspace root within source, when the manifest is not at the mount root.

This is what lets an existing multi-crate workspace be built as it stands. CargoConfig.deps cannot, because it wraps the crate in a generated workspace and cargo forbids nesting one workspace inside another. A workspace that already patches its siblings by relative path just needs them present at those paths, which is a matter of laying the tree out — Directory.merge(a.at("x"), b.at("y")) — and pointing this at the root crate.

// source holds `engine/`, `engine-macros/` and `util/` side by side
manifestDir: "engine",

mounts: Record<string, Directory>

property

Extra read-only trees to mount, by absolute container path → tree. For inputs a build reads from outside the source tree (a include_str! that escapes the crate, a fixture directory).

See Directory.

package: boolean | CargoOptions | WithId<CargoOptions>[]

property

The package outputs to register, in the same shapes as check.

Off by default: most crates are built, not published, and a packaging run that nobody consumes is cost with no reader.

See CargoOptions, WithId.

resources: DagResources

property

What each of this builder's runs is admitted against and held to — see DagResources.

Worth setting for a large workspace, for the same reason CargoOptions.jobs is. A node admits every DAG that declares nothing against its default share (a quarter of what it can hand out), and holds it to that as a hard limit, page cache included: a compile that wants more has its cache reclaimed over and over and, when its compilers alone exceed the share, is killed. Per command, CargoOptions.resources wins over this.

See DagResources.

sccache: false | "read-only"

property

The node's shared compile cache (sccache — see docs/sccache.md), on by default wherever the node can serve it.

Every compiling command's pod asks the node for sccache, and cargo runs rustc through the wrapper (build.rustc-wrapper in the pod's own $CARGO_HOME/config.toml, so the source tree is never touched and a build that sets RUSTC_WRAPPER itself keeps it). Entries live in the node's store, so a crate compiled by any pod of any build on the cluster is a download for the next one with the same inputs.

  • omitted — read-write, on a node that advertises pod.sccache; on one that does not, the build runs exactly as it did before sccache existed;
  • "read-only" — use entries, never store any;
  • false — off. cache: false (cache) turns it off too: that setting asks for every command to run cold, and a compile cache is a cache.

It coexists with the /target cache volume rather than replacing it. The volume keeps one command's whole target dir on one node — fresh crates are not recompiled at all, and workspace members build incrementally. sccache shares compiled crates across crate graphs, commands and nodes, which is what a cold or evicted volume needs.

Incremental compiles are not cacheable: sccache declines any rustc invocation carrying -C incremental, which cargo passes for workspace members in the dev profile. Those stay the volume's job; dependencies (and every release-profile crate) go through sccache. A builder whose environment sets CARGO_INCREMENTAL=1 gets no sccache at all — the wrapper refuses to run under it, and would fail every compile.

Like a cache volume it cannot change what a build produces: only the request reaches a pod's spec, never the cache's content.

scope: Scope

property

Where this Cargo's work appears in the build tree.

A Cargo makes its own Cargo child of whatever it is given, and one subscope per command (build, test, clippy, doc, package), so a member that runs several of them gets a readable subtree.

Required. There is no sensible default: a builder with nowhere to put its work ends up wherever its first consumer happens to be, which is how a shared task came to be attributed to an unrelated part of the tree.

See Scope.

source: Directory

property

The source tree: a single crate's root, or a workspace root.

See Directory.

test: boolean | CargoTestOptions | WithId<CargoTestOptions>[]

property

The test targets to register on scope, automatically.

The same shapes as check, and for the same reason: every crate wants its tests run and almost none wants them run differently, so it is a default rather than a line in each build file.

  • omitted — one target at <scope>/test;
  • false — none, for a crate whose tests cannot run here;
  • an options object — one target at <scope>/test, run that way;
  • a list — one per entry at <scope>/test/<id>, so a crate that must be tested several ways gets a separate verdict for each rather than one that stops at the first failure.

See CargoTestOptions, WithId.

toolchain: any

property

The toolchain to build with.

A CargoToolchain normally; a bare container image is accepted for a toolchain assembled some other way, as long as cargo is on its PATH.

workspace: boolean

property

Scope every command to the whole workspace (--workspace). Ignored when CargoConfig.package is set.

For a test target this is the safe default: Cargo resolves the member list from the workspace manifest at build time — including glob members (crates/*) and path dependencies pulled in implicitly — so a crate added tomorrow is selected with no build definition to update.

On this page