Skip to content

Conversation

@davidtwco
Copy link
Member

@davidtwco davidtwco commented Oct 31, 2025

Add a new Cargo configuration option, build-std = "always|never", which will unconditionally rebuild standard library dependencies. The set of standard library dependencies can optionally be customised with a new build-std-crates option. It also describes how Cargo (or external tools) should build the standard library crates on stable (i.e., which flags to pass and features to enable).

This proposal limits the ways the built standard library can be customised (such as by settings in the profile) and intends that the build standard library matches the prebuilt one (if available) as closely as possible.

This RFC is is part of the build-std project goal and a series of build-std RFCs:

  1. build-std context (build-std: context #3873)
  2. build-std="always" (this RFC)
  3. Explicit standard library dependencies (build-std: explicit dependencies #3875)
  4. build-std="compatible" (RFC not opened yet)
  5. build-std="match-profile" (RFC not opened yet)

There is also a Zulip channel where you can ask questions about any of the build-std RFCs. This series of RFCs was drafted over many months with the help of stakeholders from many Rust project teams, we thank them for their help!

Rendered

@davidtwco davidtwco added T-libs-api Relevant to the library API team, which will review and decide on the RFC. T-compiler Relevant to the compiler team, which will review and decide on the RFC. T-cargo Relevant to the Cargo team, which will review and decide on the RFC. labels Oct 31, 2025
@ehuss ehuss moved this to RFC needs review in Cargo status tracker Nov 4, 2025

- [*Allow reusing sysroot artifacts if available*][future-reuse-sysroot]

[Opaque dependencies]: https://hackmd.io/@epage/ByGfPtRell
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has moved to a more official place

Suggested change
[Opaque dependencies]: https://hackmd.io/@epage/ByGfPtRell
[Opaque dependencies]: https://github.com/rust-lang/cargo/issues/3573#issuecomment-3498262549


> [!NOTE]
>
> Inspired by the concept of [opaque dependencies][Opaque dependencies], the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicoburns brought up on reddit the idea of cargo clean not affecting opaque dependencies, requiring some other step to clean them (maybe a cargo clean -p std). Alternatively, we may get this "for free" with rust-lang/cargo#5931.

I lean towards keeping cargo clean the same for now but might be worth calling this question out somewhere.


```toml
[build]
build-std = { when = "always", crates = "std" }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

crates being plural but only taking a single string argument rather than a list/table reads a bit odd. Not sure what to do about that given that only specifying the "max" crate to be build and implying dependencies sounds reasonable.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe build-std.up-to = "std"? Since crates = "std" is the default, it makes a lot of sense for people to say, for example, build-std = { when = "always", up-to = "alloc" }.

@ehuss
Copy link
Contributor

ehuss commented Dec 11, 2025

As a heads up, we are planning to start an FCP proposal on this RFC shortly after #3873 (build-std context) has been approved.

invoked ([?][rationale-implied-bootstrap]). Cargo will not need to use
`RUSTC_BOOTSTRAP` when compiling the standard library with a stable toolchain.
The standard library's dependencies will not be permitted to use build probes to
detect whether a nightly version is being used.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went through all build scripts in dependencies we have. The libc crate detects both the rustc version and if it is a nightly version. It seems like it doesn't actually use the latter for anything though. The object crate also detects rustc version. Nothing else seems to be detecting the rustc version that I could see.

Ideally, a crate should be able to provide alternate memory symbols and disable
`compiler_builtins`' symbols for the entire crate graph by enabling a feature
(e.g. `std`/`libc` could do this) - this is what an `external-mem` feature
enables.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Until external-mem automatically gets enabled for all targets with a libc implementation, this inversion of the mem feature would cause a silent performance hit for those targets, while previously you would get a loud failure, which IMO is preferable.

[preventing-implicit-sysroot-dependencies]: #preventing-implicit-sysroot-dependencies

Cargo will pass a new flag to rustc which will prevent rustc from loading
top-level dependencies from the sysroot ([?][rationale-root-sysroot-deps]).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--sysroot /dev/null is already effectively that except for that also blocking discovery of self-contained artifacts.

Vendoring the standard library is possible since it currently has its own
workspace, allowing the dependencies of just the standard library crates (and
not the compiler or associated tools in `rust-lang/rust`) to be easily packaged.
Doing so has multiple advantages..
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fully agree we should be vendoring the standard library dependencies. Actually implementing that is non-trivial however: #t-cargo > vendoring for -Zbuild-std Setting the vendoring using .cargo/config.toml doesn't work and I couldn't figure out how to make -Zbuild-std respect it. Next thing I want to try is patching library/Cargo.toml to add a [patch.crates-io] section. Perhaps the standard library workspace is still considered enough of a workspace by -Zbuild-std for that to work.


For example, Rust's project goal to enable Rust for Linux to build using only a
stable toolchain would require that it be possible to build `core` without
nightly.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative design would be to have a rustc flag which makes it build all requested standard library crates and put them in a specified directory. And then another flag to load standard library crates from said directory when compiling user code. Rustc would then be responsible for all orchestration and we wouldn't require every build system to implement a Cargo.toml parser and build.rs output parser. Said parser would need to be updated every time we use a new cargo feature in the standard library, which would mean we can't use any new cargo features ever without breaking some build system if said build system is responsible for orchestrating the compilation of the standard library.

Handling this all inside rustc itself would allow much more freedom for us (both using newer cargo features and reorganizing the standard library) and be easier for alternative build systems. If we don't want all this logic to be inside rustc itself, we could also put the build logic in a separate rustc-sysroot-build binary (which could for example use cargo as library or binary to build the standard library as regular cargo project and then copy out the libraries into the output directory) and only keep the flag to use the built standard library inside rustc, with regular cargo invoking rustc-sysroot-build first.

dependencies of `profiler-builtins` so that build-std can reliably compile the
`profiler-builtins` crate regardless of the environment. Alternatively,
stability guarantees could be adjusted to set expectations that some parts of
the standard library may not build without external system dependencies.
Copy link
Member

@bjorn3 bjorn3 Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me the fact that profiler-builtins is even a crate at all rather than a C static library is a hack to enable building the profiler-rt C library within the context of a regular cargo build of the standard library. If we give up on supporting that, we should just get rid of profiler-builtins as a crate entirely and have rustc directly load a .a file. That would also simplify some logic inside rustc I think. Currently we have to inject a dependency on profiler-builtins quite early already rather than delaying this to the linker code.

change (e.g. switching between stable and nightly and back). The `dylib` is only
linked against when `-Cprefer-dynamic` is used. build-std will initially be
conservative and not include the `dylib` and `-Cprefer-dynamic` would fail
compilation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure -Cprefer-dynamic would fallback to static linking rather than failing compilation.

As part of rust-lang#3883, we have switched
the template to stop using level-1 headings which isn't the way mdbook
is intended to be used.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Dec 19, 2025
…json, r=Kivooeo

Destabilise `target-spec-json`

Per rust-lang/compiler-team#944:

> Per rust-lang#71009, the ability to load target spec JSONs was stabilised accidentally. Within the team, we've always considered the format to be unstable and have changed it freely. This has been feasible as custom targets can only be used with core, like any other target, and so custom targets de-facto require nightly to be used (i.e. to build core manually or use Cargo's -Zbuild-std).
>
> Current build-std RFCs (rust-lang/rfcs#3873, rust-lang/rfcs#3874) propose a mechanism for building core on stable (at the request of Rust for Linux), which combined with a stable target-spec-json format, permit the current format to be used much more widely on stable toolchains. This would prevent us from improving the format - making it less tied to LLVM, switching to TOML, enabling keys in the spec to be stabilised individually, etc.
>
> De-stabilising the format gives us the opportunity to improve the format before it is too challenging to do so. Internal company toolchains and projects like Rust for Linux already use target-spec-json, but must use nightly at some point while doing so, so while it could be inconvenient for those users to destabilise this, it is hoped that an minimal alternative that we could choose to stabilise can be proposed relatively quickly.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Dec 19, 2025
…json, r=Kivooeo

Destabilise `target-spec-json`

Per rust-lang/compiler-team#944:

> Per rust-lang#71009, the ability to load target spec JSONs was stabilised accidentally. Within the team, we've always considered the format to be unstable and have changed it freely. This has been feasible as custom targets can only be used with core, like any other target, and so custom targets de-facto require nightly to be used (i.e. to build core manually or use Cargo's -Zbuild-std).
>
> Current build-std RFCs (rust-lang/rfcs#3873, rust-lang/rfcs#3874) propose a mechanism for building core on stable (at the request of Rust for Linux), which combined with a stable target-spec-json format, permit the current format to be used much more widely on stable toolchains. This would prevent us from improving the format - making it less tied to LLVM, switching to TOML, enabling keys in the spec to be stabilised individually, etc.
>
> De-stabilising the format gives us the opportunity to improve the format before it is too challenging to do so. Internal company toolchains and projects like Rust for Linux already use target-spec-json, but must use nightly at some point while doing so, so while it could be inconvenient for those users to destabilise this, it is hoped that an minimal alternative that we could choose to stabilise can be proposed relatively quickly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-cargo Relevant to the Cargo team, which will review and decide on the RFC. T-compiler Relevant to the compiler team, which will review and decide on the RFC. T-libs-api Relevant to the library API team, which will review and decide on the RFC.

Projects

Status: RFC needs review

Development

Successfully merging this pull request may close these issues.

9 participants