From cc25a36ca6fb8b8a46f85ae61f18574ef3170b53 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 31 Oct 2025 11:20:34 +0000 Subject: [PATCH 1/4] build-std: context --- text/0000-build-std-context.md | 1226 ++++++++++++++++++++++++++++++++ 1 file changed, 1226 insertions(+) create mode 100644 text/0000-build-std-context.md diff --git a/text/0000-build-std-context.md b/text/0000-build-std-context.md new file mode 100644 index 00000000000..61403426ceb --- /dev/null +++ b/text/0000-build-std-context.md @@ -0,0 +1,1226 @@ +- Feature Name: `build-std-context` +- Start Date: 2025-06-05 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + +# Summary +[summary]: #summary + +While Rust's pre-built standard library has proven itself sufficient for the +majority of use cases, there are a handful of use cases that are not well +supported: + +1. Rebuilding the standard library to match the user's profile +2. Rebuilding the standard library with ABI-modifying flags +3. Building the standard library for tier three targets + +Proposals to solve these problems come broadly under the umbrella of "build-std" +and date back over 10 years ago, though no complete solution has yet reached +consensus. + +**This RFC does not propose any changes directly, only document the background, +history and motivations for build-std. It is part of a series of build-std RFCs +and later RFCs will reference this one.** This RFC is part of the +[build-std project goal]. + +1. build-std context (this RFC) + - [Background][background] + - [History][history] + - [Motivation][motivation] +2. `build-std="always"` ([rfcs#XXXX]) + - [Proposal][rfcs#XXXX-proposal] + - [Rationale and alternatives][rfcs#XXXX-rationale-and-alternatives] + - [Unresolved questions][rfcs#XXXX-unresolved-questions] + - [Future possibilities][rfcs#XXXX-future-possibilities] + - [Summary of proposed changes][rfcs#XXXX-summary] +3. Explicit standard library dependencies ([rfcs#XXXX]) + - [Proposal][rfcs#XXXX-proposal] + - [Rationale and alternatives][rfcs#XXXX-rationale-and-alternatives] + - [Unresolved questions][rfcs#XXXX-unresolved-questions] + - [Future possibilities][rfcs#XXXX-future-possibilities] +4. `build-std="compatible"` (RFC not opened yet) +5. `build-std="match-profile"` (RFC not opened yet) + +This RFC is co-authored by [David Wood][davidtwco] and +[Adam Gemmell][adamgemmell]. To improve the readability of this RFC, it does not +follow the standard RFC template, while still aiming to capture all of the +salient details that the template encourages. + +There is also a [literature review appendix][appendix] in a HackMD which +contains a summary of all literature found during the process of writing this +RFC. + +## Scope +[scope]: #scope + +build-std has a long and storied history of previous discussions and proposals +which cover a large area and many use-cases. Any individual future RFC will not +be able to support many use cases that those waiting for build-std hope that it +will. This is also an explicit and deliberate choice for the build-std project +goal's proposals. + +This RFC will focus on summarising these previous discussion and proposals in +order to enable an MVP of build-std to be accepted and stabilised. This will lay +the foundation for future proposals to lift restrictions and enable build-std to +support more use cases, without those proposals having to survey the ten-plus +years of issues, pull requests and discussion that this RFC has. + +## Acknowledgements +[acknowledgements]: #acknowledgements + +This RFC would not have been possible without the advice, feedback and support +of [Josh Triplett][joshtriplett], [Eric Huss][ehuss], +[Wesley Wiser][wesleywiser] and [Tomas Sedovic][tomassedovic] throughout this +entire effort. + +Thanks to [mati865] for advising on some of the specifics related to special +object files, [petrochenkov] for his expertise on rustc's dependency loading and +name resolution; [fee1-dead] for their early and thorough reviews; +[Ed Page][epage] for writing about opaque dependencies and his invaluable Cargo +expertise; [Jacob Bramley][jacobbramley] for his feedback on early drafts; as +well as [Amanieu D'Antras][amanieu], [Tobias Bieniek][turbo87], +[Adam Harvey][lawngnome], [James Munns][jamesmunns], +[Jonathan Pallant][thejpster], [Jieyou Xu][jieyouxu], [Jakub Beránek][kobzol], +[Weihang Lo][weihanglo], and [Mark Rousskov][simulacrum] for providing feedback +from their areas of expertise on later drafts. + +## Terminology +[terminology]: #terminology + +The following terminology is used throughout the RFC: + +- "the standard library" is used to refer to multiple of the crates that + constitute the standard library such as `core`, `alloc`, `std`, `test`, + `proc_macro` or their dependencies. +- "std" is used to refer only to the `std` crate, not the entirety of the + standard library + +Throughout the build-std project goal's later RFCs, parentheses with "?" links +([?][rationale-rationale]) will be present that which link the relevant section +in the appropriate "Rationale and alternatives" section to justify a decision or +provide alternatives to it. + +Additionally, "note alerts" will be used in the *Proposal* sections to separate +implementation considerations from the core proposal. Implementation detail +should be considered non-normative. These details could change during +implementation and are present solely to demonstrate that the implementation +feasibility has been considered and to provide an example of how implementation +could proceed. + +> [!NOTE] +> +> This is an example of a "note alert" that will be used to separate +> implementation detail from the proposal proper. + +# Background +[background]: #background + +This section aims to introduce any relevant details about the standard library +and compiler that are assumed knowledge by referenced sources and later +RFCs. + +See [*Implementation summary*][implementation-summary] for a summary of the +current unstable build-std feature in Cargo. + +## Standard library +[background-standard-library]: #standard-library + +Since the first stable release of Rust, the standard library has been distributed +as a pre-built artifact via rustup, which has a variety of advantages and/or +rationale: + +- It saves Rust users from having to rebuild the standard library whenever they + start a project or do a clean build +- The standard library has and has had dependencies which require a more + complicated build environment than typical Rust projects + - e.g. requiring a working C toolchain to build `compiler_builtins`' `c` + feature +- To varying degrees at different times in its development, the standard + library's implementation has been tied to the compiler implementation and has had + to change in lockstep + +Not all targets have a pre-built standard library distributed via rustup, though +it is a minimum requirement for certain platform support tiers. According to +rustc's [platform support docs][platform-support], for tier three targets: + +> Tier 3 targets are those which the Rust codebase has support for, but which +> the Rust project does not build or test automatically, so they may or may not +> work. Official builds are not available. + +..and tier two targets: + +> The Rust project builds official binary releases of the standard library (or, +> in some cases, only the core library) for each tier 2 target, and automated +> builds ensure that each tier 2 target can be used as build target after each +> change. + +..and finally, tier one targets: + +> The Rust project builds official binary releases for each tier 1 target, and +> automated testing ensures that each tier 1 target builds and passes tests +> after each change. + +As an innate property of the target, not all targets can support the `std` crate +This is independent of its tier, where as stated in the +[Target Tier Policy][target-tier-policy] lower-tier targets may not have a +complete implementation for all APIs in the crates they can support. + +All of the standard library crates leverage permanently unstable features +provided by the compiler that will never be stabilised and therefore require +nightly to build. + +The configuration for the pre-built standard library build is spread across +bootstrap, the standard library workspace, individual standard library crate +manifests and the target specification. The pre-built standard library is +installed into the sysroot. + +At the beginning of compilation, unless the crate has the `#![no_std]` +attribute, the compiler will load the `libstd.rlib` file from the sysroot as a +dependency of the current crate and add an implicit `extern crate std` for it. +This is the mechanism by which every crate has an implicit dependency on the +standard library. + +The standard library sources are distributed in the `rust-src` component by +rustup and placed in the sysroot under `lib/rustlib/src/`. The sources consist +of the `library/` workspace plus `src/llvm-project/libunwind`, which was +required in the past to build the `unwind` crate on some targets. + +Cargo supports explicitly declaring a dependency on crates with the same names +as standard library crates with a `path` source +(e.g. `core = { path = "../my_core" }`), which rustc will load instead of crates +in the sysroot. Crates with these dependencies are not accepted by crates.io, +but there are crates on GitHub that use this pattern, such as +[embed-rs/stm32f7-discovery][embed-rs-cargo-toml], which are used as `git` +dependencies of other crates on GitHub. + +### Dependencies +[background-dependencies]: #dependencies + +Behind the facade, the standard library is split into multiple crates, some of +which are in different repositories and included as submodules or using [JOSH]. + +As well as local crates, the standard library depends on crates from crates.io. +It needs to be able to point these crates' dependencies on the standard library +at the sources of `core`, `alloc` and `std` in the current [rust-lang/rust] +checkout. + +This is achieved through use of the `rustc-dep-of-std` feature. Crates used in +the dependency graph of `std` declare a `rustc-dep-of-std` feature and when +enabled, add new dependencies on `rustc-std-workspace-{core,alloc,std}`. +`rustc-std-workspace-{core,alloc,std}` are empty crates published on crates.io. +As part of the workspace for the standard library, +`rustc-std-workspace-{core,alloc,std}` are patched with a `path` source to the +directory for the corresponding crate. + +Historically, there have necessarily been C dependencies of the standard library, +increasing the complexity of the build environment required. While these have +largely been removed over time - for example, `libbacktrace` previously depended +on `backtrace-sys` but now uses `gimli` ([rust#46439]), a pure-rust +implementation. There are still some C dependencies: + +- `libunwind` will either link to the LLVM `libunwind` or the system's + `libunwind`/`libgcc_s`. LLVM's `libunwind` is shipped as part of the + rustup component for the standard library and will be linked against + when `-Clink-self-contained` is used + - This only applies to Linux and Fuchsia targets +- `compiler_builtins` has an optional `c` feature that will use optimised + routines from `compiler-rt` when enabled. It is enabled for the pre-built + standard library +- `compiler_builtins` has an optional `mem` feature that provides symbols + for common memory routines (e.g. `memcpy`) + - It is enabled automatically on some `no_std` platforms as when `std` is + built `libc` provides these routines. + - Users can rely on weak linkage to override these symbols, but in scenarios + where weak linkage is not supported or where the symbols are to be + overridden from a shared library, then users must directly turn the feature + off. +- To use sanitizers, the sanitizer runtimes from LLVM's compiler-rt need to + be linked against. Building of these is enabled in `bootstrap.toml` + ([`build.sanitizers`][bootstrap-sanitizers]) and they are + included in the rustup components shipped by the project. + +Dependencies of the standard library may use unstable or internal compiler and +language features only when they are a dependency of the standard library. + +### Features +[background-features]: #features + +There are a handful of features defined in the standard library crates' +`Cargo.toml`s. These features are not strictly additive (`llvm-libunwind` and +`system-llvm-libunwind` are mutually exclusive). There is currently no stable +existing mechanism for users to enable or disable these features. The default +set of features is determined by [logic in bootstrap][bootstrap-features-logic] +and [the `rust.std-features` key in `bootstrap.toml`][bootstrap-features-toml]. +The enabled features are often different depending on the target. + +It is also common for user crates to depend on the standard library (via +`#![no_std]`) conditional on Cargo features being enabled or disabled (e.g. a +`std` feature or if `--test` is used). + +### Target support +[background-target-support]: #target-support + +The `std` crate's [`build.rs`][std-build.rs] checks for supported values of the +`CARGO_CFG_TARGET_*` environment variables. These variables are akin to the +conditional compilation [configuration options][conditional-compilation-config-options], +and often correspond to parts of the target triple (for example, +`CARGO_CFG_TARGET_OS` corresponds to the "os" part of a target triple - "linux" +in "aarch64-unknown-linux-gnu"). This filtering is strict enough to distinguish +between built-in targets but loose enough to match similar custom targets. There +is no equivalent mechanism on the `alloc` or `core` crates. + +When encountering an unknown or unsupported operating system then the +`restricted_std` cfg is set. `restricted_std` marks the entire standard library +as unstable, requiring `feature(restricted_std)` to be enabled on any crate that +depends on it. The only way for users to enable the `restricted_std` feature on +behalf of dependencies is the uncommon `-Zcrate-attr=features(restricted_std)` +rustc flag and users commonly report that they are not aware how to do this. + +Cargo and rustc support custom targets, defined in JSON files according to an +unstable schema defined in the compiler. On nightly, users can dump the +target-spec-json for an existing target using `--print target-spec-json`. This +JSON can be saved in a file, tweaked and used as the argument to `--target`. It +is unintentional but custom target specifications can be used with `--target` +even on stable toolchains ([rust#71009] proposes destabilising this behaviour). +However, as custom targets do not have a pre-built standard library and so must +use `-Zbuild-std`, their use is relegated to nightly toolchains in practice. +Custom targets may have `restricted_std` set depending on their `cfg` +configuration options. + +## Prelude +[background-prelude]: #prelude + +rustc has the concept of the "extern prelude" which is the set of crates that +can be referred to without an explicit `extern crate` statement. Originally this +was populated by users writing `extern crate $crate` in their code for each +direct dependency. Since the 2018 edition, crates passed via `--extern` are +added to the extern prelude. `core` is always added to the extern prelude. For +crates without the `#![no_std]` attribute, `std` is added to the extern prelude. + +`core` or `std`'s prelude module (depending on the presence of `#![no_std]`) is +imported by rustc injecting a `use $crate::prelude::rust_20XX::*` statement. + +`extern crate` can still be used and will search for the dependency in locations +where direct dependencies can be found, such as `-L crate=` paths or in the +sysroot. `-L dependency=` paths will not be searched, as these directories only +contain indirect dependencies (i.e. dependencies of direct dependencies). + +Although only `std` or `core` are added to the extern prelude automatically, +users can still write `extern crate alloc` or `extern crate test` to load them +from the sysroot. + +`--extern` has a `noprelude` modifier which will allow the user to use +`--extern` to specify the location at which a crate can be found without adding +it to the extern prelude. This could allow a path for crates like `alloc` or +`test` to be provided without effecting the observable behaviour of the +language. + +## Panic strategies +[background-panic-strategies]: #panic-strategies + +Rust has the concept of a *panic handler*, which is a crate that is responsible +for performing a panic. There are various panic handler crates on crates.io, +such as [panic-abort] (which different from the `panic_abort` panic runtime!), +[panic-halt], [panic-itm], and [panic-semihosting]. Panic handler crates define +a function annotated with `#[panic_handler]`. There can only be one +`#[panic_handler]` in the crate graph. + +`core` uses the panic handler to implement panics inserted by code generation +(e.g. arithmetic overflow or out-of-bounds access) and the `core::panic!` macro +immediately delegates to the panic handler crate. + +`std` defines a panic handler. `std`'s panic handler function and its +`std::panic!` macro print panic information to stderr and delegate to a +*panic runtime* to decide what to do next, determined by the *panic strategy*. + +There are two panic runtime crates in the standard library - `panic_unwind` +(which gracefully unwinds the stack using `libunwind` and performs cleanup) and +`panic_abort` (which terminates the program shortly after being called). Each +target supported by rustc specifies a default panic strategy - either "unwind" +or "abort" - though these are only relevant if `std`'s panic handler is used +(i.e. the target isn't a `no_std` target or being used with a `no_std` crate). + +Rust's `-Cpanic` flag allows the user to choose the panic strategy, with the +target's default as a fallback. If `-Cpanic=unwind` is provided then this +doesn't guarantee that the unwind strategy is used, as the target may not +support it. + +Both crates are compiled and shipped with the pre-built standard library for +targets which support `std`. Some targets have a pre-built standard library with +only the `core` and `alloc` crates, such as the `x86_64-unknown-none` target. +While `x86_64-unknown-none` defaults to the `abort` panic strategy, as this +target does not support the standard library, this default isn't actually +relevant. + +The `std` crate has a `panic_unwind` feature that enables an optional dependency +on the `panic_unwind` crate. + +`core` also provides support for the (unstable) `-Cpanic=immediate_abort` +strategy by modifying the `core::panic!` macro to immediately call the abort +intrinsic without calling the panic handler, which can dramatically reduce code +size. `std` also adds an immediate abort to its `panic!` macro. + +## Cargo +[background-cargo]: #cargo + +Cargo's building of the dependency graph is largely driven by the registry +index, except for crates from `git` or `path` sources. + +[Cargo registries][cargo-docs-registry], like crates.io, are centralised sources +for crates. A registry's index is the interface between Cargo and the registry +that Cargo queries to know which versions are available for any given crate, +what its dependencies are, etc. + +Cargo can query registries using a Git protocol which caches the registry on +disk, or using a sparse protocol which exposes the index over HTTP and allows +Cargo to avoid Cargo having a local copy of the whole index, which has become +quite large for crates.io. + +crates.io's registry index is exposed as both a HTTP API and a Git repository - +[rust-lang/crates.io-index] - both are updated automatically by crates.io when +crates are published, yanked, etc. The HTTP API is mostly used. + +Each crate in the registry index has a JSON file, following +[a defined schema][cargo-json-schema] which is jointly maintained by the Cargo +and crates.io teams. Crates may refer to those in other registries, but all +non-`path`/`git` crates in the dependency graph must exist in a registry. As the +registry index drives the building of Cargo's dependency graph, all +non-`path`/`git` crates that end up in the dependency graph must be present a +registry. + +When a package is published, Cargo posts a JSON blob to the registry which is +not a index entry but has sufficient information to generate one. crates.io does +not use Cargo's JSON blob, instead re-generating it from the `Cargo.toml` (this +avoids the index and `Cargo.toml` from going out-of-sync due to bugs or +malicious publishes). As a consequence, changes to the index format must be +duplicated in Cargo and crates.io. Behind the scenes, data from the `Cargo.toml` +extracted by crates.io is written to a database, which is where the index entry +and frontend are generated from. + +Dependency information of crates in the registry are rendered in the crates.io +frontend. + +Registries can have different policies for what crates are accepted. For +example, crates.io does not permit publishing packages named `std` or `core` but +other registries might. + +### Public/private dependencies +[background-pubpriv-dependencies]: #publicprivate-dependencies + +[Public and private dependencies][rust#44663] are an unstable feature which +enables declaring which dependencies form part of a library's public interface, +so as to make it easier to avoid breaking semver compatibility. + +With the `public-dependency` feature enabled, dependencies are marked as +"private" by default which can be overridden with a `public = true` declaration. + +Private dependencies are passed to rustc with an `priv` modifier to the +`--extern` flag. Dependencies without this modifier are treated as public by +rustc for backwards compatibility reasons. rust emits the +`exported-private-dependencies` lint if an item from a private dependency is +re-exported. + +## Target modifiers +[background-target-modifiers]: #target-modifiers + +[rfcs#3716] introduced the concept of *target modifiers* to rustc. Flags marked +as target modifiers must match across the entire crate graph or the compilation +will fail. + +For example, flags are made target modifiers when they change the ABI of +generated code and could result in unsound ABI mismatches if two crates are +linked together with different values of the flag set. + +# History +[history]: #history + +*The following summary of the prior art is necessarily less detailed than the +source material, which is exhaustively surveyed in +[Appendix: Exhaustive literature review][appendix].* + +## [rfcs#1133] (2015) +[rfcs-1133-2015]: #rfcs1133-2015 + +build-std was first proposed in a [2015 RFC (rfcs#1133)][rfcs#1133] by +[Ericson2314], aiming to improve support for targets that do not have a +pre-built standard library; to enable building the standard library with +different profiles; and to simplify `rustbuild` (now `bootstrap`). It also was +written with the goal of supporting the user in providing a custom +implementation of the standard library and supporting different implementations +of the language that provide their own standard libraries. + +This RFC proposed that the standard library be made an explicit dependency in +`Cargo.toml` and be rebuilt automatically when required. An implicit dependency +on the standard library would be added automatically unless an explicit +dependency is written. This RFC was written prior to a stable `#![no_std]` +attribute and so does not address the circumstance where a implicit dependency +would make a no-std crate fail to compile on a target that does not support +the standard library. + +There were objectives of and possibilities enabled by the RFC that were not +shared with the project teams at the time, such as the standard library being +a regular crate on crates.io and the concept of the sysroot being retired. +Despite this, the RFC appeared to be close to acceptance before being blocked +by Cargo having a mechanism to have unstable features and then closed in favour +of [cargo#4959]. + +## [xargo] and [cargo#4959] (2016) +[xargo-and-cargo-4959-2016]: #xargo-and-cargo4959-2016 + +While the discussions around [rfcs#1133] where ongoing, [xargo] was released in +2016. Xargo is a Cargo wrapper that builds a sysroot with a customised standard +library and then uses that with regular Cargo operations (i.e. `xargo build` +performs the same operation as `cargo build` but with a customised standard +library). Configuration for the customised standard library was configured in +the `Xargo.toml`, supporting configuring codegen flags, profile settings, Cargo +features and multi-stage builds. It required nightly to build the standard +library as it did not use `RUSTC_BOOTSTRAP`. Xargo had inherent limitations due +to being a Cargo wrapper, leading to suggestions that its functionality be +integrated into Cargo. + +[cargo#4959] is a proposal inspired by [xargo], suggesting that a `[sysroot]` +section be added to `.cargo/config` which would enable similar configuration to +that of `Xargo.toml`. If this configuration is set, Cargo would build and use a +sysroot with a customised standard library according to the configuration +specified and the release profile. This sysroot would be rebuilt whenever +relevant configuration changes (e.g. profiles). [cargo#4959] received varied +feedback: the proposed syntax was not sufficiently user-friendly; it did not +enable the user to customise the standard library implementation; and that +exposing bootstrap stages was brittle and user-unfriendly. [cargo#4959] wasn't +updated after submission so ultimately stalled and remains open. + +[rfcs#1133] and [cargo#4959] took very different approaches to build-std, with +[cargo#4959] proposing a simpler approach that exposed the necessary low-level +machinery to users and [rfcs#1133] attempting to take a more first-class and +user-friendly approach that has many tricky design implications. + +## [rfcs#2663] (2019) +[rfcs-2663-2019]: #rfcs2663-2019 + +In 2019, [*rfcs#2663: `std` Aware Cargo*][rfcs#2663] was opened as the most +recent RFC attempting to advance build-std. [rfcs#2663] shared many of the +motivations of [rfcs#1133]: building the standard library for tier three and +custom targets; customising the standard library with different Cargo features; +and applying different codegen flags to the standard library. It did not concern +itself with build-std's potential use in `rustbuild` or with abolishing the +sysroot. + +[rfcs#2663] was primarily concerned what functionality should be available to +the user and what the user experience ought to be. It proposed that `core`, +`alloc` and `std` be automatically built when the target did not have a pre-built +standard library available through rustup. It would be automatically rebuilt on +any target when the profile configuration was modified such that it no longer +matched the pre-built standard library. If using nightly, the user could enable +Cargo features and modify the source of the standard library. Standard library +dependencies were implicit by default, as today, but would be written explicitly +when enabling Cargo features. It also aimed to stabilise the target-spec-json +format and allow "stable" Cargo features to be enabled on stable toolchains, and +as such proposed the concept of stable and unstable Cargo features be +introduced. + +There was a lot of feedback on [rfcs#2663] which largely stemmed from it being +very high-level, containing many large unresolved questions and details left for +the implementers to work out. For example, it proposed that there be a concept +of stable and unstable Cargo features but did not elaborate any further, leaving +that as an implementation detail. Nevertheless, the proposal was valuable in +more clearly elucidating a potential user experience that build-std could aim +for, and the feedback provided was incorporated into the [wg-cargo-std-aware] +effort, described below. + +## [wg-cargo-std-aware] (2019-) +[wg-cargo-std-aware-2019-]: #wg-cargo-std-aware-2019- + +[rfcs#2663] demonstrated that there was demand for a mechanism for being able to +(re-)build the standard library, and the feedback showed that this was a thorny +problem with lots of complexity, so in 2019, the [wg-cargo-std-aware] repository +was created to organise related work and explore the issues involved in +build-std. + +[wg-cargo-std-aware] led to the current unstable implementation of `-Zbuild-std` +in Cargo, which is described in detail in the [*Implementation summary* +section][implementation-summary] below. + +Issues in the wg-cargo-std-aware repository can be roughly partitioned into seven +categories: + +1. **Exploring the motivations and use cases for the standard library** + + There are a handful of motivations catalogued in the [wg-cargo-std-aware] + repository, corresponding to those raised in the earlier RFCs and proposals: + + - Building with custom profile settings ([wg-cargo-std-aware#2]) + - Building for unsupported targets ([wg-cargo-std-aware#3]) + - Building with different Cargo features ([wg-cargo-std-aware#4]) + - Replacing the source of the standard library ([wg-cargo-std-aware#7]) + - Using build-std in bootstrap/rustbuild ([wg-cargo-std-aware#19]) + - Improving the user experience for `no_std` binary projects + ([wg-cargo-std-aware#36]) + + These are all either fairly self-explanatory, described in the summary of the + previous RFCs/proposals above, or in the [*Motivation*][motivation] section + of this RFC. + +2. **Support for build-std in Cargo's subcommands** + + Cargo has various subcommands where the desired behaviour when used with + build-std needs some thought and consideration. A handful of issues were + created to track this, most receiving little to no discussion: + [`cargo metadata`][wg-cargo-std-aware#20], [`cargo clean`][wg-cargo-std-aware#21], + [`cargo pkgid`][wg-cargo-std-aware#24], and [the `-p` flag][wg-cargo-std-aware#26]. + + [`cargo fetch`][wg-cargo-std-aware#22] had fairly intuitive interactions with + build-std - that `cargo fetch` should also fetch any dependencies of the + standard library - which was implemented in [cargo#10129]. + + The [`--build-plan` flag][wg-cargo-std-aware#45] does not support build-std and its + issue did not receive much discussion, but the future of this flag in its + entirety seems to be uncertain. + + [`cargo vendor`][wg-cargo-std-aware#23] did receive lots of discussion. + Vendoring the standard library is desirable (for the same reasons as any + vendoring), but would lock the user to a specific version of the toolchain + when using a vendored standard library. However, if the `rust-src` component + contained already-vendored dependencies, then `cargo vendor` would not need + to support build-std and users would see the same advantages. + + Vendored standard library dependencies were implemented using a hacky + approach (necessarily, prior to the standard library having its own + workspace), but this was later reverted due to bugs. No attempt has been made + to reimplement vendoring since the standard library has had its own + workspace. + +3. **Dependencies of the standard library** + + There are a handful of dependencies of the standard library that may pose + challenges for build-std by dint of needing a working C toolchain or + special-casing. + + [`libbacktrace`][wg-cargo-std-aware#16] previously required a C compiler to + build `backtrace-sys`, but now uses `gimli` internally. + + [`compiler_builtins`][wg-cargo-std-aware#15] has a `c` feature that uses C + versions of some intrinsics that are more optimised. This is used by the + pre-built standard library, and if not used by build-std, could be a point of + divergence. `compiler-builtins/c` can have a significant impact on code + quality and build size. It also has a `mem` feature which provides symbols + (`memcpy`, etc) for platforms without `std` that don't have these same + symbols provided by `libc`. `compiler_builtins` is also built with a large + number of compilation units to force each function into a different unit, + avoiding unintentionally bringing in a symbol that conflicts with one in the + system's `libgcc`. + + ['unwind'][wg-cargo-std-aware#29] links to the system's version of libunwind. + Enabling the `llvm-libunwind` feature, `-Clink-self-contained` or + `-Ctarget-feature=+crt-static` will statically link to the pre-built + `libunwind` distributed in the standard library component for the target, if + present. + + [Sanitizers][wg-cargo-std-aware#17], when enabled, require a sanitizer + runtime to be present. These are currently built by bootstrap and part of + LLVM. + +4. **Design considerations** + + There are many design considerations discussed in the [wg-cargo-std-aware] + repository: + + [wg-cargo-std-aware#5] explored how/if dependencies on the standard library + should be declared. The issue claims that users should have to opt-in to + build-std, support alternative standard library implementations, and that + Cargo needs to be able to pass `--extern` to rustc for all dependencies. + + It is an open question how to handle multiple dependencies each declaring a + dependency on the standard library. A preference towards unifying standard + library dependencies was expressed (these would have no concept of a version, + so just union all features). + + There was no consensus on how to find a balance between explicitly depending + on the standard library versus implicitly, or on whether the pre-built-ness + of a dependency should be surfaced to the user. + + [wg-cargo-std-aware#6] argues that target-spec-json would be de-facto stable + if it can be used by build-std on stable. While `--target=custom.json` can be + used on stable today, it effectively requires build-std and so a nightly + toolchain. As build-std enables custom targets to be used on stable, this + would effectively be a greater commitment to the current stability of custom + targets than currently exists and would warrant an explicit decision. + + [wg-cargo-std-aware#8] highlighted that a more-portable standard library + would be beneficial for build-std (i.e. a `std` that could build on any + target), but that making the standard library more portable isn't necessarily + in-scope for build-std. + + [wg-cargo-std-aware#11] investigated how build-std could get the standard + library sources. rustup can download `rust-src`, but there was a preference + expressed that rustup not be required. Cargo could have reasonable default + probing locations that could be used by distros and would include where + rustup puts `rust-src`. + + [wg-cargo-std-aware#12] concluded that the `Cargo.lock` of the standard + library would need to be respected so that the project can guarantee that the + standard library works with the project's current testing. + + [wg-cargo-std-aware#13] explored how to determine the default set of cfg + values for the standard library. This is currently computed by bootstrap. + This could be duplicated in Cargo in the short-term, made visible to + build-std through some configuration, or require the user to explicitly + declare them. + + [wg-cargo-std-aware#14] looks into additional rustc flags and environment + variables passed by bootstrap to the compiler. A comparison of the + compilation flags from bootstrap and build-std was + [posted in a comment][wg-cargo-std-aware#14-review]. No solutions were + suggested, other than that it may need a similar mechanism as + [wg-cargo-std-aware#13]. + + [wg-cargo-std-aware#29] tries to determine how to support different panic + strategies. Should Cargo use the profile to decide what to use? How does it + know which panic strategy crate to use? It is argued that Cargo ought to work + transparently - if the user sets the panic strategy differently then a + rebuild is triggered. + + [wg-cargo-std-aware#30] identifies that some targets have special handling in + bootstrap which will need to be duplicated in build-std. Targets could be + allowlisted or denylisted to avoid having to address this initially. + + [wg-cargo-std-aware#38] argues that a forced lock of the standard library + is desirable, to which there was no disagreement. This was more relevant + when build-std did not use the on-disk `Cargo.lock`. + + [wg-cargo-std-aware#39] explores the interaction between build-std and + public/private dependencies ([rfcs#3516]). Should the standard library always + be public? There were no solutions presented, only that if defined in + `Cargo.toml`, the standard library will likely inherit the default from that. + + [wg-cargo-std-aware#43] investigates the options for the UX of build-std. + `-Zbuild-std` flag is not a good experience as it needs added to every + invocation and has few extension points. Using build-std should be a unstable + feature at first. It was argued that build-std should be transparent and + happen automatically when Cargo determines it is necessary. There are + concerns that this could trigger too often and that it should only happen + automatically for ABI-modifying flags. + + [wg-cargo-std-aware#46] observes that some targets link against special + object flags (e.g. `crt1.o` on musl) and that build-std will need to handle + these without hardcoding target-specific logic. There were no conclusions, + but `-Clink-self-contained` might be able to help. + + [wg-cargo-std-aware#47] discusses how to handle targets that typically ship + with a different linker (e.g. `rust-lld` or `gcc`). `rust-lld` is now shipped + by default reducing the potential impact of this, though it is discovered via + the sysroot, and so will need to be found via another mechanism if disabled. + + [wg-cargo-std-aware#50] argues that the impact on build probes ought to be + considered and was later closed as t-cargo do not want to support build + probes. + + [wg-cargo-std-aware#51] plans for removal of `rustc-dep-of-std`, identifying + that if explicit dependencies on the standard library are adopted, that the + need for this feature could be made redundant. + + [wg-cargo-std-aware#68] notices that `profiler_builtins` needs to be compiled + after `core` (i.e. `core` can't be compiled with profiling). The error + message has been improved for this but there was otherwise no commentary. + This has changed since the issue was filed, as `profiler_builtins` is now a + `#![no_core]` crate. + + [wg-cargo-std-aware#85] considers that there has to be a deliberate testing + strategy in place between the [rust-lang/rust] and [rust-lang/cargo] + repositories to ensure there is no breakage. `rust-toolstate` could be used + but is not very good. Alternatively, Cargo could become a [JOSH] subtree of + [rust-lang/rust]. + + [wg-cargo-std-aware#86] proposes that the initial set of targets supported by + build-std be limited at first to further reduce scope and limit exposure to + the trickier issues. + + [wg-cargo-std-aware#88] reports that `cargo doc -Zbuild-std` doesn't generate + links to the standard library. Cargo doesn't think the standard library comes + from crates.io, and bootstrap isn't involved to pass + `-Zcrate-attr="doc(html_root_url=..)"` like in the pre-built standard + library. + + [wg-cargo-std-aware#90] asks how `restricted_std` should apply to custom + targets. `restricted_std` is triggered based on the `target_os` value, which + means it will apply for some custom targets but not others. build-std needs + to determine what guarantees are desirable/expected. Current implementation + wants slightly-modified-from-default target specs to be accepted and + completely new target specs to hit `restricted_std`. + + [wg-cargo-std-aware#92] suggests that some targets could be made "unstable" + and as such only support build-std on nightly. This forces users of those + targets to use nightly where they will receive more frequent fixes for their + target. It would also permit more experimentation with build-std while + enabling stabilisation for mainstream targets. + +5. **Implementation considerations** + These won't be discussed in this summary, see [the implementation summary][implementation-summary] + or [the relevant section of the literature review for more detail][appendix-impl] + +6. **Bugs in the compiler or standard library** + These aren't especially relevant to this summary, see [the relevant section + of the literature review for more detail][appendix-bugs] + +7. **Cargo feature requests narrowly applied to build-std** + These aren't especially relevant to this summary, see [the relevant section + of the literature review for more detail][appendix-cargo-feats] + +Since around 2020, activity in the [wg-cargo-std-aware] repository largely +trailed off and there have not been any significant developments related to +build-std since. + +### Implementation summary +[implementation-summary]: #implementation-summary + +*An exhaustive review of implementation-related issues, pull requests and +discussions can be found in +[the relevant section of the literature review][appendix-impl].* + +There has been an unstable and experimental implementation of build-std in Cargo +since August 2019 ([wg-cargo-std-aware#10]/[cargo#7216]). + +[cargo#7216] added the [`-Zbuild-std`][build-std] flag to Cargo. `-Zbuild-std` +re-builds the standard library crates which rustc then uses instead of the +pre-built standard library from the sysroot. + +Originally, `-Zbuild-std` always build `std` by default. Since the addition of +the `std` field to target metadata in [rust#122305], Cargo only builds `std` by +default if `metadata.std` is true. + +`test` is also built if `std` is being built and tests are being run with the +default harness. + +Optionally, users can provide the list of crates to be built, though this was +intended as an escape hatch to work around bugs - the arguments to the flag are +unstable since the names of crates comprising the standard library are not +stable. + +Cargo has a hardcoded list of what dependencies need to be added for a given +user-requested crate (i.e. `std` implies building `core`, `alloc`, +`compiler_builtins`, etc.). It is common for users to manually specify the +`panic_abort` crate. + +Originally, `-Zbuild-std` required that `--target` be provided +([wg-cargo-std-aware#25]) to force Cargo to use different sysroots for the host +and target , but this restriction was later resolved ([cargo#14317]). + +A second flag, [`-Zbuild-std-features`][build-std-features], was added in +[cargo#8490] and allows overriding the default Cargo features of the standard +library. Like the arguments to `-Zbuild-std`, this values accepted by this flag +are inherently unstable as the library team has not committed to any of the +standard library's Cargo features being stable. Features are enabled on the +`sysroot` crate and propagate down through the crate graph of the standard +library (e.g. `compiler-builtins-mem` is a feature in `sysroot`, `std`, +`alloc`, and `core` until `compiler_builtins`). + +build-std gets the source of the standard library from the `rust-src` rustup +component. This does not happen automatically and the user must ensure the +component has been downloaded themselves. Only the standard library crates from +the [rust-lang/rust] repository are included in the `rust-src` dependency (i.e. +none of the crates.io dependencies). + +When `-Zbuild-std` has been passed, Cargo creates a second workspace for the +standard library based on the `Cargo.{toml,lock}` from the `rust-src` component. +Originally this was an in-memory workspace, prior to the standard library having +a separate workspace from the compiler which could be used independently +([rust#128534]/[cargo#14358]). This workspace is then resolved separately and +the resolve is combined with the user's resolve to produce a dependency graph of +things to build with the user's crates depending on the standard library's +crates. Some additional work is done to deduplicate crates across the graph and +then this crate graph is used to drive work (usually rustc invocations) as +usual. This approach allows for build-time parallelism and sharing of crates +between the two separate resolves but does involve `build-std`-specific logic in +and around unit generation and is very unlike the rest of Cargo +([wg-cargo-std-aware#64]). + +Resolving the standard library separately from the user's crate helps guarantee +that the exact dependency versions of the pre-built standard library are used, +which is a key constraint ([wg-cargo-std-aware#12]). Locking the standard +library could also help ([wg-cargo-std-aware#38]). A consequence of this is that +each of the Cargo subcommands (e.g. `cargo metadata`) need to have special +support for build-std implemented, but this might be desirable. + +The standard library crates are considered non-local packages and so are not +compiled with incremental compilation or dep-info fingerprint tracking and any +warnings will be silenced. + +build-std provides newly-built standard library dependencies to rustc using +`--extern noprelude:$crate`. `noprelude` was added in [rust#67074] to support +build-std and ensure that loading from the sysroot and using `--extern` were +equivalent ([wg-cargo-std-aware#40]). Prior to the addition of `noprelude`, +build-std briefly created new sysroots and used those instead of `--extern` +([cargo#7421]). rustc can still try to load a crate from the sysroot if the user +uses it which is currently a common source of confusing "duplicate lang item" +errors (as the user ends up with build-std `core` and sysroot `core` +conflicting). + +Host dependencies like build scripts and `proc_macro` crates use the +existing pre-built standard library from the sysroot, so Cargo does not +pass `--extern` to those. + +Modifications to the standard library are not supported. While build-std +has no mechanism to detect or prevent modifications to the `rust-src` content, +rebuilds aren't triggered automatically on modifications. The user cannot +override dependencies in the standard library workspace with `[patch]` sections +of their `Cargo.toml`. + +To simplify build-std in Cargo, build-std wants to be able to always build +`std`, which is accomplished through use of the +[`unsupported` module in `std`'s platform abstraction layer][std-unsupported], +and `restricted_std`. `std` checks for unsupported targets in its +[`build.rs`][std-build.rs] and applies the `restricted_std` cfg which marks the +standard library as unstable for unsupported targets. + +Users can enable the `restricted_std` feature in their crates. This mechanism +has been noted as confusing ([wg-cargo-std-aware#87]) and has the issue that the +user cannot opt into the feature on behalf of dependencies +([wg-cargo-std-aware#69]). + +The initial implementation does not include support for build-std in many of +Cargo's subcommands including `metadata`, `clean`, `vendor`, `pkgid` and the +`-p` options for various commands. Support for `cargo fetch` was implemented in +[cargo#10129]. + +## `no_std` Usability +[no_std-usability]: #no_std-usability + +There are also issues related to the usability of `no_std` crates: + +- Discoverability of `no_std` crates is difficult with a mix of categories + (`no-std`) and keywords (`nostd`/`no_std`) that are not used consistently by + `no_std` crates ([crates.io#7306]). + +- `no_std` crates can accidentally and easily depend on crates that use `std` + which can result in build failures in some targets ([cargo#8798]). + +## Related work +[related-work]: #related-work + +There are a variety of ongoing efforts, ideas, RFCs or draft notes describing +features that are related or would be beneficial for build-std: + +- **[Opaque dependencies]**, [epage], May 2025 + - Introduces the concept of an opaque dependency that has its own + `Cargo.lock`, `RUSTFLAGS` and `profile` + - Opaque dependencies could enable a variety of build-time performance + improvements: + - Caching - differences in dependency versions can cause unique instances of + every dependent crate + - Pre-built binaries - can leverage a pre-built artifact for a given opaque + dependency + - e.g. the standard library's distributed `rlib`s + - MIR-only/cross-crate lazy compilation - Small dependencies could be built + lazily and larger dependencies built once + - Optimising dependencies - dependencies could always be optimised when they + are unlikely to be needed during debugging + +# Motivation +[motivation]: #motivation + +> [!IMPORTANT] +> +> This section lists all of the motivations that have been associated with +> build-std in its various iterations, but not all of these use cases will be +> addressed by this project goal. +> +> The motivations that will not be addressed are nevertheless mentioned here so +> that reviewers have a more complete context for what has and hasn't been +> desired of build-std over time. + +While the pre-built standard library has been sufficient for the majority of +Rust users, there are a variety of use-cases which require the ability to +rebuild the standard library. + +1. **Building the standard library without relying on unstable escape hatches** + + - While tangential to the core of build-std as a feature, projects like Rust + for Linux want to be able to build crates from the standard library using + a stable toolchain without relying on escape hatches like + `RUSTC_BOOTSTRAP` that the Rust project does not encourage use of + + - It is relatively straightforward to support this, hence its inclusion + + - Cargo's implementation of build-std should be able to re-use whichever + mechanism is designed to address this + +2. **Building standard library crates that are not shipped for a target** + + - Targets which have limited `std` support may wish to use the subsets of + the standard library which could work but are not shipped by the project + (e.g. `std` on `x86_64-unknown-none`) + +3. **Using the standard library with tier three targets** + + - There is no stable mechanism for using the standard library on a tier + three target that does not ship a pre-built std + + - While it is common for these targets to not support the standard library, + they should be able to use `core` + + - These users are forced to use nightly and the unstable `-Zbuild-std` + feature or third-party tools like [cargo-xbuild] (formerly [xargo]) + +4. **Unblock stabilisation of ABI-modifying compiler flags** + + - Any compiler flags which change the ABI cannot currently be stabilised as + they would immediately mismatch with the pre-built standard library + + - Without an ability to rebuild the standard library using these flags, it + is impossible to use them effectively and safely if stabilised + + - ABI-modifying flags are designated as target modifiers + ([rfcs#3716]/[rust#136966]) and require that the same value for the flag + is passed to all compilation units + + - Flags which need to be set across the entire crate graph to uphold some + property (i.e. enhanced security) are also target modifiers + + - For example: sanitizers, control flow integrity, `-Zfixed-x18`, etc + +5. **Re-building the standard library with different codegen flags or profile** + ([wg-cargo-std-aware#2]) + + - Embedded users need to optimise aggressively for size, due to the limited + space available on their target platforms, which can be achieved in Cargo + by setting `opt-level = s/z` and `panic = "abort"` in their profile. + However, these settings will not apply to the pre-built standard library + + - Similarly, when deploying to known environments, use of `target-cpu` or + `target-feature` can improve the performance of code generation or allow + the use of newer hardware features than the target's baseline provides. As + above, these configuration will not apply to the pre-built standard + library + + - While the pre-built standard library is built to support debugging without + compromising size and performance by setting `debuginfo=1`, this isn't + ideal, and building the standard library with the dev profile would + provide a better experience when debugging + +The following use cases are not currently planned as part of this project goal, +but could be supported with follow-up RFCs (and any RFCs proposed as part of +this goal will attempt to ensure they remain viable as future possibilities): + +1. **Using the standard library with custom targets** + + - There is no stable mechanism for using the standard library for a custom + target (using target-spec-json) + + - Like tier three targets, these targets often only support `core` and are + forced to use nightly today + +2. **Enabling Cargo features for the standard library** ([wg-cargo-std-aware#4]) + + - There are opportunities to expose Cargo features from the standard library + that would be useful for certain subsets of the Rust users. + + - For example, embedded users may want to enable `optimize_for_size` or + disable `backtrace` to reduce binary size + +3. **Using miri on a stable toolchain** + + - Using miri requires building the standard library with specific compiler + flags that would not be appropriate for the pre-built standard library, so + is forced to require nightly and build its own sysroot + +Some use cases are unlikely to supported by the project unless a new and +compelling use-case is presented, and so this project goal may make decisions +which make these motivations harder to solve in future: + +1. **Modifying the source code of the standard library** ([wg-cargo-std-aware#7]) + + - Some platforms require a heavily modified standard library that would not + be suitable for upstreaming, such as [Apache's SGX SDK][sgx] which + replaces some standard library and ecosystem crates with forks or custom + crates for a custom `x86_64-unknown-linux-sgx` target + + - Similarly, some tier three targets may wish to patch standard library + dependencies to add or improve support for the target + + - If a stable mechanism were provided to make such changes to the standard + library, then this would constrain future standard library development. + These changes are better attempted by maintaining a fork of the standard + library. + +2. **Retire the concept of the sysroot** + + - Earlier proposals for build-std were motivated in-part by the desire to see + the concept of the sysroot retired. + + - This is challenging while maintaining backwards-compatibility, + especially for users who do not use Cargo and assume rustc can find the + standard library in the sysroot. Removing the sysroot has no advantages + to the end-user of Rust in itself. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +These rationales and alternatives apply to the build-std proposal as a whole: + +## Why have rationale sections? +[rationale-rationale]: #why-have-rationale-sections + +A separate rationale section makes for easier reading by letting the proposal +sections of the RFCs flow better without interruptions or tangents. + +↩ [*Terminology*][terminology] + +## Why not do nothing? +[rationale-why-not-do-nothing]: #why-not-do-nothing + +Support for rebuilding the standard library is a long-standing feature request +from subsets of the Rust community and blocks the work of some project teams +(e.g. sanitisers and branch protection in the compiler team, amongst others). +Inaction forces these users to remain on nightly and depend on the unstable +`-Zbuild-std` flag indefinitely. RFCs and discussion dating back to the first +stable release of the language demonstrate the longevity of build-std as a +need. + +## Shouldn't build-std be part of rustup? +[rationale-in-rustup]: #shouldnt-build-std-be-part-of-rustup + +build-std is effectively creating a new sysroot with a customised standard +library. rustup as Rust's toolchain manager has existing machinery to create and +maintain sysroots, and if it could invoke Cargo to build the standard library +then it could create a new toolchain from a build from a `rust-src` component. +rustup would be invoking tools from the next layer of abstraction (Cargo) in the +same way that Cargo invokes tools from the layer of abstraction after it +(rustc). + +A brief prototype of this idea was created and a +[short design document was drafted][why-not-rustup] before concluding that it +would not be possible. With Cargo's artifact dependencies it may be desirable +to build with a different standard library and if rustup was creating different +toolchains per-customised standard library then Cargo would need to have +knowledge of these to switch between them, which isn't possible (and something +of a layering violation). It is also unclear how Cargo would find and use the +uncustomized host sysroot for build scripts and procedural macros. In addition +rustup's knowledge of sysroots and toolchains is limited to the archives it +unpacks - it becoming a part of the build system is not trivial, especially +considering it uses a different versioning system to Cargo, Rust and the +standard library. + +[build-std project goal]: https://rust-lang.github.io/rust-project-goals/2025h2/build-std.html + +[davidtwco]: https://github.com/davidtwco +[adamgemmell]: https://github.com/adamgemmell +[amanieu]: https://github.com/Amanieu +[ehuss]: https://github.com/ehuss +[epage]: https://github.com/epage +[fee1-dead]: https://github.com/fee1-dead +[jacobbramley]: https://github.com/jacobbramley +[jamesmunns]: https://github.com/JamesMunns +[jieyouxu]: https://github.com/jieyouxu +[joshtriplett]: https://github.com/joshtriplett +[kobzol]: https://github.com/kobzol +[lawngnome]: https://github.com/LawnGnome +[mati865]: https://github.com/mati865 +[petrochenkov]: https://github.com/petrochenkov +[simulacrum]: https://github.com/simulacrum +[thejpster]: https://github.com/thejpster +[tomassedovic]: https://github.com/tomassedovic +[turbo87]: https://github.com/Turbo87 +[weihanglo]: https://github.com/weihanglo +[wesleywiser]: https://github.com/wesleywiser +[Ericson2314]: https://github.com/Ericson2314 + +[appendix]: https://hackmd.io/@davidtwco/BJG0jgZkbl +[appendix-impl]: https://hackmd.io/@davidtwco/BJG0jgZkbl#implementation +[appendix-bugs]: https://hackmd.io/@davidtwco/BJG0jgZkbl#bugs-in-the-compiler-or-standard-library +[appendix-cargo-feats]: https://hackmd.io/@davidtwco/BJG0jgZkbl#cargo-feature-requests-narrowly-applied-to-build-std + +[why-not-rustup]: https://hackmd.io/@davidtwco/rkYRlKv_1x +[Opaque dependencies]: https://hackmd.io/@epage/ByGfPtRell + +[JOSH]: https://josh-project.github.io/josh/intro.html +[panic-abort]: https://crates.io/crates/panic-abort +[panic-halt]: https://crates.io/crates/panic-halt +[panic-itm]: https://crates.io/crates/panic-itm +[panic-semihosting]: https://crates.io/crates/panic-semihosting +[rust-lang/cargo]: https://github.com/rust-lang/cargo +[rust-lang/crates.io-index]: https://github.com/rust-lang/crates.io-index +[rust-lang/rust]: https://github.com/rust-lang/rust +[sgx]: https://github.com/apache/incubator-teaclave-sgx-sdk +[wg-cargo-std-aware]: https://github.com/rust-lang/wg-cargo-std-aware +[cargo-xbuild]: https://github.com/rust-osdev/cargo-xbuild +[xargo]: https://github.com/japaric/xargo + +[build-std]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std +[build-std-features]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features +[bootstrap-features-logic]: https://github.com/rust-lang/rust/blob/00b526212bbdd68872d6f964fcc9a14a66c36fd8/src/bootstrap/src/lib.rs#L732 +[bootstrap-features-toml]: https://github.com/rust-lang/rust/blob/00b526212bbdd68872d6f964fcc9a14a66c36fd8/bootstrap.example.toml#L816 +[bootstrap-sanitizers]: https://github.com/rust-lang/rust/blob/d13a431a6cc69cd65efe7c3eb7808251d6fd7a46/bootstrap.example.toml#L388 +[cargo-docs-registry]: https://doc.rust-lang.org/nightly/nightly-rustc/cargo/sources/registry/index.html +[cargo-json-schema]: https://doc.rust-lang.org/cargo/reference/registry-index.html#json-schema +[conditional-compilation-config-options]: https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options +[embed-rs-cargo-toml]: https://github.com/embed-rs/stm32f7-discovery/blob/e2bf713263791c028c2a897f2eb1830d7f09eceb/Cargo.toml#L21 +[platform-support]: https://doc.rust-lang.org/nightly/rustc/platform-support.html +[std-build.rs]: https://github.com/rust-lang/rust/blob/f315e6145802e091ff9fceab6db627a4b4ec2b86/library/std/build.rs#L17 +[std-unsupported]: https://github.com/rust-lang/rust/blob/f768dc01da9a681716724418ccf64ce55bd396c5/library/std/src/sys/pal/mod.rs#L68-L69 +[target-tier-policy]: https://doc.rust-lang.org/nightly/rustc/target-tier-policy.html + +[cargo#10129]: https://github.com/rust-lang/cargo/pull/10129 +[cargo#14317]: https://github.com/rust-lang/cargo/pull/14317 +[cargo#14358]: https://github.com/rust-lang/cargo/pull/14358 +[cargo#4959]: https://github.com/rust-lang/cargo/issues/4959 +[cargo#7216]: https://github.com/rust-lang/cargo/pull/7216 +[cargo#7421]: https://github.com/rust-lang/cargo/pull/7421 +[cargo#8490]: https://github.com/rust-lang/cargo/pull/8490 +[cargo#8798]: https://github.com/rust-lang/cargo/issues/8798 +[crates.io#7306]: https://github.com/rust-lang/crates.io/pull/7306 +[rfcs#1133]: https://github.com/rust-lang/rfcs/pull/1133 +[rfcs#2663]: https://github.com/rust-lang/rfcs/pull/2663 +[rfcs#3516]: https://rust-lang.github.io/rfcs/3516-public-private-dependencies.html +[rfcs#3716]: https://rust-lang.github.io/rfcs/3716-target-modifiers.html +[rust#44663]: https://github.com/rust-lang/rust/issues/44663 +[rust#46439]: https://github.com/rust-lang/rust/pull/46439 +[rust#71009]: https://github.com/rust-lang/rust/issues/71009 +[rust#67074]: https://github.com/rust-lang/rust/issues/67074 +[rust#122305]: https://github.com/rust-lang/rust/pull/128534 +[rust#128534]: https://github.com/rust-lang/rust/pull/128534 +[rust#136966]: https://github.com/rust-lang/rust/issues/136966 + +[wg-cargo-std-aware#2]: https://github.com/rust-lang/wg-cargo-std-aware/issues/2 +[wg-cargo-std-aware#3]: https://github.com/rust-lang/wg-cargo-std-aware/issues/3 +[wg-cargo-std-aware#4]: https://github.com/rust-lang/wg-cargo-std-aware/issues/4 +[wg-cargo-std-aware#5]: https://github.com/rust-lang/wg-cargo-std-aware/issues/5 +[wg-cargo-std-aware#6]: https://github.com/rust-lang/wg-cargo-std-aware/issues/6 +[wg-cargo-std-aware#7]: https://github.com/rust-lang/wg-cargo-std-aware/issues/7 +[wg-cargo-std-aware#8]: https://github.com/rust-lang/wg-cargo-std-aware/issues/8 +[wg-cargo-std-aware#10]: https://github.com/rust-lang/wg-cargo-std-aware/issues/10 +[wg-cargo-std-aware#11]: https://github.com/rust-lang/wg-cargo-std-aware/issues/11 +[wg-cargo-std-aware#12]: https://github.com/rust-lang/wg-cargo-std-aware/issues/12 +[wg-cargo-std-aware#13]: https://github.com/rust-lang/wg-cargo-std-aware/issues/13 +[wg-cargo-std-aware#14-review]: https://github.com/rust-lang/wg-cargo-std-aware/issues/14#issuecomment-2315878717 +[wg-cargo-std-aware#14]: https://github.com/rust-lang/wg-cargo-std-aware/issues/14 +[wg-cargo-std-aware#15]: https://github.com/rust-lang/wg-cargo-std-aware/issues/15 +[wg-cargo-std-aware#16]: https://github.com/rust-lang/wg-cargo-std-aware/issues/16 +[wg-cargo-std-aware#17]: https://github.com/rust-lang/wg-cargo-std-aware/issues/17 +[wg-cargo-std-aware#19]: https://github.com/rust-lang/wg-cargo-std-aware/issues/19 +[wg-cargo-std-aware#20]: https://github.com/rust-lang/wg-cargo-std-aware/issues/20 +[wg-cargo-std-aware#21]: https://github.com/rust-lang/wg-cargo-std-aware/issues/21 +[wg-cargo-std-aware#22]: https://github.com/rust-lang/wg-cargo-std-aware/issues/22 +[wg-cargo-std-aware#23]: https://github.com/rust-lang/wg-cargo-std-aware/issues/23 +[wg-cargo-std-aware#24]: https://github.com/rust-lang/wg-cargo-std-aware/issues/24 +[wg-cargo-std-aware#25]: https://github.com/rust-lang/wg-cargo-std-aware/issues/25 +[wg-cargo-std-aware#26]: https://github.com/rust-lang/wg-cargo-std-aware/issues/26 +[wg-cargo-std-aware#29]: https://github.com/rust-lang/wg-cargo-std-aware/issues/29 +[wg-cargo-std-aware#30]: https://github.com/rust-lang/wg-cargo-std-aware/issues/30 +[wg-cargo-std-aware#36]: https://github.com/rust-lang/wg-cargo-std-aware/issues/36 +[wg-cargo-std-aware#38]: https://github.com/rust-lang/wg-cargo-std-aware/issues/38 +[wg-cargo-std-aware#39]: https://github.com/rust-lang/wg-cargo-std-aware/issues/39 +[wg-cargo-std-aware#40]: https://github.com/rust-lang/wg-cargo-std-aware/issues/40 +[wg-cargo-std-aware#43]: https://github.com/rust-lang/wg-cargo-std-aware/issues/43 +[wg-cargo-std-aware#45]: https://github.com/rust-lang/wg-cargo-std-aware/issues/45 +[wg-cargo-std-aware#46]: https://github.com/rust-lang/wg-cargo-std-aware/issues/46 +[wg-cargo-std-aware#47]: https://github.com/rust-lang/wg-cargo-std-aware/issues/47 +[wg-cargo-std-aware#50]: https://github.com/rust-lang/wg-cargo-std-aware/issues/50 +[wg-cargo-std-aware#51]: https://github.com/rust-lang/wg-cargo-std-aware/issues/51 +[wg-cargo-std-aware#64]: https://github.com/rust-lang/wg-cargo-std-aware/issues/64 +[wg-cargo-std-aware#68]: https://github.com/rust-lang/wg-cargo-std-aware/issues/68 +[wg-cargo-std-aware#69]: https://github.com/rust-lang/wg-cargo-std-aware/issues/69 +[wg-cargo-std-aware#85]: https://github.com/rust-lang/wg-cargo-std-aware/issues/85 +[wg-cargo-std-aware#86]: https://github.com/rust-lang/wg-cargo-std-aware/issues/86 +[wg-cargo-std-aware#87]: https://github.com/rust-lang/wg-cargo-std-aware/issues/87 +[wg-cargo-std-aware#88]: https://github.com/rust-lang/wg-cargo-std-aware/issues/88 +[wg-cargo-std-aware#90]: https://github.com/rust-lang/wg-cargo-std-aware/issues/90 +[wg-cargo-std-aware#92]: https://github.com/rust-lang/wg-cargo-std-aware/issues/92 From 5cff9ffae49f83c287c03eeeebd8c19d54d06cb6 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 31 Oct 2025 11:50:46 +0000 Subject: [PATCH 2/4] rename to rfc 3873 --- text/{0000-build-std-context.md => 3873-build-std-context.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename text/{0000-build-std-context.md => 3873-build-std-context.md} (99%) diff --git a/text/0000-build-std-context.md b/text/3873-build-std-context.md similarity index 99% rename from text/0000-build-std-context.md rename to text/3873-build-std-context.md index 61403426ceb..578b3d08fe4 100644 --- a/text/0000-build-std-context.md +++ b/text/3873-build-std-context.md @@ -1,6 +1,6 @@ - Feature Name: `build-std-context` - Start Date: 2025-06-05 -- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- RFC PR: [rust-lang/rfcs#3873](https://github.com/rust-lang/rfcs/pull/3873) - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) # Summary From c8649ed4bb52564cb34c67367a3c519803990468 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 31 Oct 2025 12:07:33 +0000 Subject: [PATCH 3/4] update forward links --- text/3873-build-std-context.md | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/text/3873-build-std-context.md b/text/3873-build-std-context.md index 578b3d08fe4..185b9d0829b 100644 --- a/text/3873-build-std-context.md +++ b/text/3873-build-std-context.md @@ -27,17 +27,17 @@ and later RFCs will reference this one.** This RFC is part of the - [Background][background] - [History][history] - [Motivation][motivation] -2. `build-std="always"` ([rfcs#XXXX]) - - [Proposal][rfcs#XXXX-proposal] - - [Rationale and alternatives][rfcs#XXXX-rationale-and-alternatives] - - [Unresolved questions][rfcs#XXXX-unresolved-questions] - - [Future possibilities][rfcs#XXXX-future-possibilities] - - [Summary of proposed changes][rfcs#XXXX-summary] -3. Explicit standard library dependencies ([rfcs#XXXX]) - - [Proposal][rfcs#XXXX-proposal] - - [Rationale and alternatives][rfcs#XXXX-rationale-and-alternatives] - - [Unresolved questions][rfcs#XXXX-unresolved-questions] - - [Future possibilities][rfcs#XXXX-future-possibilities] +2. `build-std="always"` ([rfcs#3874]) + - [Proposal][rfcs#3874-proposal] + - [Rationale and alternatives][rfcs#3874-rationale-and-alternatives] + - [Unresolved questions][rfcs#3874-unresolved-questions] + - [Future possibilities][rfcs#3874-future-possibilities] + - [Summary of proposed changes][rfcs#3874-summary] +3. Explicit standard library dependencies ([rfcs#3875]) + - [Proposal][rfcs#3875-proposal] + - [Rationale and alternatives][rfcs#3875-rationale-and-alternatives] + - [Unresolved questions][rfcs#3875-unresolved-questions] + - [Future possibilities][rfcs#3875-future-possibilities] 4. `build-std="compatible"` (RFC not opened yet) 5. `build-std="match-profile"` (RFC not opened yet) @@ -1101,6 +1101,18 @@ standard library. [build-std project goal]: https://rust-lang.github.io/rust-project-goals/2025h2/build-std.html +[rfcs#3874]: https://github.com/rust-lang/rfcs/pull/3874 +[rfcs#3874-proposal]: https://github.com/davidtwco/rfcs/blob/build-std-part-two-always/text/3874-build-std-always.md#proposal +[rfcs#3874-rationale-and-alternatives]: https://github.com/davidtwco/rfcs/blob/build-std-part-two-always/text/3874-build-std-always.md#rationale-and-alternatives +[rfcs#3874-unresolved-questions]: https://github.com/davidtwco/rfcs/blob/build-std-part-two-always/text/3874-build-std-always.md#unresolved-questions +[rfcs#3874-future-possibilities]: https://github.com/davidtwco/rfcs/blob/build-std-part-two-always/text/3874-build-std-always.md#future-possibilities +[rfcs#3874-summary]: https://github.com/davidtwco/rfcs/blob/build-std-part-two-always/text/3874-build-std-always.md#summary-of-proposed-changes +[rfcs#3875]: https://github.com/rust-lang/rfcs/pull/3875 +[rfcs#3875-proposal]: https://github.com/davidtwco/rfcs/blob/build-std-part-three-explicit-dependencies/text/3875-build-std-explicit-dependencies.md#proposal +[rfcs#3875-rationale-and-alternatives]: https://github.com/davidtwco/rfcs/blob/build-std-part-three-explicit-dependencies/text/3875-build-std-explicit-dependencies.md#rationale-and-alternatives +[rfcs#3875-unresolved-questions]: https://github.com/davidtwco/rfcs/blob/build-std-part-three-explicit-dependencies/text/3875-build-std-explicit-dependencies.md#unresolved-questions +[rfcs#3875-future-possibilities]: https://github.com/davidtwco/rfcs/blob/build-std-part-three-explicit-dependencies/text/3875-build-std-explicit-dependencies.md#future-possibilities + [davidtwco]: https://github.com/davidtwco [adamgemmell]: https://github.com/adamgemmell [amanieu]: https://github.com/Amanieu From 1f0a20049236c454c47ceba0c9f5ee0703f6bdf2 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 3 Nov 2025 11:40:35 +0000 Subject: [PATCH 4/4] fix typos, grammatical errors and missing words --- text/3873-build-std-context.md | 81 +++++++++++++++++----------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/text/3873-build-std-context.md b/text/3873-build-std-context.md index 185b9d0829b..e0f4a8fc671 100644 --- a/text/3873-build-std-context.md +++ b/text/3873-build-std-context.md @@ -59,7 +59,7 @@ be able to support many use cases that those waiting for build-std hope that it will. This is also an explicit and deliberate choice for the build-std project goal's proposals. -This RFC will focus on summarising these previous discussion and proposals in +This RFC will focus on summarising these previous discussions and proposals in order to enable an MVP of build-std to be accepted and stabilised. This will lay the foundation for future proposals to lift restrictions and enable build-std to support more use cases, without those proposals having to survey the ten-plus @@ -96,12 +96,11 @@ The following terminology is used throughout the RFC: standard library Throughout the build-std project goal's later RFCs, parentheses with "?" links -([?][rationale-rationale]) will be present that which link the relevant section -in the appropriate "Rationale and alternatives" section to justify a decision or -provide alternatives to it. +([?][rationale-rationale]) will be present which link to the relevant "Rationale +and alternatives" section to justify a decision or provide alternatives to it. Additionally, "note alerts" will be used in the *Proposal* sections to separate -implementation considerations from the core proposal. Implementation detail +implementation considerations from the core proposal. Implementation details should be considered non-normative. These details could change during implementation and are present solely to demonstrate that the implementation feasibility has been considered and to provide an example of how implementation @@ -312,7 +311,7 @@ from the sysroot. `--extern` has a `noprelude` modifier which will allow the user to use `--extern` to specify the location at which a crate can be found without adding it to the extern prelude. This could allow a path for crates like `alloc` or -`test` to be provided without effecting the observable behaviour of the +`test` to be provided without affecting the observable behaviour of the language. ## Panic strategies @@ -320,10 +319,10 @@ language. Rust has the concept of a *panic handler*, which is a crate that is responsible for performing a panic. There are various panic handler crates on crates.io, -such as [panic-abort] (which different from the `panic_abort` panic runtime!), -[panic-halt], [panic-itm], and [panic-semihosting]. Panic handler crates define -a function annotated with `#[panic_handler]`. There can only be one -`#[panic_handler]` in the crate graph. +such as [panic-abort] (which is different from the `panic_abort` panic +runtime!), [panic-halt], [panic-itm], and [panic-semihosting]. Panic handler +crates define a function annotated with `#[panic_handler]`. There can only be +one `#[panic_handler]` in the crate graph. `core` uses the panic handler to implement panics inserted by code generation (e.g. arithmetic overflow or out-of-bounds access) and the `core::panic!` macro @@ -373,8 +372,8 @@ what its dependencies are, etc. Cargo can query registries using a Git protocol which caches the registry on disk, or using a sparse protocol which exposes the index over HTTP and allows -Cargo to avoid Cargo having a local copy of the whole index, which has become -quite large for crates.io. +Cargo to avoid having a local copy of the whole index, which has become quite +large for crates.io. crates.io's registry index is exposed as both a HTTP API and a Git repository - [rust-lang/crates.io-index] - both are updated automatically by crates.io when @@ -385,11 +384,11 @@ Each crate in the registry index has a JSON file, following and crates.io teams. Crates may refer to those in other registries, but all non-`path`/`git` crates in the dependency graph must exist in a registry. As the registry index drives the building of Cargo's dependency graph, all -non-`path`/`git` crates that end up in the dependency graph must be present a +non-`path`/`git` crates that end up in the dependency graph must be present in a registry. When a package is published, Cargo posts a JSON blob to the registry which is -not a index entry but has sufficient information to generate one. crates.io does +not an index entry but has sufficient information to generate one. crates.io does not use Cargo's JSON blob, instead re-generating it from the `Cargo.toml` (this avoids the index and `Cargo.toml` from going out-of-sync due to bugs or malicious publishes). As a consequence, changes to the index format must be @@ -414,7 +413,7 @@ so as to make it easier to avoid breaking semver compatibility. With the `public-dependency` feature enabled, dependencies are marked as "private" by default which can be overridden with a `public = true` declaration. -Private dependencies are passed to rustc with an `priv` modifier to the +Private dependencies are passed to rustc with a `priv` modifier to the `--extern` flag. Dependencies without this modifier are treated as public by rustc for backwards compatibility reasons. rust emits the `exported-private-dependencies` lint if an item from a private dependency is @@ -453,9 +452,9 @@ This RFC proposed that the standard library be made an explicit dependency in `Cargo.toml` and be rebuilt automatically when required. An implicit dependency on the standard library would be added automatically unless an explicit dependency is written. This RFC was written prior to a stable `#![no_std]` -attribute and so does not address the circumstance where a implicit dependency -would make a no-std crate fail to compile on a target that does not support -the standard library. +attribute and so does not address the circumstance where an implicit dependency +would make a `#![no_std]` crate fail to compile on a target that does not +support the standard library. There were objectives of and possibilities enabled by the RFC that were not shared with the project teams at the time, such as the standard library being @@ -467,7 +466,7 @@ of [cargo#4959]. ## [xargo] and [cargo#4959] (2016) [xargo-and-cargo-4959-2016]: #xargo-and-cargo4959-2016 -While the discussions around [rfcs#1133] where ongoing, [xargo] was released in +While the discussions around [rfcs#1133] were ongoing, [xargo] was released in 2016. Xargo is a Cargo wrapper that builds a sysroot with a customised standard library and then uses that with regular Cargo operations (i.e. `xargo build` performs the same operation as `cargo build` but with a customised standard @@ -505,18 +504,18 @@ and applying different codegen flags to the standard library. It did not concern itself with build-std's potential use in `rustbuild` or with abolishing the sysroot. -[rfcs#2663] was primarily concerned what functionality should be available to -the user and what the user experience ought to be. It proposed that `core`, -`alloc` and `std` be automatically built when the target did not have a pre-built -standard library available through rustup. It would be automatically rebuilt on -any target when the profile configuration was modified such that it no longer -matched the pre-built standard library. If using nightly, the user could enable -Cargo features and modify the source of the standard library. Standard library -dependencies were implicit by default, as today, but would be written explicitly -when enabling Cargo features. It also aimed to stabilise the target-spec-json -format and allow "stable" Cargo features to be enabled on stable toolchains, and -as such proposed the concept of stable and unstable Cargo features be -introduced. +[rfcs#2663] was primarily concerned with what functionality should be available +to the user and what the user experience ought to be. It proposed that `core`, +`alloc` and `std` be automatically built when the target did not have a +pre-built standard library available through rustup. It would be automatically +rebuilt on any target when the profile configuration was modified such that it +no longer matched the pre-built standard library. If using nightly, the user +could enable Cargo features and modify the source of the standard library. +Standard library dependencies were implicit by default, as today, but would be +written explicitly when enabling Cargo features. It also aimed to stabilise the +target-spec-json format and allow "stable" Cargo features to be enabled on +stable toolchains, and as such proposed the concept of stable and unstable Cargo +features be introduced. There was a lot of feedback on [rfcs#2663] which largely stemmed from it being very high-level, containing many large unresolved questions and details left for @@ -577,7 +576,7 @@ categories: entirety seems to be uncertain. [`cargo vendor`][wg-cargo-std-aware#23] did receive lots of discussion. - Vendoring the standard library is desirable (for the same reasons as any + Vendoring the standard library is desirable (for the same reasons as any vendoring), but would lock the user to a specific version of the toolchain when using a vendored standard library. However, if the `rust-src` component contained already-vendored dependencies, then `cargo vendor` would not need @@ -694,9 +693,9 @@ categories: [wg-cargo-std-aware#43] investigates the options for the UX of build-std. `-Zbuild-std` flag is not a good experience as it needs added to every - invocation and has few extension points. Using build-std should be a unstable - feature at first. It was argued that build-std should be transparent and - happen automatically when Cargo determines it is necessary. There are + invocation and has few extension points. Using build-std should be an + unstable feature at first. It was argued that build-std should be transparent + and happen automatically when Cargo determines it is necessary. There are concerns that this could trigger too often and that it should only happen automatically for ABI-modifying flags. @@ -806,12 +805,12 @@ and target , but this restriction was later resolved ([cargo#14317]). A second flag, [`-Zbuild-std-features`][build-std-features], was added in [cargo#8490] and allows overriding the default Cargo features of the standard -library. Like the arguments to `-Zbuild-std`, this values accepted by this flag +library. Like the arguments to `-Zbuild-std`, the values accepted by this flag are inherently unstable as the library team has not committed to any of the standard library's Cargo features being stable. Features are enabled on the `sysroot` crate and propagate down through the crate graph of the standard -library (e.g. `compiler-builtins-mem` is a feature in `sysroot`, `std`, -`alloc`, and `core` until `compiler_builtins`). +library (e.g. `compiler-builtins-mem` is a feature in `sysroot`, `std`, `alloc`, +and `core` until `compiler_builtins`). build-std gets the source of the standard library from the `rust-src` rustup component. This does not happen automatically and the user must ensure the @@ -988,7 +987,7 @@ rebuild the standard library. - Similarly, when deploying to known environments, use of `target-cpu` or `target-feature` can improve the performance of code generation or allow the use of newer hardware features than the target's baseline provides. As - above, these configuration will not apply to the pre-built standard + above, these configurations will not apply to the pre-built standard library - While the pre-built standard library is built to support debugging without @@ -1022,7 +1021,7 @@ this goal will attempt to ensure they remain viable as future possibilities): flags that would not be appropriate for the pre-built standard library, so is forced to require nightly and build its own sysroot -Some use cases are unlikely to supported by the project unless a new and +Some use cases are unlikely to be supported by the project unless a new and compelling use-case is presented, and so this project goal may make decisions which make these motivations harder to solve in future: @@ -1187,7 +1186,7 @@ standard library. [rust#46439]: https://github.com/rust-lang/rust/pull/46439 [rust#71009]: https://github.com/rust-lang/rust/issues/71009 [rust#67074]: https://github.com/rust-lang/rust/issues/67074 -[rust#122305]: https://github.com/rust-lang/rust/pull/128534 +[rust#122305]: https://github.com/rust-lang/rust/pull/122305 [rust#128534]: https://github.com/rust-lang/rust/pull/128534 [rust#136966]: https://github.com/rust-lang/rust/issues/136966