From c7e099a3df5653a28c8642d56b796bde019a4640 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 22 Jul 2025 12:01:56 +0000 Subject: [PATCH 01/96] build-std: context Co-authored-by: Adam Gemmell --- text/0000-build-std/0-introduction.md | 87 + text/0000-build-std/1-background.md | 302 ++++ text/0000-build-std/2-history.md | 536 ++++++ text/0000-build-std/3-motivation.md | 97 + .../4-appendix-literature-review.md | 1593 +++++++++++++++++ 5 files changed, 2615 insertions(+) create mode 100644 text/0000-build-std/0-introduction.md create mode 100644 text/0000-build-std/1-background.md create mode 100644 text/0000-build-std/2-history.md create mode 100644 text/0000-build-std/3-motivation.md create mode 100644 text/0000-build-std/4-appendix-literature-review.md diff --git a/text/0000-build-std/0-introduction.md b/text/0000-build-std/0-introduction.md new file mode 100644 index 00000000000..c7826feba4e --- /dev/null +++ b/text/0000-build-std/0-introduction.md @@ -0,0 +1,87 @@ +- Feature Name: `build-std` +- 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 + +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. Due to the length of this RFC, it +is split over multiple files to avoid rendering issues and slow loading on some +platforms. + +### Scope +[scope]: #scope + +build-std, as proposed by this RFC, has many restrictions and limitations that +mean it will not support most use cases that those waiting for build-std hope +that it will. This is an explicit and deliberate choice. + +This RFC will focus on resolving the key questions that will enable a 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+ years of issues, pull requests +and discussion that this RFC has. + +As a general rule, this RFC tries to answer the question "what crates of the +standard library get built and when do they get built" and considers anything +else as likely out-of-scope. + +### Terminology +[terminology]: #terminology + +The following terminology is used throughout the RFC: + +- "the standard library" is used to refer to all of the crates that comprise the + standard library - `core`, `alloc` and `std` +- "std" is used to refer only to the `std` crate, not the entirety of the standard + library + +# Contents +[contents]: #contents + +This RFC has the following contents: + +1. [Summary][summary] (you are here) + + - Introduction to the proposal, its scope, terminology/conventions used and + the structure of the RFC + +2. [Background](./1-background.md) + + - Detailed explanations of how relevant and impacted parts of the Rust + toolchain currently work + +3. [History](./2-history.md) + + - Chronological summary of the various proposals and discussions that have + taken place relating to the ability to rebuild the standard library, and + of the current experimental implementation in Cargo + +4. [Motivation](./3-motivation.md) + + - Descriptions of the varied problems that build-std has been proposed as a + solution to + +5. [Appendix II: Exhaustive literature review](./4-appendix-literature-review.md) + + - More detailed summaries of the relevant issues, discussions, pull requests + and proposals that comprise the history of the build-std feature since + 2015 + + - [*History*](./2-history.md) aims to summarise this content further and + cover everything that should be necessary to understand the proposal + +[davidtwco]: https://github.com/davidtwco +[adamgemmell]: https://github.com/adamgemmell \ No newline at end of file diff --git a/text/0000-build-std/1-background.md b/text/0000-build-std/1-background.md new file mode 100644 index 00000000000..d669ab9ecb4 --- /dev/null +++ b/text/0000-build-std/1-background.md @@ -0,0 +1,302 @@ +# Background +[background]: #background + +See [*Implementation summary*][implementation-summary] for a summary of the +current unstable build-std feature in Cargo. This section aims to introduce any +relevant details about the standard library and compiler that are assumed +knowledge by referenced sources and later sections. + +## 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 support the standard library or have a pre-built standard +library distributed via rustup. This depends on the tier of support for the +target. According to rustc's [platform support][platform-support] documentation, +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. + +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 the standard library with +a `path` source (e.g. `core = { path = "../my_core" }`), but crates with these +dependencies are not accepted by crates.io. 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]) - 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 isn't used when `std` is built as `libc` provides these routines, + but is often used by `no_std` crates when there is not a system `libc` +- 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. 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. + +### 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. + +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. There is no mechanism for users to enable the `restricted_std` +feature on behalf of dependencies. There is also no such mechanism for `alloc` +or `core`, only `std`. + +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` even +on stable toolchains, though the JSON format is unstable. Custom targets do not +have a pre-built standard library and so must use `-Zbuild-std`. 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 are the set of crates that +have been loaded by the compiler as direct dependencies. 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 +automatically loaded and added to the extern prelude. + +`std` is automatically loaded and added to the extern prelude. For `#![no_std]` +crates, `core` is loaded and added to the extern prelude instead. For `std` or +`core` as appropriate, an additional `use $crate::prelude::rust_20XX::*` is +injected for common items that Rust does not require users import (e.g. +`Option`). + +`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` is also a panic handler. `std`'s panic handler and `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` and +`panic_abort` - each with a corresponding panic strategy. 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 has a `panic_immediate_abort` feature which modifies the +`core::panic!` macro to immediately call the abort intrinsic without calling the +panic handler. `std` and `alloc` have the same feature which enable the feature +in `core`. `std`'s feature also adds an immediate abort to its `panic!` macro. + +## Cargo +[background-cargo]: #cargo + +Cargo's building of the dependency graph is driven by the registry index. +[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 crates are available, what their dependencies +are, etc. crates.io's registry index is a Git repository - +[rust-lang/crates.io-index] - which is updated automatically by crates.io when +crates are published, yanked, 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. + +Each crates in the registry has a JSON file, following +[a defined schema][cargo-json-schema]. Crates may refer to those in other +registries, but all crates in the dependency graph must exist in a registry. As +the registry index drives the building of Cargo's dependency graph, all crates +that end up in the dependency graph must be present a registry. + +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. + +[implementation-summary]: ./2-history.md#implementation-summary + +[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/crates.io-index]: https://github.com/rust-lang/crates.io-index +[rust-lang/rust]: https://github.com/rust-lang/rust + +[rfcs#3716]: https://rust-lang.github.io/rfcs/3716-target-modifiers.html +[rust#46439]: https://github.com/rust-lang/rust/pull/46439 +[rust#44663]: https://github.com/rust-lang/rust/issues/44663 + +[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 +[target-tier-policy]: https://doc.rust-lang.org/nightly/rustc/target-tier-policy.html +[std-build.rs]: https://github.com/rust-lang/rust/blob/f315e6145802e091ff9fceab6db627a4b4ec2b86/library/std/build.rs#L17 +[platform-support]: https://doc.rust-lang.org/nightly/rustc/platform-support.html diff --git a/text/0000-build-std/2-history.md b/text/0000-build-std/2-history.md new file mode 100644 index 00000000000..834d97244d1 --- /dev/null +++ b/text/0000-build-std/2-history.md @@ -0,0 +1,536 @@ +# History +[history]: #history + +*The following summary of the prior art is necessarily less detailed than the +source material, which is exhaustively surveyed in +[Appendix II: Exhaustive literature review][appendix-ii].* + +## [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. + + [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-ii-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-ii-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-ii-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-ii-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. + +`-Zbuild-std` builds `std` by default. `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 a virtual 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]. + +## 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]: ./3-motivation.md +[appendix-ii]: ./4-appendix-literature-review.md +[appendix-ii-impl]: ./4-appendix-literature-review.md#implementation +[appendix-ii-bugs]: ./4-appendix-literature-review.md#bugs-in-the-compiler-or-standard-library +[appendix-ii-cargo-feats]: ./4-appendix-literature-review.md#cargo-feature-requests-narrowly-applied-to-build-std + +[JOSH]: https://josh-project.github.io/josh/intro.html +[rust-lang/cargo]: https://github.com/rust-lang/cargo +[rust-lang/rust]: https://github.com/rust-lang/rust +[wg-cargo-std-aware]: https://github.com/rust-lang/wg-cargo-std-aware +[xargo]: https://github.com/japaric/xargo + +[Opaque dependencies]: https://hackmd.io/@epage/ByGfPtRell + +[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 +[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 +[rust#128534]: https://github.com/rust-lang/rust/pull/128534 +[rust#67074]: https://github.com/rust-lang/rust/issues/67074 +[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#2]: https://github.com/rust-lang/wg-cargo-std-aware/issues/2 +[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#3]: https://github.com/rust-lang/wg-cargo-std-aware/issues/3 +[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#4]: https://github.com/rust-lang/wg-cargo-std-aware/issues/4 +[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#5]: https://github.com/rust-lang/wg-cargo-std-aware/issues/5 +[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#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#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#8]: https://github.com/rust-lang/wg-cargo-std-aware/issues/8 +[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 + +[build-std-features]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features +[build-std]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std +[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 + +[Ericson2314]: https://github.com/Ericson2314 +[epage]: https://github.com/epage \ No newline at end of file diff --git a/text/0000-build-std/3-motivation.md b/text/0000-build-std/3-motivation.md new file mode 100644 index 00000000000..47609940bc3 --- /dev/null +++ b/text/0000-build-std/3-motivation.md @@ -0,0 +1,97 @@ +# Motivation +[motivation]: #motivation + +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 +re-build the standard library. + +1. **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 + +2. **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 + +3. **Building the standard library on a stable toolchain without Cargo** + + - While tangential to the core of build-std as a feature, projects like Rust + for Linux want to be able to build an unmodified `core` from `rust-src` in + the sysroot on a stable toolchain without Cargo + - Cargo may also want a mechanism to build the standard library for build-std + on a stable toolchain without relying on `RUSTC_BOOTSTRAP` + +4. **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`) + +5. **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]) + +6. **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 + +7. **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 + +8. **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 a feature like `optimize_for_size` or + `panic_immediate_abort` to reduce binary size + +9. **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 + +[cargo-xbuild]: https://github.com/rust-osdev/cargo-xbuild +[xargo]: https://github.com/japaric/xargo + +[rfcs#3716]: https://rust-lang.github.io/rfcs/3716-target-modifiers.html +[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#4]: https://github.com/rust-lang/wg-cargo-std-aware/issues/4 +[wg-cargo-std-aware#7]: https://github.com/rust-lang/wg-cargo-std-aware/issues/7 + +[sgx]: https://github.com/apache/incubator-teaclave-sgx-sdk \ No newline at end of file diff --git a/text/0000-build-std/4-appendix-literature-review.md b/text/0000-build-std/4-appendix-literature-review.md new file mode 100644 index 00000000000..027947a792a --- /dev/null +++ b/text/0000-build-std/4-appendix-literature-review.md @@ -0,0 +1,1593 @@ +# Appendix II: Exhaustive literature review +[appendix-ii]: #appendix-ii-exhaustive-literature-review + +This section will attempt to summarize every issue, pull request, RFC and +discussion related to the design and implementation of build-std since its +conception in May 2015. If anything has been omitted then that's just an +oversight and it can be added. The summaries may not reflect current up-to-date +information if those updates weren't in the discussion being summarized. +Up-to-date information should be present when these issues are referenced in the +previous sections. + +This section's level of detail is not strictly necessary to understand this RFC, +the summary at the start of the [History][history] section should be +sufficient, but this section should help if more detail is desired on some +referenced material. + +## [rfcs#1133] (2015) +[a1-rfcs-1133-2015]: #rfcs1133-2015 + +This section contains all of the sources related to [rfcs#1133]. + +- **[rfcs#1133]: Make Cargo aware of standard library dependencies**, + [Ericson2314], May 2015 + - This is the first RFC that proposed making Cargo aware of the standard + library + - It was motivated by.. + - ..better support for cross-compilation to targets that cannot have + pre-built std due to strange configuration requirements + - ..building std with different configurations (e.g. panic + strategies/features/etc) + - ..simplifying `rustbuild` + - The RFC proposes both that the standard library should be explicitly listed + as a dependency in `Cargo.toml` and that it should be rebuilt when necessary + - `std = { version = "1.10", stdlib = true }` is the proposed syntax for a + `std` dependency in `Cargo.toml` + - `version = "*"` is also acceptable. As today, a package specifying a + version for the standard library will be rejected by crates.io + - `stdlib = true` defines the source of the dependency (similarly to `git` + or `path`) + - As the compiler/language version is tied to the standard library + version, this is effectively declaring an MSRV + - This dependency would be implicitly added to all crates unless a + standard library dependency is explicitly written + - i.e. writing `core = ..` would prevent the default `std = ..` + dependency from being added implicitly + - An `implicit-dependencies` key would also be added and to determine + whether implicit standard library dependencies are added. This is to + be able to write the `Cargo.toml` of the `core` crate + - `no_std` was not stable at the time of this RFC being written, so + the RFC does not address the circumstance where an implicit + dependency may make an existing `no_std` crate fail to build for a + tier three target that does not support the standard library + - The RFC is written prior to the introduction of the `rust-src` component + and assumes that other implementations of the compiler may exist that will + have their own standard library implementations and that the feature must + support that + - A description of how the feature could be implemented in Cargo is + provided: + - Add implicit dependencies as early as possible so the majority of Cargo + requires fewer changes + - `stdlib = true` generates a "source id" mapping to either a compiler + source directory (e.g. `rust-src` today) or a "sysroot binary mock + source" + - A "sysroot binary mock source" is the source containing the pre-built + standard library and is found by searching the sysroot for the + standard library rlib + - It always builds the source if present, falling back to the sysroot + rlibs otherwise + - The RFC argues that as the configuration of the standard library to + build is not known, the implementation must be conservative (e.g. no + features are enabled) + - It is intended that rustc would never use the sysroot (by passing + `--sysroot=''`) + - The standard library would not be added to lockfiles, the implementation + argues that there would be no value in adding it + - The RFC aims to be forward-compatible with the standard library source + being replaced by users and that parts of the standard library could be on + crates.io + - The RFC also suggests adding a mechanism for this to be introduced to + Cargo as an unstable feature, as Cargo had no mechanism for this when the + RFC was written + - There was varied feedback over a period of three years, initially: + - The advantage of replacing the standard library was not clear, as + `std = { path = "..." }` is already possible with Cargo (and used by some + projects to wrap the standard library) + - This doesn't work if a user wants to replace `std` over the entire + dependency graph + - Declaring a standard library dependency explicitly in all crates was seen + as unfortunate by some as it was redundant in many cases + - [xargo] was mentioned for the first time in May 2016. + - [cargo#2768] was opened as an initial implementation of the RFC. + - After core/std was being built using bootstrap and Cargo, there was another + burst of activity on the RFC: + - Supporting `compiler-rt` was raised as a challenge, but it was argued that + this wasn't a blocker as they are not necessary for the very bare metal + use-case intended by the author + - Lots of possibilities that the RFC enabled were raised on the discussion + thread + - There was discussion about what would trigger a build of std versus re-use + of std from the sysroot: + - The RFC wasn't exceptionally clear on this, but it appears that the + intent was for the `Cargo.toml` to be the source-of-truth for what a + package needs, and that the environment/profile settings determine + whether a build needs to happen + - Cargo would pass `--sysroot-whitelist` with a list of crate names to + the compiler when it determines that rustc should be permitted to use + the pre-built artifacts from the sysroot + - It was repeatedly expressed by the author and advocates of the RFC that a + ideal final state would be that the sysroot as a concept not exist (at + least for loading dependencies) + - Contemporary project members discussed the RFC and shared their + conclusions: + - Sysroot crates being specified with a special syntax is reasonable + - Putting std on crates.io is a non-goal + - The sysroot exists and won't go away anytime soon + - A known location in the sysroot for the std sources is desirable/good + - The std facade should be a normal part of the crate DAG + - This was not true when the comment was written in July 2016 + - It should be possible to override features of the sysroot crates + - Features should be used to avoid C dependencies + - Sysroot replacement poses stability concerns so must be restricted to + nightly + - By August 2016, the participating project members seemed quite happy with + the RFC and shared some more feedback: + - There was interest in requiring semver versions for the standard library, + as a pseudo-MSRV + - `build-dependencies` and `dev-dependencies` shouldn't have explicit + standard library dependencies + - Didn't want a `--no-resolve-sysroot` flag (to prevent loading crates from + the sysroot) as this would break people who use unstable crates from the + sysroot + - There were specific implications identified with respect to + versioning/dependency specification: + - Crates in the sysroot would need to have the same version as the + compiler + - Standard library dependencies effectively allow language version pinning + - A `^1.0` version would add constraints on Rust 2 + - It would stabilise the name of `test` + - A mechanism for building unstable code in the sysroot on the stable + compiler would be necessary + - This is the current use case desired by Rust for Linux + - There were many concerns about avoiding abuse of this and discussion + of mechanisms to confirm that only the intended unstable crates were + built on a stable compiler + - The RFC stalled for a few months and then was blocked by a mechanism for + unstable Cargo features in July 2017 + - In February 2018, the RFC was closed in favour of [cargo#4959] +- **[cargo#2768]: Phase 1 of stdlib dependencies**, [Ericson2314], Jun 2016 + - An initial implementation of [rfcs#1133]. + - This PR received almost no feedback. +- **[cargo#5002]: Explicit standard library dependencies**, [Ericson2314], Feb + 2018 + - A issue split-off from [rfcs#1133] with the goal of discussing how explicit + dependencies on the standard library could work + - This issue received no feedback +- **[cargo#5003]: Implicit standard library dependencies**, [Ericson2314], Feb + 2018 + - A issue split-off from [rfcs#1133] with the goal of discussing how implicit + dependencies on the standard library could work + - This issue received no feedback + +## [xargo] and [cargo#4959] (2016) +[a1-xargo-and-cargo-4959-2016]: #xargo-and-cargo4959-2016 + +This section contains all of the sources related to [xargo] and [cargo#4959]: + +- **[xargo]**, [japaric], Mar 2016 + - A developer tool that wraps Cargo to provide build-std-like functionality + - Built while [rfcs#1133] was still being discussed + - Builds custom sysroots based on the configuration in a `Xargo.toml` + - Requires nightly as it builds the standard library and gets standard + library sources from the `rust-src` component + - Supports multi-stage builds, features, flags, etc. + - Xargo is used instead of Cargo and has the same command line interface, but + ensures that the locally-built sysroots are used + - In maintenance mode since January 2018 + - Cargo team were interested in incorporating its functionality at the time +- **[cargo#4959]: Sysroot building functionality**, [japaric], Jan 2018 + - Successor of [rfcs#1133], inspired by [xargo] + - Xargo was fairly widely used but had issues due to being a wrapper around + Cargo rather than a part of Cargo + - It didn't replicate Cargo's fingerprinting so would unnecessarily perform + rebuilds + - It didn't track changes to sysroot sources to trigger rebuilds when they + changed + - It didn't have a rustup shim so users couldn't use the toolchain selection + arguments typical of rustup shims (e.g. `+nightly`) + - There were deviations from built-in Cargo commands + - It suggested adding a `[sysroot]` section in the `.cargo/config` + - Could specify features/flags/stages for + `core`/`compiler_builtins`/`alloc`/`std`/etc + - Can also specify `rust-src` path + - Optional, defaults to `rust-src` component path + - If set, Cargo would rebuild sysroot crates for targets, put them in the + `target` directory and use them for rustc/rustdoc/etc + - These would be rebuilt when profiles change, using Cargo's usual + fingerprinting mechanism + - These crates would always be built using the release profile + - Like xargo, would support multi-stage builds + - e.g. `std` built with default sysroot, then `test` built in sysroot w/ + new `std`, then a new sysroot made with both the new `test` and new + `std` + - None of it would apply to `build.rs` + - There was a variety of feedback: + - There should be restrictions on what crates could be put in the sysroot + should be added so that this mechanism could not be used for third-party + crates + - Procedural macros would also need to use the host sysroot + - Syntax was not user-friendly enough + - The ability to customise std and not require the `rust-src` component be + used was requested + - Similarly, requests for `[patch]` sections + - There was a mention of a imminent merging of rustup and Cargo which could + be relevant + - Spoiler: this didn't happen + - Exposing bootstrap stages is cumbersome, error-prone and brittle and Cargo + should just figure that part out automatically + - There were arguments against further reliance on the sysroot as a concept + - Incremental/IDE support is allegedly more challenging with the sysroot + - Some proposed features in the ether circa March 2018 related to + module-system namespacing/lighter `extern crate` would be made more + challenging if the entire sysroot were automatically imported + - Many of the other arguments against the sysroot were actually arguments + against a pre-built standard library that cannot possibly satisfy all + users +- **[cargo-xbuild]**, [rust-osdev], May 2018 + - A simplified fork of `xargo` + - Wrapper around `cargo build` that uses a custom sysroot according to the + configuration in `package.metadata.cargo-xbuild` in `Cargo.toml` + - Now recommends using `--build-std` in Cargo instead + +## [rfcs#2663] (2019) +[a1-rfcs-2663-2019]: #rfcs2663-2019 + +This section contains all of the sources related to [rfcs#2663]: + +- **[rfcs#2663]: `std` Aware Cargo**, [jamesmunns], Mar 2019 + - Re-building the standard library in this proposal is motivated by: + - Being able to use the standard library with tier three and custom targets + that do not have a pre-built standard library + - Customising the standard library with different feature flags + - Applying different codegen flags to the standard library + - This proposal largely focuses on what the user experience of build-std + should be and has many unresolved questions and details left for the + implementers to work out + - Unlike [rfcs#1133], this RFC only focuses on when the standard library + should be rebuilt, rather than how a dependency on the standard library + should be declared + - It is primarily inspired by [xargo] and also cites [rfcs#1133], + [cargo#5002] and [cargo#5003] + - There are four objectives of the RFC: + - Allow core to be recompiled when a target isn't available from rustup + - This should be possible on a stable toolchain, but will require nightly + to.. + - ..set feature flags + - ..modify core + - Cargo should recompile core when a custom target spec is used, feature + flags are modified, profile configuration is changed or the sysroot is + patched + - As above, on a stable toolchain, only the profile configuration will + be able to be changed to trigger a rebuild + - Only the root crate's feature flags and profiles would be respected, + not those of dependencies + - Unless opting into Cargo features, core does not need to be explicitly + specified as a dependency in `Cargo.toml` + - Sources for core are from the `rust-src` component + - The proposal lists three implications of the above feature: + - Target specification format would need to be stabilised + - It isn't explained why this is a necessary implication + - Rust implementation of `compiler_builtins` would need to be used for + custom targets + - `RUSTC_BOOTSTRAP` needs to be set for core + - Allow use of "stable" Cargo features from Cargo + - This section proposes that a mechanism exist to declare Cargo features + as stable and unstable and that only stable features be usable on the + stable channel (i.e. resolving [cargo#10881]) + - There are no specifics on how these features would be declared, but + the syntax for using a feature is described as being identical for + stable and unstable features + - Unstable feature flags in the standard library could be stabilised by + following the same stabilisation process as anything else in the + standard library + - The proposal does not mention anything about the unification of the + features of the dependencies of the standard with those same + dependencies of the user's crate + - Allow alloc/std to be recompiled when a target isn't available and allow + use of "stable" Cargo features from alloc/std + - Exactly as above + - Doesn't address complexities with alloc/std - when does Cargo need to + build alloc or std and not just core? How does Cargo know this? + - Allow users to provide their own versions of core/alloc/std + - Would always require nightly + - Suggests using regular patch syntax under `patch.sysroot` key + - There are many unresolved questions in the RFC: + - How to specify a dependency on the standard library in a crate? + - How does a `no_std` crate tell Cargo it doesn't need to build std? + - Should std be rebuilt if core is? + - Should there be tamper-detection for the standard library? + - Should the standard library be built locally (per project) or globally + (shared between projects)? + - What to do with the standard library's `Cargo.lock`? + - Should profile overrides *always* rebuild std? + - Should providing a custom standard library require nightly? + - Should customising the standard library be permitted? + - There are also a handful of future possibilities mentioned: + - core/std could be unified into a single crate with different features to + represent the differences that exist between the crates + - The project could choose to stop shipping a precompiled standard library + - This RFC was sufficiently vague that it was unlikely to be accepted as + written - to accept it is largely to assert that something like build-std is + desired, which is not controversial, but the tricky details which make + build-std difficult would still need to be designed and discussed + - A variety of feedback was received: + - Enabling customisation of std may not be practical because it would + require all combinations of Cargo feature flags be tested + - It is asserted that this testing would be necessary without considering + alternatives (such as a documented stability policy for the standard + library's feature flags) + - It is suggested that only feature flags of omission (that remove parts + of the standard library) be used to avoid this + - It was later relayed that Cargo features do not work this way + - Another suggestion was only no flags enabled and all flags enabled could + be tested and that this would be sufficient + - There is disagreement over whether specifying a custom standard library + should require nightly + - It is already possible to specify a standard library dependency in + `Cargo.toml` with a path and have it override that crate + - At the time of the conversation, this was used by the `embed-rs` crate + to override some of the standard library's future types + ([source][embed-rs-source]/[`Cargo.toml`][embed-rs-cargo-toml]) + - Some argue that it should be possible to do this on stable because any + alternative implementation would necessarily only build on nightly + anyway + - It is argued both that the target-spec-json format *would* and *would not* + need to be stabilised if it were supported by build-std + - As build-std would make it more practical to use these custom targets on + a stable toolchain, some argue that the format would need to be made + stable + - The host sysroot would need to be used for `build.rs` and procedural + macros + - There are C dependencies of the standard library that are difficult to + build and would need some consideration of this to ensure the usability of + build-std + - `libbacktrace` has been replaced by `gimli` so this is less of a concern + now + - There are concerns that rebuilding the standard library whenever the + profile is changed would be too disruptive + - e.g. changing the optimisation level triggering a rebuilding of std + would add to compilation times + - It is suggested that the standard library only be rebuilt if a crate + adds an explicit dependency on them + - Cargo's default profiles may not match the configuration of the + pre-built standard library + - Research is required to ensure that the default configuration of the + standard library is known to Cargo and not just bootstrap + - Alternatively, only rebuild for ABI-modifying flags + - Sanitizers require sanitizer runtimes to be present and these are not + configured by Cargo features + - Stable/unstable Cargo features is an RFC of its own + - Only considering the root crate would break dependencies that enable + specific standard library features + - Cargo needs to know what crates to build when a rebuild is triggered + - e.g. only `core`, `alloc` too, `std` as well? + - There are various arguments that the standard library and its crates + should not be special-cased in any way + - There is pushback to this arguing that the standard library is + inherently special + - Trying to make the standard library a regular crate that is versioned, + on crates.io and does not exist in the sysroot is often raised in + these prior art and makes build-std much more complicated and less + likely to succeed + - Users should have the option of using the C implementation of + `compiler_builtins` + - Crates will need to be able to specify a lack of dependency on the + standard library (e.g. `no_std` crates) + - It is important that a pre-compiled standard library and locally-compiled + standard library have identical behaviour + - t-lang [discussed the RFC in a meeting][rfcs#2663-t-lang] + - There weren't any concerns, except: + - Niko raised that putting something behind a Cargo feature that was + previously not gated behind a Cargo feature breaks users who use + `default-features = false` and this should be resolved as it has + implications for the standard library's development + - It was suggested that `default-features = false` could be prohibited + for standard library dependencies + - Ultimately closed with interested parties directed to the + [wg-cargo-std-aware] repository + - There was additional feedback in the draft version of the RFC which was + shared with some project members - [jamesmunns/rfcs#1] + - Initially the RFC did not clarify when Cargo would trigger a rebuild + - Cargo needs to know how not to do any of the proposed machinery for the + `core` and `compiler_builtins` crates itself + - `rustc_inherit_overflow_checks` could be removed + - Cargo features enabled in the standard library cannot just be decided by + the root crate + - There was disagreement about whether this is accurate + - Interactions with `rustc-std-workspace-core` are unclear + - `patch.sysroot.$crate` key rather than re-using `patch.$crate` makes the + standard library special + +## [wg-cargo-std-aware] (2019-) +[a1-wg-cargo-std-aware-2019-]: #wg-cargo-std-aware-2019- + +After the above issues, pull requests, RFCs and discussions, the +[wg-cargo-std-aware] was created to host issues related to build-std and the +effort which resulted in the current unstable implementation of build-std. + +Unlike prior art which predates [wg-cargo-std-aware], [wg-cargo-std-aware]'s +issues capture the majority of the tricky details involved in build-std but +often do not have much discussion to summarise. + +Issues in [wg-cargo-std-aware] are very varied and so are split into eight +categories in this proposal: + +### Use cases +[use-cases]: #use-cases + +These issues collect and elaborate on the use cases that users have for +build-std: + +- **[wg-cargo-std-aware#2]: Build the standard library with custom profile + settings**, [ehuss], Jul 2019 + - Currently, the standard library is only available with the profile settings + chosen when Rust is distributed + - "release" profile with `codegen-units=1` and `opt-level=2` + - Using different settings is desirable + - When build-std builds Cargo, it should build using the current profile + - Profile overrides can be used to use different settings for the standard + library specifically + - Users currently do not expect the standard library to be rebuilt when + changing the profile + - e.g. setting `opt-level=3` will not currently rebuild std and if it + started to do so then this could significantly increase build times for + small projects + - At time of writing, build-std was intended to be strictly opt-in so this + would not be an issue + - It was later clarified that the concern was not "whether configured + profile settings would apply to the standard library", but rather "whether + that always triggers a rebuild" + - build-std should always re-use pre-built artifacts if such artifacts + exist and match the desired profile + - Risk that profile overrides could expose internal details about the standard + library, like the `compiler_builtins` crate +- **[wg-cargo-std-aware#3]: Build the standard library for an unsupported + target**, [ehuss], Jul 2019 + - build-std is desired to make it easier to build the standard library for + targets that do not have a pre-built standard library, including unsupported + targets (i.e. `no_std` environments) and custom targets (using + target-spec-json) + - Tools like [xargo] and [cargo-xbuild] are used to do this + - Custom targets are already supported by Cargo, so work for + [wg-cargo-std-aware#2] should overlap + - `no_std` binaries often require nightly features + - `core` is not maximally portable + - It may be worth exploring how to lower the barrier to porting the standard + library to a new platform using build-std +- **[wg-cargo-std-aware#4]: Build the standard library with different cargo + features**, [ehuss], Jul 2019 + - Some users want to enable or disable Cargo features to remove or modify + parts of the standard library + - e.g. to change the formatting machinery to emphasise code size, or remove + panic machinery when unused + - There was agreement that this customisation should be limited to code behind + `cfg(feature = "..")` attributes, not arbitrary `cfg`s + - [cargo#8490] added `-Zbuild-std-features=` to support this experimentally + - An example provided was wanting to be able to toggle whether `RefCell` could + provide backtraces when panicking for outstanding borrows +- **[wg-cargo-std-aware#7]: Custom source standard library**, [ehuss], Jul 2019 + - Some users want to be able to replace the source of the standard library + with a custom implementation + - The issue notes that this is unlikely to be stabilised in the foreseeable + future + - It was suggested that it would be better to allow the user to supply a + pre-built artifact for any dependency in the crate graph + - As of 2022, miri needed its own sysroot build and used [xargo] to do that +- **[wg-cargo-std-aware#19]: Use in rustbuild**, [Ericson2314], Jul 2019 + - build-std could be used as part of the [rust-lang/rust] bootstrap, this + would.. + - ..simplify bootstrap + - ..reduce gap between official and user builds + - ..demonstrate that Cargo is expressive enough + - Most discussion took place in internals thread + - See *Dogfooding -Z build-std in rustbuild* below +- **[wg-cargo-std-aware#36]: Better understand the no_std binary use case**, + [ehuss], Sep 2019 + - `no_std` binaries can be tricky (e.g. may require manually linking libc) and + it would be nice if this were smoother + - This use-case seems adjacent to build-std +- **[wg-cargo-std-aware#42]: metaprogramming and bootstrapping**, + [Ericson2314], Sep 2019 + - `build.rs` and `proc_macro` ought to be able to leverage build-std too + - There was no further relevant discussion +- **[wg-cargo-std-aware#61]: Can we tailor the compiler-builtins package that is + compiled and linked together with the core crate?**, [parraman], Nov 2020 + - User wants to change the `compiler_builtins` version using build-std + - Closed as duplicate of [wg-cargo-std-aware#7] +- **internals.r-l.o: [Dogfooding -Z build-std in rustbuild][wg-cargo-std-aware#19-internals]**, [Ericson2314], Jan 2021 + - Proposes using `-Zbuild-std` in rustbuild in order to dogfood it to more + users + - Suggests that this would lead to Cargo needing to learn some of bootstrap's + current behaviour and that Cargo would need to be changed more often to + accommodate changes that bootstrap receives + - Suggests that changing the Cargo version contained within a beta release + would make this easier + - More detail is provided on how this could be implemented + - This would require building rustc with the beta standard library + - At the time this was seen as unlikely, but has since been implemented + ([rust#119899]) + - This implication was rejected as it was argued that `-Zbuild-std` would + eventually allow a different source to be used + - `-Zbuild-std` *might* be useful for bootstrap but using it in bootstrap is + unlikely to help advance the stabilisation of build-std + - There was detailed discussion about the degree to which `x.py` is just a + wrapper around Cargo and whether the sysroot is necessary + - Rust for Linux developers add that it is important for their use case that + there is a simple way to build the standard library without requiring Cargo + - Ideally with a mechanism for doing this using a stable toolchain +- **[wg-cargo-std-aware#77]: Cannot test bug fixes of dependencies of + `libcore`/`libstd` on targets where `-Zbuild-std` is required**, [cr1901], Nov + 2021 + - User wants to change the `compiler_builtins` version to test upcoming + bugfixes + - Closed as duplicate of [wg-cargo-std-aware#7] + +### Support for build-std in Cargo's subcommands +[support-for-build-std-in-cargo-subcommands]: #support-for-build-std-in-cargos-subcommands + +These issues discuss the complexity involved in supporting build-std in specific +subcommands of Cargo: + +- **[wg-cargo-std-aware#20]: Support `cargo metadata`**, [ehuss], Sep 2019 + - `cargo metadata` outputs machine-readable JSON containing an array of all of + the packages in the workspace + - The format has some stability guarantees + - build-std would need to be supported in `cargo metadata` but the issue does + not describe how that should work + - There was no discussion on the issue +- **[wg-cargo-std-aware#21]: Support `cargo clean`**, [ehuss], Sep 2019 + - `cargo clean -p std` doesn't work but should + - There was no discussion on the issue +- **[wg-cargo-std-aware#22]: Support `cargo fetch`**, [ehuss], Sep 2019 + - Implemented by [jyn514] in [cargo#10129] + - Fetches crates.io dependencies of the standard library and should continue + to do this if the dependencies are not vendored +- **[wg-cargo-std-aware#23]: Support `cargo vendor`**, [ehuss], Sep 2019 + - `cargo vendor` doesn't understand build-std + - Vendoring the standard library and its dependencies would lock the user to a + specific toolchain version, which would not be desirable + - If `rust-src` contained a vendored standard library then `cargo vendor` + would not need changed + - Makes source replacement or `path` overrides challenging to implement + - At the time of writing, vendoring the standard library was difficult as + `cargo vendor` does not support vendoring a subset of the packages in a + workspace, and the standard library did not have its own workspace at the + time + - Implemented by [Gankra] in [cargo#8834] and [rust#78790] by adding `patch` + entries to all members to use the vendored crates + - Later reverted in [cargo#8968] and [rust#79838] due to regressions + - [cargo#8962]: Cargo was always updating the registry index with + `-Zbuild-std` + - [cargo#8963]: Cargo was producing unused patch warnings with + `-Zbuild-std-features=compiler-builtins-mem` + - [cargo#8945]: Custom targets were broken as Cargo didn't expect + `rustc-std-workspace` in the vendored dependencies + - Using patches to emulate vendoring (by changing `path`) is not correct and + proper vendoring should be used + - [rust#128534] moved the standard library to its own workspace which should + make vendoring possible + - There were some suggestions that using a vendored standard library should + be optional as it prevents patching the standard library +- **[wg-cargo-std-aware#24]: Support `cargo pkgid`**, [ehuss], Sep 2019 + - `cargo pkgid` doesn't support build-std but should + - There was no discussion on the issue +- **[wg-cargo-std-aware#26]: Possibly support `-p` for standard library + dependencies**, [ehuss], Sep 2019 + - `-p` normally works for any dependency + - There was discussion of how `-p` could work if `-Zbuild-std` were the final + interface for build-std + - There is a risk of leaking the dependencies of the standard library + depending on how this support is implemented +- **[wg-cargo-std-aware#45]: Support --build-plan**, [ehuss], Sep 2019 + - `--build-plan` does not include anything from build-std + - [cargo#7614] is a long and still-actively-discussed thread discussing the + future of `--build-plan` with mixed opinions + - `--build-plan` is still unstable so support for build-std can be a blocker + for it if build-std lands first or vice-versa +- **[wg-cargo-std-aware#83]: Allow std to be specified as package spec**, + [dullbananas], Apr 2023 + - User wants to use `-p` with build-std, closed as duplicate of + [wg-cargo-std-aware#26] + +### Dependencies of the standard library +[appendix-dependencies-of-the-standard-library]: #dependencies-of-the-standard-library + +These issues discuss the challenges involved in building some of the +dependencies of the standard library: + +- **[wg-cargo-std-aware#15]: Deps compiler_builtin**, [ehuss], Jul 2019 + - There's a `c` feature of this crate that uses optimised C versions for some + of the intrinsics + - This is used by default + - The `mem` feature of this crate provides some demangled symbols used in + `no_std` builds of `alloc` when there is not a `libc` to provide those + symbols + - Built using a large number of codegen units to force each function to into + its own unit + - [rust#135395] attempted to fix compiler-builtins' codegen unit + partitioning in the compiler + - It forced the compiler to use a large number of codegen units for the + compiler-builtins crate + - There is a tension between the embedded use-case for compiler-builtins' + intrinsics and what Rust for Linux wants + - RfL depends on compiler-builtins being compiled into a single object + file + - It was mentioned that almost all intrinsics now have a Rust implementation + and that could be made the default for build-std eventually + - Some concerns that this would result in divergence between locally-built + and distributed standard libraries +- **[wg-cargo-std-aware#16]: Deps: backtrace**, [ehuss], Jul 2019 + - `libbacktrace` previously required a C compiler but has since been replaced + by `gimli` in the standard library and so this is no longer an issue + ([rust#46439]) +- **[wg-cargo-std-aware#17]: Deps: sanitizers**, [ehuss], Jul 2019 + - At the time of writing, sanitizers are a dependency of the standard library + and require LLVM components (located using `LLVM_CONFIG`) + - It is suggested that the implementation of sanitizers could be revisited so + that they are distributed as plain libraries alongside rustc and linking + against them rather than rebuilding them as part of build-std + - There would be no dependency on LLVM sources outside of building rustc. + [rust#31605] could be resurrected to do this. +- **[wg-cargo-std-aware#18]: Deps: proc-macro**, [ehuss], Jul 2019 + - Procedural macros are already built with the host sysroot so wouldn't use a + customised standard library +- **[wg-cargo-std-aware#65]: Does not work with vendoring**, [raphaelcohn], Feb + 2021 + - Closed as duplicate of [wg-cargo-std-aware#23] + +### Design considerations +[design-considerations]: #design-considerations + +These issues document open design questions for build-std: + +- **[wg-cargo-std-aware#5]: Cargo standard library dependencies**, [ehuss], Jul + 2019 + - How will a dependency on the standard library be expressed in `Cargo.toml`? + - There are various requirements laid about by the issue: + - Users should have to opt-in to build the standard library + - It should be able to support alternative standard library implementations + - Cargo needs to be able to pass `--extern name` to specify explicit + dependencies to add to the extern prelude, even for pre-build artifacts + - References [rfcs#1133], [rfcs#2663], [cargo#5002], [cargo#5003], [rust#57288] + - [rust#57288] tracks the effort to stop requiring `extern crate`. As of + October 2023: + - `--extern proc_macro` passed by Cargo to avoid needing + `extern crate proc_macro` + - `extern crate test` is still required, but `test` is unstable + - `extern crate std`/`extern crate alloc` still required for `no_std` - + Cargo has no way of knowing that a no_std crate uses std and that + `--extern crate std` ought to be used + - `extern crate core` as above for `no_core` + - How does Cargo handle multiple crates in the graph declaring dependencies + on the standard library? + - Unify them, there is no concept of a "version" for the standard library + dependencies + - e.g. a union of all features + - How to balance implicit vs explicit dependencies on the standard library? + - Existing stable crates depend on the standard library implicitly + - Tempting to declare every crate does unless opting out + - Existing stable `no_std` crates do not have an explicit opt-out but are + compatible with targets that work without a standard library at all + - How to express a dependency on a pre-built artifact vs building from source? + - Users could have no direct control, rebuilds are triggered based on other + factors (e.g. profile settings, target, feature flags, etc) if a pre-built + artifact does not exist for that configuration + - Any differences between a locally-built artifact and pre-built artifact is + a bug + - It was suggested that the *Pre-Pre-RFC: making `std`-dependent Cargo + features features a first-class concept* proposal be adopted (see below) +- **[wg-cargo-std-aware#6]: Target specification?**, [ehuss], Jul 2019 + - build-std makes target-spec-json more usable on stable and project teams + will need to decide if they are comfortable with the current format or if it + needs changed + - Custom targets are more likely to require nightly as not having a standard + library, they will need nightly to use build-std + - If is opined that if build-std allows the standard library to be built for + custom targets then that should require an explicit decision to stabilise + the format + - e.g. if `cargo +stable build --target=foo.json` works then the format is + de-facto stable + - The standard library's `build.rs` checks for whole target string which + doesn't support custom targets very well + - There are a handful of general requests of the target-spec-json format: + - Switch to TOML + - Clean up LLVM-specific details + - Allow inherited specs + - Use them in rustc rather than defining them in code +- **[wg-cargo-std-aware#8]: Standard library portability**, [ehuss], Jul 2019 + - Discusses needs for making the standard library more portable and configurable + - i.e. not strictly build-std related but build-std benefits from a more + portable standard library + - References a bunch of previous/related efforts: + - [rfcs#1502] + - [internals.r-l.o: Fleshing out libstd scenarios] + - [internals.r-l.o: Refactoring libstd for ultimate portability] + - [rfcs#1868] + - [A vision for portability in Rust] + - [portability-wg] + - [embedded-wg] + - Somewhat out-of-scope for wg-cargo-std-aware + - The mechanism for increasing portability may need to be exposed via + `Cargo.toml` (e.g. features) + - It is an impediment of making it easier to build std for unsupported targets +- **[wg-cargo-std-aware#11]: Downloading source**, [ehuss], Jul 2019 + - rustup can download `rust-src` which doesn't include the dependencies of the + standard library, but does include the `Cargo.lock` + - Preference that rustup not be required + - Acquiring dependencies may be challenging + - build-std needs to be transparent to be a first-class feature + - Cargo has support for downloading various things but needs to know where + the source is + - rustup knows toolchain and commit but Cargo doesn't + - Could have a reasonable default probing location (e.g. for distros) and + could query rustup + - [cargo#2768] allowed the user to specify a path in their configuration + - Could publish the source for each standard library version to crates.io +- **[wg-cargo-std-aware#12]: `Cargo.lock` and dependency resolution**, [ehuss], Jul 2019 + - Very likely that the standard library will need to be built with the same + dependency versions as distributed version + - May end up with different versions of dependencies as the user's crate + - Locking dependencies may be good to guarantee determinism + - Closed assuming that this is a settled question + - Current implementation uses a separate resolve to keep dependency versions + separate from user's dependency versions +- **[wg-cargo-std-aware#13]: Default feature specification**, [ehuss], Jul 2019 + - How to determine the default set of cfg values for the standard library? + - Currently set by bootstrap + - Also sets environment variables used by build scripts (e.g. `LLVM_CONFIG`) + - Various possibilities + - Hardcode in Cargo, not idea long-term + - Some configuration in source distribution + - Make user explicitly declare them + - Similar to [wg-cargo-std-aware#4] +- **[wg-cargo-std-aware#14]: Default flags and environment variables**, + [ehuss], Jul 2019 + - There are additional rustc flags passed to standard library crates which + could be duplicated initially but not long-term + - There are suggestions that a config file may be necessary as in + [wg-cargo-std-aware#13] + - There is overlap with [wg-cargo-std-aware#28] + - There is a summary of the differences in flags between bootstrap and + build-std in + [wg-cargo-std-aware#14 (comment)][wg-cargo-std-aware#14-review] +- **[Pre-Pre-RFC: making `std`-dependent Cargo features features a first-class + concept][wg-cargo-std-aware#5-internals]**, [bascule], Aug 2019 + - API guidelines say that Cargo features should be strictly additive and that + gating std support should be behind a `std` feature + - `no_std` users end up always using `default-features = false` and opting + into everything except `std` + - Unintentionally enabled `std` features can prevent linking, often deep in + dependency hierarchies + - Proposes top-level `std-features = true` that automatically enables or + disables the `std` features of dependencies +- **[wg-cargo-std-aware#29]: Support different panic strategies**, [ehuss], Sep 2019 + - Current implementation hardcoded for `unwind` + - How does Cargo know what to use? Inspecting the profile? + - Always build both `unwind`/`abort`? + - `-Cpanic=abort` needs to be passed for `abort` crate + - Some targets default to `abort` + - `abort` crates currently rebuild w/ `unwind` when built with `libtest` + - Cargo should work transparently - user sets `panic` in their profile and Cargo + respects that and handles everything else + - As everything is compiled by Cargo, can lift restrictions like `-Cpanic=abort` + being necessary for `panic_abort` crate + - Cargo should be able to take a more "pure" stance relative to `libtest` + - [rust#64158] later merged supporting `panic=abort` with `libtest` + - It is not yet stable ([rust#67650]) + - Ideally only compile one panic strategy crate + - Target-specific settings are tricky + - Almost all cases of building the standard library from source are `panic=abort` + targets w/ no unwinding support + - Is profile sufficient to build `panic_abort`/`panic_unwind`? + - Some crates don't want any panic strategy - when not using the standard library, + not defining a panic strategy may make sense + - `std` has `#![needs_panic_runtime]` + - build-std may require `-Zpanic-abort-tests` +- **[wg-cargo-std-aware#30]: Figure out how to handle target-specific + settings**, [ehuss], Sep 2019 + - Some targets have special logic and it isn't clear how this can be handled + by Cargo + - Often target-specific and toolchain-related + - Can potentially whitelist or blacklist targets +- **[wg-cargo-std-aware#38]: Consider doing a forced lock of the standard + library**, [ehuss], Sep 2019 + - Ensure that the in-memory `Cargo.lock` is not modified + - Hard to guarantee in practice + - Could add a test to assert this + - [cargo#13916] attempted to add a check to verify the virtual workspace + for the standard library post-resolve is a strict subset of it + pre-resolve + - [rust#128534]/[cargo#14358] meant that the standard library has its own + workspace and build-std does not need to generate one + - On-disk lockfile is now used so do not need to worry about it changing + - Still need to implement `--locked` behaviour + - Doing so would break `[patch]` with build-std +- **[wg-cargo-std-aware#39]: Figure out interaction with public/private dependencies**, [ehuss], Sep 2019 + - Public/private status of the standard library is hardcoded to public in MVP - should + it be? + - If defined in `Cargo.toml`, it will likely inherit visibility from that, which defaults + to private. +- **[wg-cargo-std-aware#43]: What will the UX be for enabling "build libstd" + logic?**, [alexcrichton], Sep 2019 + - How will build-std eventually be enabled? + - At time of writing, `-Zbuild-std=$crates`, but what should the eventual + syntax be? + - e.g. `build.std` option in `Cargo.toml` or `.config/cargo` + - Opting into build-std as an unstable feature should be a `-Z` flag or entry + in `cargo-features` + - Eventually not a flag at all, and Cargo should try to compile the standard + library automatically if a compiled standard library is not available + - Concern that the pre-compiled standard library may not match by default + and there would be too many false-positive rebuilds + - For missing targets, need to distinguish between forgetting to run + `rustup target add` and needing to compile the standard library + - `[profile]` could not affect the standard library by default + - There are cases where implicit rebuilding could be desirable + - e.g. ABI-modifying flags + - Passing a flag on every invocation is not a good user experience + - [cargo#10308] is a prototype with explicit standard library dependencies + - Idea posted on internals, see *Build-std and the standard library* below + - If enabled manually, [cargo#8733] expressed the need to enable build-std + only for certain targets, in particular when cross-compiling to no-std + targets +- **[wg-cargo-std-aware#46]: How to handle special object files?**, [ehuss], Sep 2019 + - How to handle pre-built object files needed to link on a target? + - e.g. `crt1.o`, `crti.o`, `crtn.o`, etc for musl or `dllcrt2.o`, + `crt2.o`, etc for Windows GNU + - Cargo is target agnostic and does not want to hardcode logic for particular + targets + - The target definitions define which files they expect to find and link + against + - [rust#68887] adds a `self-contained` directory which could help +- **[wg-cargo-std-aware#47]: how to handle pre-built linkers?**, [ehuss], Sep + 2019 + - Some pre-built targets ship with a copy of rust-lld or gcc to assist with + linking + - `rust-lld` could be shipped as a rustup component or the user could be + forced to install these components + - Since this issue was filed, `rust-lld` is now always shipped + - rustc finds `rust-lld` via the sysroot and if the sysroot is not provided + then another mechanism will need to be used to find `rust-lld` +- **[wg-cargo-std-aware#50]: Impact on build scripts that invoke rustc**, [jdm], Oct 2019 + - Need to make sure that build scripts that invoke rustc are able to do this with the correct + standard library + - Closed as t-cargo do not want to encourage or support build probes +- **[wg-cargo-std-aware#51]: Plan for removal of `rustc-dep-of-std`**, [ehuss], Nov 2019 + - `rustc-dep-of-std` is a feature that packages used as dependencies of `std` have that, + when enabled, use to declare explicit dependencies of `core`/`compiler_builtins`/etc + - May not be necessary once these packages are always declaring dependencies on + `core`/etc + - Cargo would still need to work out what to do when seeing explicit dependencies + - These dependencies could always be built with build-std but that would involve + using build-std in bootstrap which may not be desirable + - Alternatively, have some mechanism for telling Cargo that the explicit dependencies + in this instance aren't from the sysroot but an rlib from bootstrap + - Could be automatic or variation on patch syntax +- **[wg-cargo-std-aware#57]: Support building workspace with separate build-std + parameters**, [jschwe], Jun 2020 + - User wants to have one package depend on `core` and `alloc` and another + package depend on `core`, `alloc` and `std` but this isn't possible with the + current experimental flag + - Closed as duplicate of [wg-cargo-std-aware#5] +- **[wg-cargo-std-aware#68]: Support Profile Guided Optimisation (PGO)**, [errantmind], Mar 2021 + - `profiler_builtins` isn't compatible with `no_core` + - i.e. `profiler_builtins` requires `core` so if building with profiling, need to + build `core` first w/out the profiling instrumentation + - [rust#79958] improves the error message for this +- **internals.r-l.o: [Build-std and the standard library][wg-cargo-std-aware#43-internals]**, [ehuss], Dec 2019 + - Proposes changing the standard library so all of its crates can build on all + targets + - It may not work and not all APIs will be available, but there will be no + compilation errors + - i.e. add runtime errors or cfgs + - Makes things simpler because build-std can become a simple toggle + - Building an empty standard library is preferred over not building at all as + this avoids breaking `no_std` crates that build for tier three targets with + no standard library support at all + - Suggestion that the standard library use Cargo features more so that most + functionality is gated by default + - Fixes this issue as most of the standard library would be absent by + default + - Some prefer that the standard library be listed in the `Cargo.toml` + eventually but that this would work initially + - Explicit standard library dependencies are being considered + - It could be a inconvenience to need to specify the standard library + dependencies in most cases + - Most packages don't need it + - Need default for packages that do not specify a standard library + dependency + - References to the "portability lint" + - Lint that triggers when calling an available platform-specific code so + that users can avoid making code less portable + - Lint was later deemed infeasible + - Described as necessary step towards long-standing goal to move from a + multiple-crates model of the standard library to a cfg-flag model + - Cargo could learn what targets a package supports + - e.g. libstd could declare this + - Doesn't work for custom targets (i.e. target-spec-json) + - Could accidentally allow the standard library to be used in `no_std` + projects + - Adds noise to `Cargo.toml` +- **[wg-cargo-std-aware#85]: Figure out rust-lang/rust testing strategy**, [ehuss], Mar 2023 + - How to test build-std when it is tightly coupled to the standard library source tree? + - Could use rust-toolstate but wasn't very good + - Could use git subtrees (or [JOSH]) + - Could aim to reduce coupling between the standard library and Cargo + - Which targets get tested and how? +- **[wg-cargo-std-aware#86]: Consider limiting supported targets in initial + stabilization**, [ehuss], Mar 2023 + - Supporting build-std on all targets is a large effort so consider + supporting fewer targets initially + - There could be a concept of stability for targets w/ build-std + - i.e. this target works with build-std on nightly only + - Generally supportive reception but every contributor wanted their target to be + one of the supported ones +- **[wg-cargo-std-aware#88]: `cargo doc -Zbuild-std` doesn't generate. links to the standard library**, [jyn514], Jun 2023 + - Cargo doesn't treat the standard library as coming from crates.io and the standard + library doesn't have `html_root_url` set, so local documentation doesn't get links to + the standard library + - Bootstrap passes `-Zcrate-attr="doc(html_root_url=..)"` +- **[cargo#12375]: artifact-dependencies doesn't compose well with build-std**, [tamird], Jul 2023 + - The current unstable implementation of build-std is required when building + for tier three targets but it is impossible to enable it for an artifact + dependency. +- **[wg-cargo-std-aware#90]: restricted_std applicability to custom JSON targets**, [Mark-Simulacrum], Feb 2024 + - The standard library's `build.rs` changed to use `TARGET_OS` rather than an complete + target name so JSON targets don't end up enabling `restricted_std` + - Need to work out what guarantees are desired + - Should std-supported be a property of the target, not `build.rs`? + - Idea behind the current approach: + - Slightly modified target specs should continue to work and permit usage of the + standard library + - Different target specs that are very different from existing targets ought not + permit usage of the standard library + - [rust#71009] needs to be resolved first + - Aims to de-stabilise target specifications, making it prohibited to pass one to + the compiler + - cc [wg-cargo-std-aware#6] + - If target-spec-json is unstable then their behaviour with build-std is also unstable +- **[wg-cargo-std-aware#92]: Consider flag to mark unstable targets**, [madsmtm], Feb 2024 + - Tier three targets are required to use nightly because of build-std + - Stable build-std effectively stabilises these targets, so users would stop using + nightly and get fixes less frequently + - Is a notion of unstable or incomplete targets desirable? +- **[wg-cargo-std-aware#95]: Use `build-std=core` on a custom target + automatically**, [nazar-pc], Mar 2024 + - Closed as duplicate of [wg-cargo-std-aware#43] + +### Implementation +[implementation]: #implementation + +These issues include bug reports for the current unstable implementation of +build-std, as well as unresolved questions for the implementation, both from +[wg-cargo-std-aware]. In addition, this section will list the pull requests in +[rust-lang/cargo] and [rust-lang/rust] that directly contributed to the +implementation. + +- **[cargo#7216]: Basic standard library support.**, [ehuss], Aug 2019 + - Initial implementation of `-Zbuild-std` + - Constructed a synthetic workspace for the standard library and used + `--extern` to provide the new dependencies to rustc. + - Required `--target` to be passed so that the host sysroot was used for build + scripts and procedural macros. +- **[cargo#7336]: Add `alloc` and `proc_macro` to libstd crates**, [alexcrichton], Sep 2019 + - Ensures `alloc` and `proc_macro` are also built when `std` is +- **[wg-cargo-std-aware#25]: Remove requirement for `--target`**, [ehuss], Sep 2019 + - `--target` must be specified to require Cargo run in cross-compilation mode (as + the `proc_macro` crate needs the host sysroot) + - Fixed in [cargo#14317] +- **[wg-cargo-std-aware#27]: Possibly publish a synthetic `Cargo.toml`**, [ehuss], Sep 2019 + - build-std initially had to create a false `Cargo.toml` for the standard library as it + was part of a workspace with the rest of rust-lang/rust + - Fixed by [cargo#14358] (after [rust#128534]) +- **[wg-cargo-std-aware#28]: Fixup some crate flags**, [ehuss], Sep 2019 + - Some crates require special compiler flags which are scattered throughout bootstrap + - e.g. `compiler_builtins` uses `debug-assertions=no`, `codegen-units=1`, `panic=abort` + - cc [wg-cargo-std-aware#15] + - There will always be some implicit contract between the standard library and build-std + - Move these to `Cargo.toml` wherever possible + - Progress made in [rust#64316] + - Bootstrap has been improved so there is less of this - target-specific and + sanitizer parts remain +- **[wg-cargo-std-aware#31]: Possibly add a way to disable the sysroot on + `rustc`**, [ehuss], Sep 2019 + - Implementation uses `--extern` to tell rustc where to find the standard library but it + will look in the sysroot for any crate that was not provided with an `--extern` + argument + - This can end up loading sysroot versions of the standard library and with + duplicate language item errors + - Was closed when build-std used `--sysroot` in [cargo#7421] and then re-opened when + it changed back to `--extern` in [cargo#7699] +- **[wg-cargo-std-aware#33]: Consider better testing strategy**, [ehuss], Sep 2019 + - build-std's testing in Cargo after the initial implementation wasn't very good and has + since been improved +- **[wg-cargo-std-aware#34]: Consider mixing `__CARGO_DEFAULT_LIB_METADATA` into the + hash**, [ehuss], Sep 2019 + - Environment variable is used for embedding the release channel into the metadata + hash but does not appear to be necessary for build-std +- **[wg-cargo-std-aware#35]: Consider not building std as a dylib**, [ehuss], Sep 2019 + - The standard library's manifest builds it as both a rlib and a dylib + - build-std only needs the rlib + - Don't want to produce the dylib and have anyone depend on it always being built + - Fixed by [cargo#7353] +- **[wg-cargo-std-aware#37]: Consider setting `require_optional_deps` to `false` for + standard library**, [ehuss], Sep 2019 + - Workspace created for the standard library sets `require_optional_deps` to `true` + but probably doesn't need to + - Fixed in [cargo#7337] +- **[cargo#7337]: Don't resolve std's optional dependencies**, [alexcrichton], Sep 2019 + - Unrequested optional dependencies are typically the `dev-dependencies` of + `std` and so don't need to be built + - Fixes [wg-cargo-std-aware#37] +- **[cargo#7350]: Improve test suite for -Zbuild-std**, [alexcrichton], Sep 2019 + - Many improvements to build-std testing, primarily the introduction of a + "mock-std" workspace which mimics the standard library's structure and + allows tests to run much quicker + - Fixes [wg-cargo-std-aware#33] +- **[rust#64316]: Delete most of `src/bootstrap/bin/rustc.rs`**, [alexcrichton], Sep 2019 + - Moved most of the standard library's configuration from the rustc shim in + bootstrap to the standard library using Cargo features, so it could be + leveraged by `-Zbuild-std` +- **[wg-cargo-std-aware#40]: Using `--extern` is apparently not equivalent to + `--sysroot`**, [alexcrichton], Sep 2019 + - Using `--extern alloc=alloc.rlib` meant that writing `extern crate alloc` was + not required, which is different than putting `alloc.rlib` in the sysroot where + `extern crate alloc` would still be required + - A consequence of this is that a locally compiled standard library would not + require `extern crate alloc` while the pre-compiled standard library would + - build-std switched to using the sysroot in [cargo#7421] and then switched back to + using `--extern` in [cargo#7699] (once `--extern noprelude:alloc=alloc.rlib` was + added) +- **[cargo#7421]: Change build-std to use --sysroot**, [ehuss], Sep 2019 + - The initial implementation used `--extern` to provide rustc the newly-built + standard library artifacts to later rustc invocations. This did not have + identical behaviour to the existing pre-built artefacts in the sysroot + ([wg-cargo-std-aware#40]) + - Negated the need to prevent rustc from using the sysroot + ([wg-cargo-std-aware#31]) + - Instead, this PR constructed a sysroot in Cargo's `target` directory and passed + that to rustc to replace the default sysroot + - It was found that this sysroot approach could still allow users to depend on + sysroot crates without declaring a dependency on + it([wg-cargo-std-aware#49]) +- **[wg-cargo-std-aware#41]: Documentation on how to use the new cargo-std support in + place of cargo xbuild**, [alex], Sep 2019 + - Fixed by adding documentation on build-std to Cargo's unstable feature documentation +- **[wg-cargo-std-aware#44]: Disable incremental for std crates**, [ehuss], Sep 2019 + - Incremental is not necessary for build-std + - Fixed in [cargo#8177] +- **[wg-cargo-std-aware#48]: Investigate custom libdir setting**, [ehuss], Sep 2019 + - Cargo expects a specific sysroot layout that can be changed with `bootstrap.toml` + - Intended to switch to `--print=target-libdir` from [rust#69608] + - Later made irrelevant by [cargo#7699] +- **[wg-cargo-std-aware#49]: Usage of `--sysroot` may still be racy and/or allow false + dependencies**, [alexcrichton], Oct 2019 + - Later made irrelevant by [cargo#7699] where `--extern` is used again +- **[cargo#7699]: Switch build-std to use --extern**, [ehuss], Dec 2019 + - A revert of [cargo#7421], but uses new `--extern` options `priv` and + `noprelude` from [rust#67074] + - Adding standard library crates to the extern prelude was the cause of + [wg-cargo-std-aware#40] + - Re-opened [wg-cargo-std-aware#31] but fixes [wg-cargo-std-aware#49] +- **[wg-cargo-std-aware#53]: `compiler_builtins` seems to be missing + symbols**, [tomaak], Jan 2020 + - `compiler_builtins` provides symbols through the `mem` feature + - It is not enabled by default as the standard library typically gets + these symbols through the platform `libc` + - `libc`'s implementation is typically better optimized + - Some `no_std` targets need compiler_builtins' implementations + - A concept of "target-specific features" could be beneficial + - Supporting custom targets makes this tricky + - `compiler-builtins-mem` feature is forwarded through standard library + crates to `compiler_builtins` + - [compiler-builtins#411] added weak linkage to the mem functions in compiler-builtins +- **[cargo#7931]: build-std: remove sysroot probe**, [ehuss], Feb 2020 + - An optimisation to remove an unnecessary `rustc --print` invocation +- **[wg-cargo-std-aware#54]: Adjust libstd to make non-Rust dependencies + optional**, [nagisa], Apr 2020 + - Cross-compiling the standard library's `C` dependencies is difficult + - The standard library now uses `gimli` not backtrace which makes this easier + - `libunwind` can be linked with `-Clink-self-contained` + - linux-musl and fortanix-sgx both may still require a C compiler + - Unclear if this can be avoided +- **[wg-cargo-std-aware#55]: Persistent unused attribute warnings when recompiling + libcore after linker flags are changed**, [cr1901], Apr 2020 + - Issue with incremental compilation, fixed by [cargo#8177] (cc [wg-cargo-std-aware#44]) +- **[cargo#8177]: build-std: Don't treat std like a "local" package**, [ehuss], Apr 2020 + - Adds the concept of a "local" package (not controlled by the user) + - `build-std` no longer uses incremental or dep-info fingerprint tracking and + will not show warnings in standard library crates + - Closed [wg-cargo-std-aware#44] and [wg-cargo-std-aware#55] +- **[wg-cargo-std-aware#62]: Linker can't find `core::panicking::panic` when lto is turned + on**, [hnj2], Nov 2020 + - `panic` can't be found with LTO turned on + - compiler-builtins wasn't being built with `overflow-checks=false` and + `debug-assertions=false` +- **[cargo#8490]: Add a `-Zbuild-std-features` flag**, [alexcrichton], Jul 2020 + - Allows users to enable Cargo features from the standard library +- **[rust#77086]: Include libunwind in the rust-src component**, [ehuss], Sep 2020 + - Includes `src/llvm-project/libunwind` in `rust-src` which is needed by some + targets, such as musl targets, to build the unwind crate +- **[cargo#8834]: Patch in vendored dependencies in `rust-src`**, [Gankra], November 2020 + - A step towards supporting `cargo vendor` ([wg-cargo-std-aware#23]) + - Allow for the `rust-src` component to include vendored dependencies of the standard + library + - Reverted in [cargo#8968] due to: + - [cargo#8962]: `-Zbuild-std` always updates the registry index + - [cargo#8963]: unused patch warnings when using + `-Zbuild-std-features=compiler-builtins-mem` + - [cargo#8945]: `-Zbuild-std` with custom targets was broken +- **[rust#78790]: Vendor libtest's dependencies in the rust-src component**, [Gankra], Nov 2020 + - [rust-lang/rust] half of [cargo#8834] + - Reverted in [rust#80082] as it caused `x.py dist` to always require + network access ([rust#79218]) +- **[wg-cargo-std-aware#63]: Support code-coverage**, [catenacyber], Dec 2020 + - Finding duplicate language item when building with `-Zinstrument-coverage` and build-std + - Works with `-Zno-profiler-runtime` + - Presumably profiler runtime is being loaded from the sysroot and that is loading other + sysroot crates and conflicting with the locally built crates +- **[wg-cargo-std-aware#64]: -Z build-std with unified workspace**, [Ericson2314], Jan 2021 + - In the current build-std implementation, the standard library is resolved + separately then combined with the user's crate graph + - It is argued that this is undesirable as it makes the standard library special + - Better to keep them separate as the standard library wants to have fixed dependency + versions matching the distributed version +- **[wg-cargo-std-aware#66]: Cross-compilation (of libc) on MacOS fails**, [raphaelcohn], Feb 2021 + - Unclear exactly what the root cause of this issue is +- **[wg-cargo-std-aware#67]: Update README.md**, [ghost], Mar 2021 + - Merged into [wg-cargo-std-aware] +- **[wg-cargo-std-aware#69]: "use of unstable library feature 'restricted_std'" can't be + fixed for deps**, [Manishearth], Jun 2021 + - User wants to use crates which use the standard library but where `restricted_std` applies + and that can't be fixed for the dependencies other than by patching +- **[wg-cargo-std-aware#70]: error: could not find native static library `c`, perhaps a `-L` + flag is missing?**, [mkb2091], Jun 2021 + - Duplicate of [wg-cargo-std-aware#66] +- **[wg-cargo-std-aware#72]: Figure out how to deal with `cargo test` with a + `no-std` target**, [phip1611], Jul 2021 + - `cargo test` doesn't work with `no_std` targets as `restricted_std` triggers + on `libtest` + - There were no comments on this issue +- **[cargo#10129]: Add support for `-Zbuild-std` to `cargo fetch`**, [jyn514], Nov 2021 + - Enables `cargo fetch -Zbuild-std` to fetch standard library crates +- **[wg-cargo-std-aware#76]: Unable to build executable for musl target**, [HenryJk], Nov 2021 + - It is unclear what fixed this issue, potentially a libc version bump + or linking `self-contained` +- **[cargo#10308]: Move build-std to Cargo.toml**, [fee1-dead], Jan 2022 + - Attempts to fix issues with build-std and per-package-target ([cargo#9451]) + - build-std's user interface is a large and open question that this patch + didn't have all the answers for so this was later closed + ([wg-cargo-std-aware#43]) +- **[cargo#10330]: Support per pkg target for -Zbuild-std**, [fee1-dead], Jan 2022 + - Another attempt to fix build-std and per-package-target ([cargo#9451]) + - Attempted to remove `--target` restriction but was told that this wasn't possible + - It probably was possible, thanks to various refactorings to Cargo between + 2019 and 2022, as [cargo#14317] faced no difficulties in removing the + restriction +- **[wg-cargo-std-aware#81]: -lunwind despite build-std=\["panic_abort", "std"\] on + powerpc-unknown-linux-musl**, [george-hopkins], Oct 2022 + - It is unclear what this issue is, there was very little detail and nobody commented +- **[rust#108924]: panic_immediate_abort requires abort as a panic strategy**, [tmiasko], Mar 2023 + - Adds a compile error when the `panic_immediate_abort` feature isn't used with `-Cpanic=abort` + - This could be triggered by build-std, as per [rust#107016] +- **[cargo#12088]: hack around `libsysroot` instead of `libtest`**, [weihanglo], May 2023 + - Cargo previously resolved features from the `test` crate, now it does so from + the `sysroot` crate, which is the canonical "head" of the standard library + - This approach to resolving features of standard library crates is still + considered a hack +- **[wg-cargo-std-aware#87]: The restricted_std error message is confusing**, [ehuss], May 2023 + - If you build a `no_std` target and forget to include `#![no_std]` then the standard library + is loaded and there's an "unstable library feature" error, this is confusing + - Improved error added in [rust#123360] and checking if a target supports the standard library + in [cargo#14183] +- **[cargo#13065]: fix: reorder `--remap-path-prefix` flags for `-Zbuild-std`**, [weihanglo], Nov 2023 + - Changing the order these flags are passed improves the source path in + diagnostics +- **[rust#120232]: Add support for JSON targets when using build-std**, [c272], Jan 2024 + - Updates the `restricted_std` filtering in `std`'s + [`build.rs`][std-build.rs] to check the target os rather than the target + triple (which is just set to the filename for JSON targets). + - Custom targets that "look similar" to builtin targets do not need to use + `restricted_std` ([wg-cargo-std-aware#90]) +- **[cargo#13404]: Verify build-std crate graph against library lock file**, [c272], Feb 2024 + - Added a new Cargo test, as an alternative to doing a forced lock + ([wg-cargo-std-aware#38]), to ensure that the resolved standard library unit + graph is a subset of the distributed `Cargo.lock` + - Closed in preference of a check at runtime +- **[rust#123360]: Document restricted_std**, [adamgemmell], Apr 2024 + - Improves the error message encountered when attempting to use `std` on a + target where `restricted_std` is set + - Proposed closing issues around `restricted_std` but a more comprehensive + solution was desired +- **[cargo#13916]: Verify build-std resolve against original lockfile**, [adamgemmell], May 2024 + - Same as [cargo#13404] but during Cargo execution + - Superseded by changes from [rust#128534] +- **[cargo#14183]: Check build target supports std when building with -Zbuild-std=std**, [harmou01], Jul 2024 + - Disallows building `std` when `metadata.std` field in the unstable + `target-spec-json` is `false` + - Aims to improve user experience compared to the `restricted_std` error + - `target-spec-json`'s `metadata.std` was added to support generation of the + compiler documentation, rather than as a source-of-truth for this + information +- **[cargo#14317]: Remove requirement for --target when invoking Cargo with -Zbuild-std**, [harmou01], Jul 2024 + - Cargo now defaults to "cross-compile" mode and unifies units when in + "host-only" mode, so host dependencies do not use the build-std standard + library and this restriction can be removed +- **[rust#128534]: Move the standard library to a separate workspace**, [bjorn3], Aug 2024 + - `rust-src` now has its own lockfile, enabling simplifications in build-std + implementation +- **[cargo#14358]: Remove hack on creating virtual std workspace**, [weihanglo], Aug 2024 + - Following [rust#128534], Cargo does not need to construct a synthetic + workspace and can load the workspace from disk + - Also enables `build-std` to use the configuration present in the workspace + manifest +- **[cargo#14370]: fix: std Cargo.lock moved to `library` dir**, [weihanglo], Aug 2024 + - Fix for [cargo#14358] which use the new `library/Cargo.lock` +- **[wg-cargo-std-aware#91]: rust-lld: undefined symbol: memchr when compiling + with nightly-aarch64-unknown-linux-musl**, [yogh333], Aug 2024 + - Undefined `memchr` symbol on `aarch64-unknown-linux-musl` when using `compiler-builtins-mem` + feature + - Suggested that the issue is a missing aarch64 musl libc +- **[cargo#14589]: Implement `--locked` for build-std**, [adamgemmell], Sep 2024 + - Alternative to [cargo#13916] + - Reuses Cargo's `--locked` machinery now that the standard library has its + own workspace and lockfile + - Concerns raised about resolving with optional dependencies and breaking the + future ability to patch the standard library workspace + - Closed pending a more comprehensive plan from the build-std project goal +- **[cargo#14850]: always link to std when testing proc-macros**, [weihanglo], Nov 2024 + - A small fix for testing proc-macros with build-std when `libstd.so` stopped + being shipped +- **[cargo#14899]: determine root crates by target spec `std:bool`**, [weihanglo], Dec 2024 + - This removes the hard error from [cargo#14183] and instead uses `std` as the + default crate for build-std if `metadata.std` is true, and + `core`/`compiler_builtins` otherwise + - `std` can be built on some targets even if they don't officially support + std, and rustdoc was relying on this behaviour +- **[cargo#14938]: make Resolve align to what to build**, [weihanglo], Dec 2024 + - Reverted part of [cargo#14899] which meant that `panic_unwind` would not + build if the `panic-unwind` feature was not present +- **[cargo#14951]: Do not hash absolute sysroot path into stdlib crates metadata**, [Dirbaio], Dec 2024 + - Improves reproducibility of `build-std` builds by only hashing paths of + standard library sources relative to the sysroot +- **[cargo#15065]: parse as comma-separated list**, [weihanglo], Jan 2025 + - Fixes a minor regression when providing multiple crates via + `CARGO_UNSTABLE_BUILD_STD` +- **[rust#135395]: Enforce the compiler-builtins partitioning scheme**, [saethlin], Jan 2025 (closed) + - Removes the profile override for `compiler_builtins`' codegen-units and + implements it in the compiler instead + - One of the use cases is build-std, which does not use the profile override + - Closed due to build issues with Rust for Linux unrelated to build-std +- **[wg-cargo-std-aware#93]: Stack trace for duplicate lang item?**, [illuzen], Feb 2025 + - Missing `panic_abort` and so loading it from the sysroot and hitting a duplicate language + item error + - Downstream of [wg-cargo-std-aware#31] +- **[wg-cargo-std-aware#94]: `panic_immediate_abort` and `no_std`**, [nazar-pc], Mar 2025 + - Suggests that a panic handler crate shouldn't be necessary when + `panic_immediate_abort` is enabled + +### Bugs in the compiler or standard library +[bugs-in-the-compiler-or-standard-library]: #bugs-in-the-compiler-or-standard-library + +These issues were bug reports for build-std that ultimately ended up being +issues resolved in the standard library or compiler: + +- **[wg-cargo-std-aware#32]: Figure out why profile override causes linker + errors**, [ehuss], Sep 2019 + - Ended up being a bug in symbol mangling ([rust#64319]) +- **[wg-cargo-std-aware#52]: cannot produce proc-macro on musl host toolchain**, + [12101111], Nov 2019 + - Issue was entirely unrelated to build-std +- **[wg-cargo-std-aware#56]: duplicate item in crate `core`**, [chaozju], Jun + 2020 + - User's dependency was using `std` (forgot to disable `std` feature) +- **[wg-cargo-std-aware#58]: It is not possible to use `-Zbuild-std` with a + Development-Channel Rust**, [cr1901], Aug 2020 + - User's toolchain version did not match local checkout of [rust-lang/rust] +- **[wg-cargo-std-aware#59]: Can't build executables for musl**, [vi], Sep 2020 + - `libunwind`'s source was missing in `rust-src` for targets that need it + - Fixed in [rust#77086] +- **[wg-cargo-std-aware#60]: Can't build std if I specify target json file: std + does not see networking**, [vi], Sep 2020 + - The standard library's `build.rs` was matching on entire target names rather + than just components like `target_os` + - Fixed in [rust#120232] +- **[wg-cargo-std-aware#71]: "duplicate lang item in crate `core`" when + building**, [TheBlueMatt], Jul 2021 + - Duplicate of [wg-cargo-std-aware#56] +- **[wg-cargo-std-aware#73]: Build on Windows fails to select a version of + `libc` for package `test`**, [MauriceKayser], Oct 2021 + - Duplicate of [cargo#9976], ultimately unrelated to build-std +- **[wg-cargo-std-aware#74]: undefined reference errors on aarch64**, + [SparrowLii], Nov 2021 + - `core`'s implementation briefly depended on libc after [rust#83655] + - `compiler_builtins` had no implementation of the symbols that the + `outline-atomics` feature was using from `libc` + - `compiler_builtins` gained implementation in [compiler-builtins#532] +- **[wg-cargo-std-aware#75]: Code won't compile with panic="abort" option**, + [HenryJk], Nov 2021 + - User was missing `panic_abort` crate in `-Zbuild-std=` +- **[wg-cargo-std-aware#78]: Rust compiler workspace patches are being ignored + when compiling with `-Zbuild-std`**, [raoulstrackx], Nov 2021 + - Adding a `[patch]` for the standard library to the workspace in the + [rust-lang/rust] did not work + - Fixed when the standard library gained its own workspace ([rust#128534]) +- **[wg-cargo-std-aware#79]: Building std with support for certain lang items**, + [AZMCode], Jan 2022 + - User wanted to define their own language item for `Error` in a `no_std` + project + - Ultimately `Error` was moved to `core` +- **[wg-cargo-std-aware#80]: duplicate lang item if `#![feature(test)]` is + enabled**, [skyzh], Mar 2022 + - `std` wasn't in the list of crates to `-Zbuild-std` and was being pulled from sysroot, + so `core` was being loaded twice +- **[wg-cargo-std-aware#82]: Hidden symbol isn't defined**, [wcampbell0x2a], Jan + 2023 + - Duplicate of [rust#107016], fixed in [rust#108924] + +### Cargo feature requests narrowly applied to build-std +[cargo-feature-requests-narrowly-applied-to-build-std]: #cargo-feature-requests-narrowly-applied-to-build-std + +These issues were feature requests for build-std that could have been a more +general feature for Cargo that could then apply to build-std too: + +- **[wg-cargo-std-aware#84]: Cache libstd artifacts between projects**, + [jyn514], May 2023 + - Cargo rebuilds the standard library for each project used with `-Zbuild-std` + (in the `target` directory) but it could be cached globally + - It was the opinion of team members that this was hard to implement + - It also could apply to any dependency of specific version and configuration + and so this could be resolved by proposing the addition of a global caching + mechanism for dependencies +- **[wg-cargo-std-aware#89]: Allow scoping of unstable features to specific + targets**, [ketsuban], Oct 2023 + - User wants unstable `build-std` to only be enabled for one target and + nightly not be required when building for other targets + - This is a consequence of how Cargo's unstable features work, and would be + fixed by a change to that mechanism, rather than anything specific to + build-std + +[history]: ./2-history.md + +[JOSH]: https://josh-project.github.io/josh/intro.html +[cargo-xbuild]: https://github.com/rust-osdev/cargo-xbuild +[embedded-wg]: https://github.com/rust-embedded/wg +[portability-wg]: https://github.com/rust-lang-nursery/portability-wg +[rust-lang/cargo]: https://github.com/rust-lang/cargo +[rust-lang/rust]: https://github.com/rust-lang/rust +[wg-cargo-std-aware]: https://github.com/rust-lang/wg-cargo-std-aware +[xargo]: https://github.com/japaric/xargo + +[A vision for portability in Rust]: http://aturon.github.io/tech/2018/02/06/portability-vision/ + +[cargo#10129]: https://github.com/rust-lang/cargo/pull/10129 +[cargo#10308]: https://github.com/rust-lang/cargo/pull/10308 +[cargo#10330]: https://github.com/rust-lang/cargo/pull/10330 +[cargo#10881]: https://github.com/rust-lang/cargo/issues/10881 +[cargo#12088]: https://github.com/rust-lang/cargo/pull/12088 +[cargo#12375]: https://github.com/rust-lang/cargo/pull/12375 +[cargo#13065]: https://github.com/rust-lang/cargo/pull/13065 +[cargo#13404]: https://github.com/rust-lang/cargo/pull/13404 +[cargo#13916]: https://github.com/rust-lang/cargo/pull/13916 +[cargo#14183]: https://github.com/rust-lang/cargo/pull/14183 +[cargo#14317]: https://github.com/rust-lang/cargo/pull/14317 +[cargo#14358]: https://github.com/rust-lang/cargo/pull/14358 +[cargo#14370]: https://github.com/rust-lang/cargo/pull/14370 +[cargo#14589]: https://github.com/rust-lang/cargo/pull/14589 +[cargo#14850]: https://github.com/rust-lang/cargo/pull/14850 +[cargo#14899]: https://github.com/rust-lang/cargo/pull/14899 +[cargo#14938]: https://github.com/rust-lang/cargo/pull/14938 +[cargo#14951]: https://github.com/rust-lang/cargo/pull/14951 +[cargo#15065]: https://github.com/rust-lang/cargo/pull/15065 +[cargo#2768]: https://github.com/rust-lang/cargo/pull/2768 +[cargo#4959]: https://github.com/rust-lang/cargo/issues/4959 +[cargo#5002]: https://github.com/rust-lang/cargo/issues/5002 +[cargo#5003]: https://github.com/rust-lang/cargo/issues/5003 +[cargo#7216]: https://github.com/rust-lang/cargo/pull/7216 +[cargo#7336]: https://github.com/rust-lang/cargo/pull/7336 +[cargo#7337]: https://github.com/rust-lang/cargo/pull/7337 +[cargo#7350]: https://github.com/rust-lang/cargo/pull/7350 +[cargo#7353]: https://github.com/rust-lang/cargo/pull/7353 +[cargo#7421]: https://github.com/rust-lang/cargo/pull/7421 +[cargo#7614]: https://github.com/rust-lang/cargo/issues/7614 +[cargo#7699]: https://github.com/rust-lang/cargo/pull/7699 +[cargo#7931]: https://github.com/rust-lang/cargo/pull/7931 +[cargo#8177]: https://github.com/rust-lang/cargo/pull/8177 +[cargo#8490]: https://github.com/rust-lang/cargo/pull/8490 +[cargo#8733]: https://github.com/rust-lang/cargo/issues/8733 +[cargo#8834]: https://github.com/rust-lang/cargo/pull/8834 +[cargo#8945]: https://github.com/rust-lang/cargo/issues/8945 +[cargo#8962]: https://github.com/rust-lang/cargo/issues/8962 +[cargo#8963]: https://github.com/rust-lang/cargo/issues/8963 +[cargo#8968]: https://github.com/rust-lang/cargo/pull/8968 +[cargo#9451]: https://github.com/rust-lang/cargo/issues/9451 +[cargo#9976]: https://github.com/rust-lang/cargo/issues/9976 +[compiler-builtins#411]: https://github.com/rust-lang/compiler-builtins/pull/411 +[compiler-builtins#532]: https://github.com/rust-lang/compiler-builtins/pull/532 +[internals.r-l.o: Fleshing out libstd scenarios]: https://internals.rust-lang.org/t/fleshing-out-libstd-scenarios/4206 +[internals.r-l.o: Refactoring libstd for ultimate portability]: https://internals.rust-lang.org/t/refactoring-std-for-ultimate-portability/4301 +[jamesmunns/rfcs#1]: https://github.com/jamesmunns/rfcs/pull/1 +[rfcs#1133]: https://github.com/rust-lang/rfcs/pull/1133 +[rfcs#1502]: https://github.com/rust-lang/rfcs/pull/1502 +[rfcs#1868]: https://github.com/rust-lang/rfcs/pull/1868 +[rfcs#2663-t-lang]: https://github.com/rust-lang/lang-team/blob/master/minutes/2019-06-06.md?rgh-link-date=2019-06-06T23%3A20%3A17Z- +[rfcs#2663]: https://github.com/rust-lang/rfcs/pull/2663 +[rust#107016]: https://github.com/rust-lang/rust/issues/107016 +[rust#108924]: https://github.com/rust-lang/rust/pull/108924 +[rust#119899]: https://github.com/rust-lang/rust/pull/119899 +[rust#120232]: https://github.com/rust-lang/rust/pull/120232 +[rust#123360]: https://github.com/rust-lang/rust/pull/123360 +[rust#128534]: https://github.com/rust-lang/rust/pull/128534 +[rust#135395]: https://github.com/rust-lang/rust/pull/135395 +[rust#31605]: https://github.com/rust-lang/rust/pull/31605 +[rust#46439]: https://github.com/rust-lang/rust/pull/46439 +[rust#57288]: https://github.com/rust-lang/rust/issues/57288 +[rust#64158]: https://github.com/rust-lang/rust/pull/64158 +[rust#64316]: https://github.com/rust-lang/rust/pull/64316 +[rust#64319]: https://github.com/rust-lang/rust/issues/64319 +[rust#67074]: https://github.com/rust-lang/rust/issues/67074 +[rust#67650]: https://github.com/rust-lang/rust/issues/67650 +[rust#68887]: https://github.com/rust-lang/rust/issues/68887 +[rust#69608]: https://github.com/rust-lang/rust/pull/69608 +[rust#71009]: https://github.com/rust-lang/rust/pull/71009 +[rust#77086]: https://github.com/rust-lang/rust/pull/77086 +[rust#78790]: https://github.com/rust-lang/rust/pull/78790 +[rust#79218]: https://github.com/rust-lang/rust/pull/79218 +[rust#79838]: https://github.com/rust-lang/rust/pull/79838 +[rust#79958]: https://github.com/rust-lang/rust/pull/79958 +[rust#80082]: https://github.com/rust-lang/rust/pull/83655 +[rust#83655]: https://github.com/rust-lang/rust/pull/83655 +[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#18]: https://github.com/rust-lang/wg-cargo-std-aware/issues/18 +[wg-cargo-std-aware#19-internals]: https://internals.rust-lang.org/t/dogfooding-z-build-std-in-rustbuild/13775/22 +[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#27]: https://github.com/rust-lang/wg-cargo-std-aware/issues/27 +[wg-cargo-std-aware#28]: https://github.com/rust-lang/wg-cargo-std-aware/issues/28 +[wg-cargo-std-aware#29]: https://github.com/rust-lang/wg-cargo-std-aware/issues/29 +[wg-cargo-std-aware#2]: https://github.com/rust-lang/wg-cargo-std-aware/issues/2 +[wg-cargo-std-aware#30]: https://github.com/rust-lang/wg-cargo-std-aware/issues/30 +[wg-cargo-std-aware#31]: https://github.com/rust-lang/wg-cargo-std-aware/issues/31 +[wg-cargo-std-aware#32]: https://github.com/rust-lang/wg-cargo-std-aware/issues/32 +[wg-cargo-std-aware#33]: https://github.com/rust-lang/wg-cargo-std-aware/issues/33 +[wg-cargo-std-aware#34]: https://github.com/rust-lang/wg-cargo-std-aware/issues/34 +[wg-cargo-std-aware#35]: https://github.com/rust-lang/wg-cargo-std-aware/issues/35 +[wg-cargo-std-aware#36]: https://github.com/rust-lang/wg-cargo-std-aware/issues/36 +[wg-cargo-std-aware#37]: https://github.com/rust-lang/wg-cargo-std-aware/issues/37 +[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#3]: https://github.com/rust-lang/wg-cargo-std-aware/issues/3 +[wg-cargo-std-aware#40]: https://github.com/rust-lang/wg-cargo-std-aware/issues/40 +[wg-cargo-std-aware#41]: https://github.com/rust-lang/wg-cargo-std-aware/issues/41 +[wg-cargo-std-aware#42]: https://github.com/rust-lang/wg-cargo-std-aware/issues/42 +[wg-cargo-std-aware#43-internals]: https://internals.rust-lang.org/t/build-std-and-the-standard-library/11459 +[wg-cargo-std-aware#43]: https://github.com/rust-lang/wg-cargo-std-aware/issues/43 +[wg-cargo-std-aware#44]: https://github.com/rust-lang/wg-cargo-std-aware/issues/44 +[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#48]: https://github.com/rust-lang/wg-cargo-std-aware/issues/48 +[wg-cargo-std-aware#49]: https://github.com/rust-lang/wg-cargo-std-aware/issues/49 +[wg-cargo-std-aware#4]: https://github.com/rust-lang/wg-cargo-std-aware/issues/4 +[wg-cargo-std-aware#5-internals]: https://internals.rust-lang.org/t/pre-pre-rfc-making-std-dependent-cargo-features-a-first-class-concept/10828 +[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#52]: https://github.com/rust-lang/wg-cargo-std-aware/issues/52 +[wg-cargo-std-aware#53]: https://github.com/rust-lang/wg-cargo-std-aware/issues/53 +[wg-cargo-std-aware#54]: https://github.com/rust-lang/wg-cargo-std-aware/issues/54 +[wg-cargo-std-aware#55]: https://github.com/rust-lang/wg-cargo-std-aware/issues/55 +[wg-cargo-std-aware#56]: https://github.com/rust-lang/wg-cargo-std-aware/issues/56 +[wg-cargo-std-aware#57]: https://github.com/rust-lang/wg-cargo-std-aware/issues/57 +[wg-cargo-std-aware#58]: https://github.com/rust-lang/wg-cargo-std-aware/issues/58 +[wg-cargo-std-aware#59]: https://github.com/rust-lang/wg-cargo-std-aware/issues/59 +[wg-cargo-std-aware#5]: https://github.com/rust-lang/wg-cargo-std-aware/issues/5 +[wg-cargo-std-aware#60]: https://github.com/rust-lang/wg-cargo-std-aware/issues/60 +[wg-cargo-std-aware#61]: https://github.com/rust-lang/wg-cargo-std-aware/issues/61 +[wg-cargo-std-aware#62]: https://github.com/rust-lang/wg-cargo-std-aware/issues/62 +[wg-cargo-std-aware#63]: https://github.com/rust-lang/wg-cargo-std-aware/issues/63 +[wg-cargo-std-aware#64]: https://github.com/rust-lang/wg-cargo-std-aware/issues/64 +[wg-cargo-std-aware#65]: https://github.com/rust-lang/wg-cargo-std-aware/issues/65 +[wg-cargo-std-aware#66]: https://github.com/rust-lang/wg-cargo-std-aware/issues/66 +[wg-cargo-std-aware#67]: https://github.com/rust-lang/wg-cargo-std-aware/issues/67 +[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#6]: https://github.com/rust-lang/wg-cargo-std-aware/issues/6 +[wg-cargo-std-aware#70]: https://github.com/rust-lang/wg-cargo-std-aware/issues/70 +[wg-cargo-std-aware#71]: https://github.com/rust-lang/wg-cargo-std-aware/issues/71 +[wg-cargo-std-aware#72]: https://github.com/rust-lang/wg-cargo-std-aware/issues/72 +[wg-cargo-std-aware#73]: https://github.com/rust-lang/wg-cargo-std-aware/issues/73 +[wg-cargo-std-aware#74]: https://github.com/rust-lang/wg-cargo-std-aware/issues/74 +[wg-cargo-std-aware#75]: https://github.com/rust-lang/wg-cargo-std-aware/issues/75 +[wg-cargo-std-aware#76]: https://github.com/rust-lang/wg-cargo-std-aware/issues/76 +[wg-cargo-std-aware#77]: https://github.com/rust-lang/wg-cargo-std-aware/issues/77 +[wg-cargo-std-aware#78]: https://github.com/rust-lang/wg-cargo-std-aware/issues/78 +[wg-cargo-std-aware#79]: https://github.com/rust-lang/wg-cargo-std-aware/issues/79 +[wg-cargo-std-aware#7]: https://github.com/rust-lang/wg-cargo-std-aware/issues/7 +[wg-cargo-std-aware#80]: https://github.com/rust-lang/wg-cargo-std-aware/issues/80 +[wg-cargo-std-aware#81]: https://github.com/rust-lang/wg-cargo-std-aware/issues/81 +[wg-cargo-std-aware#82]: https://github.com/rust-lang/wg-cargo-std-aware/issues/82 +[wg-cargo-std-aware#83]: https://github.com/rust-lang/wg-cargo-std-aware/issues/83 +[wg-cargo-std-aware#84]: https://github.com/rust-lang/wg-cargo-std-aware/issues/84 +[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#89]: https://github.com/rust-lang/wg-cargo-std-aware/issues/89 +[wg-cargo-std-aware#8]: https://github.com/rust-lang/wg-cargo-std-aware/issues/8 +[wg-cargo-std-aware#90]: https://github.com/rust-lang/wg-cargo-std-aware/issues/90 +[wg-cargo-std-aware#91]: https://github.com/rust-lang/wg-cargo-std-aware/issues/91 +[wg-cargo-std-aware#92]: https://github.com/rust-lang/wg-cargo-std-aware/issues/92 +[wg-cargo-std-aware#93]: https://github.com/rust-lang/wg-cargo-std-aware/issues/93 +[wg-cargo-std-aware#94]: https://github.com/rust-lang/wg-cargo-std-aware/issues/94 +[wg-cargo-std-aware#95]: https://github.com/rust-lang/wg-cargo-std-aware/issues/95 + +[embed-rs-cargo-toml]: https://github.com/embed-rs/stm32f7-discovery/blob/e2bf713263791c028c2a897f2eb1830d7f09eceb/Cargo.toml#L21 +[embed-rs-source]: https://github.com/embed-rs/stm32f7-discovery/blob/e2bf713263791c028c2a897f2eb1830d7f09eceb/core/src/lib.rs#L7 +[std-build.rs]: https://github.com/rust-lang/rust/blob/f315e6145802e091ff9fceab6db627a4b4ec2b86/library/std/build.rs#L17 + +[12101111]: https://github.com/12101111 +[AZMCode]: https://github.com/AZMCode +[Dirbaio]: https://github.com/Dirbaio +[Ericson2314]: https://github.com/Ericson2314 +[Gankra]: https://github.com/Gankra +[HenryJk]: https://github.com/HenryJk +[Manishearth]: https://github.com/Manishearth +[Mark-Simulacrum]: https://github.com/Mark-Simulacrum +[MauriceKayser]: https://github.com/MauriceKayser +[SparrowLii]: https://github.com/SparrowLii +[TheBlueMatt]: https://github.com/TheBlueMatt +[adamgemmell]: https://github.com/adamgemmell +[alex]: https://github.com/alex +[alexcrichton]: https://github.com/alexcrichton +[bascule]: https://github.com/bascule +[bjorn3]: https://github.com/bjorn3 +[c272]: https://github.com/c272 +[catenacyber]: https://github.com/catenacyber +[chaozju]: https://github.com/chaozju +[cr1901]: https://github.com/cr1901 +[dullbananas]: https://github.com/dullbananas +[ehuss]: https://github.com/ehuss +[errantmind]: https://github.com/errantmind +[fee1-dead]: https://github.com/fee1-dead +[george-hopkins]: https://github.com/george-hopkins +[ghost]: https://github.com/ghost +[harmou01]: https://github.com/harmou01 +[hnj2]: https://github.com/hnj2 +[illuzen]: https://github.com/illuzen +[jamesmunns]: https://github.com/jamesmunns +[japaric]: https://github.com/japaric +[jdm]: https://github.com/jdm +[jschwe]: https://github.com/jschwe +[jyn514]: https://github.com/jyn514 +[ketsuban]: https://github.com/ketsuban +[madsmtm]: https://github.com/madsmtm +[mkb2091]: https://github.com/mkb2091 +[nagisa]: https://github.com/nagisa +[nazar-pc]: https://github.com/nazar-pc +[parraman]: https://github.com/parraman +[phip1611]: https://github.com/phip1611 +[raoulstrackx]: https://github.com/raoulstrackx +[raphaelcohn]: https://github.com/raphaelcohn +[rust-osdev]: https://github.com/rust-osdev +[saethlin]: https://github.com/saethlin +[skyzh]: https://github.com/skyzh +[tamird]: https://github.com/tamird +[tmiasko]: https://github.com/tmiasko +[tomaak]: https://github.com/tomaak +[vi]: https://github.com/vi +[wcampbell0x2a]: https://github.com/wcampbell0x2a +[weihanglo]: https://github.com/weihanglo +[yogh333]: https://github.com/yogh333 From a68f0856b1942725a66103cf1fcbca37cf969f19 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 22 Jul 2025 12:39:57 +0000 Subject: [PATCH 02/96] history: correct default crate built --- text/0000-build-std/2-history.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/text/0000-build-std/2-history.md b/text/0000-build-std/2-history.md index 834d97244d1..6027f53c747 100644 --- a/text/0000-build-std/2-history.md +++ b/text/0000-build-std/2-history.md @@ -342,11 +342,17 @@ since August 2019 ([wg-cargo-std-aware#10]/[cargo#7216]). re-builds the standard library crates which rustc then uses instead of the pre-built standard library from the sysroot. -`-Zbuild-std` builds `std` by default. `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. +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`, @@ -479,6 +485,7 @@ features that are related or would be beneficial for build-std: [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 +[rust#122305]: https://github.com/rust-lang/rust/pull/128534 [rust#128534]: https://github.com/rust-lang/rust/pull/128534 [rust#67074]: https://github.com/rust-lang/rust/issues/67074 [wg-cargo-std-aware#10]: https://github.com/rust-lang/wg-cargo-std-aware/issues/10 From 3d9b3992fde45f5f2b991e5e1ed85cb89e599190 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 23 Jul 2025 09:55:32 +0000 Subject: [PATCH 03/96] background: clarify stability of custom targets --- text/0000-build-std/1-background.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/text/0000-build-std/1-background.md b/text/0000-build-std/1-background.md index d669ab9ecb4..c50abb32606 100644 --- a/text/0000-build-std/1-background.md +++ b/text/0000-build-std/1-background.md @@ -146,10 +146,13 @@ or `core`, only `std`. 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` even -on stable toolchains, though the JSON format is unstable. Custom targets do not -have a pre-built standard library and so must use `-Zbuild-std`. Custom targets -may have `restricted_std` set depending on their `cfg` configuration options. +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 @@ -289,6 +292,7 @@ linked together with different values of the flag set. [rfcs#3716]: https://rust-lang.github.io/rfcs/3716-target-modifiers.html [rust#46439]: https://github.com/rust-lang/rust/pull/46439 [rust#44663]: https://github.com/rust-lang/rust/issues/44663 +[rust#71009]: https://github.com/rust-lang/rust/issues/71009 [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 From 0c97a214ef4e2200743889df940d1b664cc1729f Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 23 Jul 2025 09:57:52 +0000 Subject: [PATCH 04/96] background: mention `path`/`git` sources --- text/0000-build-std/1-background.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/text/0000-build-std/1-background.md b/text/0000-build-std/1-background.md index c50abb32606..c1408e8ed5d 100644 --- a/text/0000-build-std/1-background.md +++ b/text/0000-build-std/1-background.md @@ -231,7 +231,9 @@ in `core`. `std`'s feature also adds an immediate abort to its `panic!` macro. ## Cargo [background-cargo]: #cargo -Cargo's building of the dependency graph is driven by the registry index. +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 crates are available, what their dependencies @@ -242,11 +244,12 @@ 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. -Each crates in the registry has a JSON file, following +Each crate in the registry has a JSON file, following [a defined schema][cargo-json-schema]. Crates may refer to those in other -registries, but all crates in the dependency graph must exist in a registry. As -the registry index drives the building of Cargo's dependency graph, all crates -that end up in the dependency graph must be present a registry. +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 crates that end up in the dependency graph must be present a +registry. Registries can have different policies for what crates are accepted. For example, crates.io does not permit publishing packages named `std` or `core` but From 8765bc5861a8ba6ccb31601b625ba88fb4420125 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 23 Jul 2025 10:05:17 +0000 Subject: [PATCH 05/96] motivation: clarify these won't all be addressed --- text/0000-build-std/3-motivation.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/text/0000-build-std/3-motivation.md b/text/0000-build-std/3-motivation.md index 47609940bc3..2ed7550ae5b 100644 --- a/text/0000-build-std/3-motivation.md +++ b/text/0000-build-std/3-motivation.md @@ -3,7 +3,9 @@ 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 -re-build the standard library. +re-build the standard library. 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 proposal. 1. **Re-building the standard library with different codegen flags or profile** ([wg-cargo-std-aware#2]) From 64bd0abac737629c5563ae96a740795231f03b95 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 28 Jul 2025 04:34:36 +0000 Subject: [PATCH 06/96] history: clarify `libunwind` source --- text/0000-build-std/2-history.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/text/0000-build-std/2-history.md b/text/0000-build-std/2-history.md index 6027f53c747..287b43f38ad 100644 --- a/text/0000-build-std/2-history.md +++ b/text/0000-build-std/2-history.md @@ -174,6 +174,12 @@ categories: symbols provided by `libc`. compiler-builtins is also built with a large number of compilation units to force each function into a different unit. + ['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. From a3e92e640b2f2f05b5c849d363fac25416380c84 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 28 Jul 2025 21:46:56 +0000 Subject: [PATCH 07/96] background: clarify not all crates in registry --- text/0000-build-std/1-background.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-build-std/1-background.md b/text/0000-build-std/1-background.md index c1408e8ed5d..862fc814310 100644 --- a/text/0000-build-std/1-background.md +++ b/text/0000-build-std/1-background.md @@ -248,8 +248,8 @@ Each crate in the registry has a JSON file, following [a defined schema][cargo-json-schema]. 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 crates that end up in the dependency graph must be present a -registry. +graph, all non-`path`/`git` crates that end up in the dependency graph must be +present a registry. Registries can have different policies for what crates are accepted. For example, crates.io does not permit publishing packages named `std` or `core` but From a99cd20a75147d98d58efd8cb8f15b16481b9547 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 28 Jul 2025 21:47:15 +0000 Subject: [PATCH 08/96] history: s/virtual/in-memory --- text/0000-build-std/2-history.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-build-std/2-history.md b/text/0000-build-std/2-history.md index 287b43f38ad..d83f4f14ae8 100644 --- a/text/0000-build-std/2-history.md +++ b/text/0000-build-std/2-history.md @@ -386,8 +386,8 @@ 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 a virtual workspace, prior to the standard library having a -separate workspace from the compiler which could be used independently +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 From 786c925985fe409201bdd82c8195c16347c4eb88 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 28 Jul 2025 21:56:52 +0000 Subject: [PATCH 09/96] background: split into support/later/won't support --- text/0000-build-std/3-motivation.md | 59 +++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/text/0000-build-std/3-motivation.md b/text/0000-build-std/3-motivation.md index 2ed7550ae5b..e3a570adb55 100644 --- a/text/0000-build-std/3-motivation.md +++ b/text/0000-build-std/3-motivation.md @@ -1,11 +1,21 @@ # 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 proposal. +> +> 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 -re-build the standard library. 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 proposal. +re-build the standard library. + +This RFC aims to support the following use cases: 1. **Re-building the standard library with different codegen flags or profile** ([wg-cargo-std-aware#2]) @@ -14,10 +24,12 @@ these use cases will be addressed by this proposal. 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 @@ -27,12 +39,16 @@ these use cases will be addressed by this proposal. - 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 3. **Building the standard library on a stable toolchain without Cargo** @@ -40,6 +56,9 @@ these use cases will be addressed by this proposal. - While tangential to the core of build-std as a feature, projects like Rust for Linux want to be able to build an unmodified `core` from `rust-src` in the sysroot on a stable toolchain without Cargo + + - It is relatively straightforward to support this, hence its inclusion + - Cargo may also want a mechanism to build the standard library for build-std on a stable toolchain without relying on `RUSTC_BOOTSTRAP` @@ -53,40 +72,58 @@ these use cases will be addressed by this proposal. - 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]) -6. **Using miri on a stable toolchain** +The following use cases are not supported by this RFC, but could be supported +with follow-up RFCs (and this RFC will attempt to ensure they remain viable as +future possibilities): - - 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 - -7. **Using the standard library with custom targets** +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 -8. **Enabling Cargo features for the standard library** ([wg-cargo-std-aware#4]) +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 a feature like `optimize_for_size` or `panic_immediate_abort` to reduce binary size -9. **Modifying the source code of the standard library** ([wg-cargo-std-aware#7]) +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 RFC 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 +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 + [cargo-xbuild]: https://github.com/rust-osdev/cargo-xbuild [xargo]: https://github.com/japaric/xargo From c740a18218b187e5b85964aa86a0d991f2723bf5 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 31 Jul 2025 21:17:49 +0000 Subject: [PATCH 10/96] background: addl. cargo registry information --- text/0000-build-std/1-background.md | 45 ++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/text/0000-build-std/1-background.md b/text/0000-build-std/1-background.md index 862fc814310..c667b4d1c23 100644 --- a/text/0000-build-std/1-background.md +++ b/text/0000-build-std/1-background.md @@ -236,20 +236,37 @@ 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 crates are available, what their dependencies -are, etc. crates.io's registry index is a Git repository - -[rust-lang/crates.io-index] - which is updated automatically by crates.io when -crates are published, yanked, 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. - -Each crate in the registry has a JSON file, following -[a defined schema][cargo-json-schema]. 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. +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 From 71638104fb65c83e16365dd27fc7f61b42aed22f Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 31 Jul 2025 21:37:22 +0000 Subject: [PATCH 11/96] history: mention `no_std` usability issues --- text/0000-build-std/2-history.md | 14 +++++++++++++ .../4-appendix-literature-review.md | 21 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/text/0000-build-std/2-history.md b/text/0000-build-std/2-history.md index d83f4f14ae8..8cfca62d035 100644 --- a/text/0000-build-std/2-history.md +++ b/text/0000-build-std/2-history.md @@ -446,6 +446,18 @@ 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 @@ -488,6 +500,8 @@ features that are related or would be beneficial for build-std: [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 diff --git a/text/0000-build-std/4-appendix-literature-review.md b/text/0000-build-std/4-appendix-literature-review.md index 027947a792a..33215663228 100644 --- a/text/0000-build-std/4-appendix-literature-review.md +++ b/text/0000-build-std/4-appendix-literature-review.md @@ -1347,6 +1347,23 @@ general feature for Cargo that could then apply to build-std too: fixed by a change to that mechanism, rather than anything specific to build-std +## Other issues +[a1-other-issues]: #other-issues + +There are a handful of other issues that are not directly referencing build-std, +but which affect related features in the toolchain, such as `no_std` crates: + +- **[keyword nostd vs no_std vs category no-std][crates.io#7306]**, [gnzlbg], Feb 2018 + - There is `no-std` category as well as a `nostd` and `no_std` keywords used + by crates. Not every crate which uses the `nostd`/`no_std` keywords also + uses the `no-std` category, and vice versa, making it harder to list all + `no_std`-supporting crates with a single search. +- **[no_std crates should not permit non-no_std dependencies][cargo#8798]**, [zesterer], Oct 2020 + - Cargo permits `no_std` crates to depend on crates that use the standard + library. When working with a target that does not ship the `std` crate, the + presence of these crates in the dependency graph can result in unexpected + build failures. + [history]: ./2-history.md [JOSH]: https://josh-project.github.io/josh/intro.html @@ -1395,6 +1412,7 @@ general feature for Cargo that could then apply to build-std too: [cargo#8177]: https://github.com/rust-lang/cargo/pull/8177 [cargo#8490]: https://github.com/rust-lang/cargo/pull/8490 [cargo#8733]: https://github.com/rust-lang/cargo/issues/8733 +[cargo#8798]: https://github.com/rust-lang/cargo/issues/8798 [cargo#8834]: https://github.com/rust-lang/cargo/pull/8834 [cargo#8945]: https://github.com/rust-lang/cargo/issues/8945 [cargo#8962]: https://github.com/rust-lang/cargo/issues/8962 @@ -1404,6 +1422,7 @@ general feature for Cargo that could then apply to build-std too: [cargo#9976]: https://github.com/rust-lang/cargo/issues/9976 [compiler-builtins#411]: https://github.com/rust-lang/compiler-builtins/pull/411 [compiler-builtins#532]: https://github.com/rust-lang/compiler-builtins/pull/532 +[crates.io#7306]: https://github.com/rust-lang/crates.io/pull/7306 [internals.r-l.o: Fleshing out libstd scenarios]: https://internals.rust-lang.org/t/fleshing-out-libstd-scenarios/4206 [internals.r-l.o: Refactoring libstd for ultimate portability]: https://internals.rust-lang.org/t/refactoring-std-for-ultimate-portability/4301 [jamesmunns/rfcs#1]: https://github.com/jamesmunns/rfcs/pull/1 @@ -1564,6 +1583,7 @@ general feature for Cargo that could then apply to build-std too: [fee1-dead]: https://github.com/fee1-dead [george-hopkins]: https://github.com/george-hopkins [ghost]: https://github.com/ghost +[gnzlbg]: https://github.com/gnzlbg [harmou01]: https://github.com/harmou01 [hnj2]: https://github.com/hnj2 [illuzen]: https://github.com/illuzen @@ -1591,3 +1611,4 @@ general feature for Cargo that could then apply to build-std too: [wcampbell0x2a]: https://github.com/wcampbell0x2a [weihanglo]: https://github.com/weihanglo [yogh333]: https://github.com/yogh333 +[zesterer]: https://github.com/zesterer \ No newline at end of file From 396138bdc25b0d30894950e6d13a306d3d500346 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 31 Jul 2025 21:39:32 +0000 Subject: [PATCH 12/96] background: user crates use features for std --- text/0000-build-std/1-background.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/text/0000-build-std/1-background.md b/text/0000-build-std/1-background.md index c667b4d1c23..7e497ba4100 100644 --- a/text/0000-build-std/1-background.md +++ b/text/0000-build-std/1-background.md @@ -125,6 +125,10 @@ enable or disable these features. The default set of features is determined by 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 From 3939ba0fe37ff6d49f436aaf1bab167da9171701 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 22 Jul 2025 12:02:28 +0000 Subject: [PATCH 13/96] build-std Co-authored-by: Adam Gemmell --- text/0000-build-std/0-introduction.md | 256 ++++- text/0000-build-std/2-history.md | 8 +- text/0000-build-std/4-stage-1a.md | 953 +++++++++++++++++ text/0000-build-std/5-stage-1b.md | 979 ++++++++++++++++++ text/0000-build-std/6-stage-2.md | 157 +++ text/0000-build-std/7-stage-3.md | 187 ++++ .../8-appendix-summary-of-changes.md | 83 ++ ...iew.md => 9-appendix-literature-review.md} | 0 8 files changed, 2616 insertions(+), 7 deletions(-) create mode 100644 text/0000-build-std/4-stage-1a.md create mode 100644 text/0000-build-std/5-stage-1b.md create mode 100644 text/0000-build-std/6-stage-2.md create mode 100644 text/0000-build-std/7-stage-3.md create mode 100644 text/0000-build-std/8-appendix-summary-of-changes.md rename text/0000-build-std/{4-appendix-literature-review.md => 9-appendix-literature-review.md} (100%) diff --git a/text/0000-build-std/0-introduction.md b/text/0000-build-std/0-introduction.md index c7826feba4e..5119329b3db 100644 --- a/text/0000-build-std/0-introduction.md +++ b/text/0000-build-std/0-introduction.md @@ -3,6 +3,85 @@ - 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 @@ -14,6 +93,14 @@ supported: 2. Rebuilding the standard library with ABI-modifying flags 3. Building the standard library for tier three targets +This RFC proposes a handful of changes to Cargo, the compiler and standard +library with the goal of defining a minimal build-std that has the potential of +being stabilised: + +- Explicitly declaring support for the standard library in target specs +- Explicit and implicit dependencies on the standard library in `Cargo.toml` +- Re-building the standard library when the profile or target modifiers change + 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 @@ -38,6 +125,20 @@ As a general rule, this RFC tries to answer the question "what crates of the standard library get built and when do they get built" and considers anything else as likely out-of-scope. +### 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]. + +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 and to +[Ed Page][epage] for writing about opaque dependencies. + +Thanks to [Jacob Bramley][jacobbramley] for their feedback on early drafts. + ### Terminology [terminology]: #terminology @@ -48,15 +149,47 @@ The following terminology is used throughout the RFC: - "std" is used to refer only to the `std` crate, not the entirety of the standard library +Throughout the RFC's "Proposal" sections, parentheses with "?" links 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. + # Contents [contents]: #contents -This RFC has the following contents: +This RFC has been split into multiple stages. Each stage is a +self-contained proposal building on the previous, which could be accepted, +implemented and stabilised on its own. + +As build-std is a complex feature with many interdependent design decisions, it +is challenging to draft a proposal that is small enough to have an achievable +scope in the short-to-medium term while making a convincing argument that it is +forward-compatible with any desired future extensions. A staged proposal enables +this - each stage can have a small and achievable scope, while still allowing a +reviewer to skip ahead and get a sense of what is planned and how that builds on +what came before. + +Later stages are less detailed and complete than the previous stages, intended +to indicate the intended direction that the RFC will take and help provide +context for the proposals of earlier stages. 1. [Summary][summary] (you are here) - Introduction to the proposal, its scope, terminology/conventions used and the structure of the RFC + + - [Proposal-wide rationale and alternatives][rationale-and-alternatives] 2. [Background](./1-background.md) @@ -74,7 +207,75 @@ This RFC has the following contents: - Descriptions of the varied problems that build-std has been proposed as a solution to -5. [Appendix II: Exhaustive literature review](./4-appendix-literature-review.md) +5. [Stage 1a: build-std=always](./4-stage-1a.md) + + - Proposes adding a `build-std = "always|off"` option to the Cargo + configuration which will unconditionally re-build the standard library + crates listed in the `build-std-crates` option + + - [Proposal](./4-stage-1a.md#proposal) + + - [Rationale and alternatives](./4-stage-1a.md#rationale-and-alternatives) + + - [Unresolved questions](./4-stage-1a.md#unresolved-questions) + + - [Future possibilities](./4-stage-1a.md#future-possibilities) + +6. [Stage 1b: Explicit dependencies](./5-stage-1b.md) + + - Proposes supporting explicit dependencies on the standard library crates in + `Cargo.toml` + + - Enables Cargo to determine which standard library crates are required by + the crate graph without `build-std-crates` being set + + - Necessary for future extensions which support public/private standard + library dependencies or enabling features of the standard library + + - [Proposal](./5-stage-1b.md#proposal) + + - [Rationale and alternatives](./5-stage-1b.md#rationale-and-alternatives) + + - [Unresolved questions](./5-stage-1b.md#unresolved-questions) + + - [Future possibilities](./5-stage-1b.md#future-possibilities) + +7. [Stage 2: build-std=compatible](./6-stage-2.md) + + - Proposes extending the `build-std` option with a new `compatible` value + which will become the default and automatically rebuilds the standard + library when it is necessary to maintain compatibility with the compiler + flags used by the rest of the crate graph. + + - [Proposal](./6-stage-2.md#proposal) + + - [Rationale and alternatives](./6-stage-2.md#rationale-and-alternatives) + + - [Unresolved questions](./6-stage-2.md#unresolved-questions) + + - [Future possibilities](./6-stage-2.md#future-possibilities) + +8. [Stage 3: build-std=match-profile](./7-stage-3.md) + + - Proposes extending the `build-std` option with new values which + automatically rebuild the standard library to match the user's current + profile. + + - [Proposal](./7-stage-3.md#proposal) + + - [Rationale and alternatives](./7-stage-3.md#rationale-and-alternatives) + + - [Unresolved questions](./7-stage-3.md#unresolved-questions) + + - [Future possibilities](./7-stage-3.md#future-possibilities) + +9. [Appendix I: Summary of changes](./8-appendix-summary-of-changes.md) + + - Summary of each of the changes from each stage which would need implemented + in the Rust toolchain, grouped by the project team whose purview the change + would fall under + +10. [Appendix II: Exhaustive literature review](./9-appendix-literature-review.md) - More detailed summaries of the relevant issues, discussions, pull requests and proposals that comprise the history of the build-std feature since @@ -83,5 +284,54 @@ This RFC has the following contents: - [*History*](./2-history.md) aims to summarise this content further and cover everything that should be necessary to understand the proposal +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +These rationales and alternatives apply to the proposal as-a-whole, rather than +any specific stage: + +## 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 lots of existing machinery +to create and maintain sysroots. rustup knows how to download `rust-src`, it +knows how to create a new toolchain from an existing sysroot (as in +`rustup toolchain link`), it would only need to learn how to invoke Cargo on the +`rust-src` sources. 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 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. + [davidtwco]: https://github.com/davidtwco -[adamgemmell]: https://github.com/adamgemmell \ No newline at end of file +[adamgemmell]: https://github.com/adamgemmell +[ehuss]: https://github.com/ehuss +[epage]: https://github.com/epage +[fee1-dead]: https://github.com/fee1-dead +[jacobbramley]: https://github.com/jacobbramley +[joshtriplett]: https://github.com/joshtriplett +[mati865]: https://github.com/mati865 +[petrochenkov]: https://github.com/petrochenkov +[tomassedovic]: https://github.com/tomassedovic +[wesleywiser]: https://github.com/wesleywiser + +[why-not-rustup]: https://hackmd.io/@davidtwco/rkYRlKv_1x diff --git a/text/0000-build-std/2-history.md b/text/0000-build-std/2-history.md index 8cfca62d035..20c56aae3d9 100644 --- a/text/0000-build-std/2-history.md +++ b/text/0000-build-std/2-history.md @@ -480,10 +480,10 @@ features that are related or would be beneficial for build-std: are unlikely to be needed during debugging [motivation]: ./3-motivation.md -[appendix-ii]: ./4-appendix-literature-review.md -[appendix-ii-impl]: ./4-appendix-literature-review.md#implementation -[appendix-ii-bugs]: ./4-appendix-literature-review.md#bugs-in-the-compiler-or-standard-library -[appendix-ii-cargo-feats]: ./4-appendix-literature-review.md#cargo-feature-requests-narrowly-applied-to-build-std +[appendix-ii]: ./9-appendix-literature-review.md +[appendix-ii-impl]: ./9-appendix-literature-review.md#implementation +[appendix-ii-bugs]: ./9-appendix-literature-review.md#bugs-in-the-compiler-or-standard-library +[appendix-ii-cargo-feats]: ./9-appendix-literature-review.md#cargo-feature-requests-narrowly-applied-to-build-std [JOSH]: https://josh-project.github.io/josh/intro.html [rust-lang/cargo]: https://github.com/rust-lang/cargo diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md new file mode 100644 index 00000000000..207f3c50137 --- /dev/null +++ b/text/0000-build-std/4-stage-1a.md @@ -0,0 +1,953 @@ +# Proposal +[proposal]: #proposal + +Cargo configuration will contain a new key `build-std` under the `[build]` +section ([?][rationale-build-std-in-config]), permitting one of two values - +"off" ([?][rationale-build-std-off]) or "always", defaulting to "off": + +```toml +[build] +build-std = "always" # or `off` +``` + +`build-std` can also be specified in the `[target.]` and +`[target.]` sections ([?][rationale-build-std-target-section]): + +```toml +[target.aarch64-unknown-illumos] +build-std = "always" # or `off` +``` + +The `build-std` configuration locations have the following precedence +([?][rationale-build-std-precedence]): + +1. `[target.]` +2. `[target.]` +3. `[build]` + +As the Cargo configuration is local to the current installation of Cargo +(typically in `~/.config/cargo`), the value of `build-std` is not influenced by +the dependencies of the current crate. + +When `build-std` is set to "always", then the standard library will be +unconditionally recompiled ([?][rationale-unconditional]) in its release profile +as part of every clean build ([?][rationale-release-profile]). This is primarily +useful for users of tier three targets. + +> [!NOTE] +> +> Configuration of the pre-built standard library is split across bootstrap and +> the Cargo packages for the standard library. As much of this configuration as +> possible should be moved to the Cargo profile for these packages so that the +> artifacts produced by build-std match the pre-built standard library as much +> as is feasible. + +Alongside `build-std`, a `build-std-crate` key will be introduced +([?][rationale-build-std-crate]), which can be used to specify which crate from +the standard library is to be built. Only "core", "alloc" and "std" are valid +values for `build-std-crate`. + +```toml +[build] +build-std-crate = "std" +``` + +If [*Stage 1b* of this proposal][stage1b] is implemented then `build-std-crate` +will not be used unless explicitly set and the crate graph's dependencies on the +standard library will determine which crates are built instead. Otherwise, +`build-std-crate` will default to "std". + +> [!NOTE] +> +> Inspired by the concept of [opaque dependencies][Opaque dependencies], the +> standard library is resolved differently to other dependencies: +> +> - The lockfile included in the standard library source will be used when +> resolving the standard library's dependencies ([?][rationale-lockfile]). +> +> - The dependencies of the standard library crates are entirely opaque to the +> user. Different semver-compatible versions of these dependencies can +> exist in the user's resolve. The user cannot control compilation any of +> the dependencies of the `core`, `alloc` or `std` standard library crates +> individually (via profile overrides, for example). +> +> - The profiles defined by the standard library will be used. +> +> Cargo will resolves the dependencies of opaque dependencies, such as the +> standard library, separately in their own workspaces. The "roots" of such a +> resolve are defined as the unified set of packages that any crate in the +> dependency graph has a explicit dependency on and those which Cargo infers a +> direct dependency on. A dependency on the roots are added to all crates in the +> "parent" resolve. +> +> Regardless of which standard library crates are being built, Cargo will build +> the `sysroot` crate of the standard library workspace. `alloc` and `std` will +> be optional dependencies of the `sysroot` crate which will be enabled when the +> user has requested them. The sysroot always depends on the `proc_macro` and +> `test` crates. Panic runtimes are dependencies of `std` and will be enabled +> depending on the features that Cargo passes to `std` (see +> [*Panic strategies*][panic-strategies]). +> +> rustc loads panic runtimes in a different way to most dependencies, and +> without looking in the sysroot they will fail to load correctly unless passed +> in with `--extern`. rustc will need to be patched to be able to load panic +> runtimes from `-L dependency=` paths in line with other transitive +> dependencies. +> +> The standard library will always be a non-incremental build +> ([?][rationale-incremental]), with no `depinfo` produced, and only a `rlib` +> produced (no `dylib`) ([?][rationale-no-dylib]). It will be built into the +> `target` directory of the crate or workspace like any other dependency. + +The host pre-built standard library will always be used for procedural macros +and build scripts ([?][rationale-sysroot-for-host-deps]). Artifact dependencies +use the same standard library as the rest of the crate (pre-built or +newly-built, as appropriate). + +*See the following sections for rationale/alternatives:* + +- [*Why put `build-std` in the Cargo config?*][rationale-build-std-in-config] +- [*Why accept `off` as a value for `build-std`?*][rationale-build-std-off] +- [*Why add `build-std` to the `[target.]` and `[target.]` sections?*][rationale-build-std-target-section] +- [*Why does `[target]` take precedence over `[build]` for `build-std`?*][rationale-build-std-precedence] +- [*Why does "always" rebuild unconditionally?*][rationale-unconditional] +- [*Why does "always" rebuild in release profile?*][rationale-release-profile] +- [*Why add `build-std-crate`?*][rationale-build-std-crate] +- [*Why use the lockfile of the `rust-src` component?*][rationale-lockfile] +- [*Why not build the standard library in incremental?*][rationale-incremental] +- [*Why not produce a `dylib` for the standard library?*][rationale-no-dylib] +- [*Why use the pre-built standard library for procedural macros and build-scripts?*][rationale-sysroot-for-host-deps] + +*See the following sections for relevant unresolved questions:* + +- [*What should the `build-std` configuration in `.cargo/config` be named?*][unresolved-config-name] +- [*What should the "always" and "off" values of `build-std` be named?*][unresolved-config-values] +- [*What should `build-std-crate` be named?*][unresolved-build-std-crate-name] + +## `restricted_std` +[restricted_std]: #restricted_std + +The existing `restricted_std` mechanism will be removed from the standard +library's [`build.rs`][std-build.rs]. + +*See the following sections for rationale/alternatives:* + +- [*Why remove `restricted_std`?*][rationale-remove-restricted-std] + +## Custom targets +[custom-targets]: #custom-targets + +Cargo will detect when the standard library is to be built for a custom target +and will emit an error ([?][rationale-disallow-custom-targets]). + +> [!NOTE] +> +> Cargo could detect use of a custom target either by comparing it with the list +> of built-in targets that rustc reports knowing about (via `--print target-list`) +> or by checking if a file exists at the path matching the provided target name. + +Custom targets can still be used with build-std on nightly toolchains provided +that `-Zunstable-options` is provided to Cargo. + +*See the following sections for rationale/alternatives:* + +- [*Why disallow custom targets?*][rationale-disallow-custom-targets] + +*See the following sections for future possibilities:* + +- [*Allow custom targets with build-std*][future-custom-targets] + +## Preventing implicit sysroot dependencies +[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]). + +> [!NOTE] +> +> rustc could add a `--no-implicit-sysroot-deps` flag with this behaviour. For +> example, writing `extern crate foo` in a crate will not load `foo.rlib` from +> the sysroot if it is present, but if an `--extern noprelude:bar.rlib` is +> provided which depends on a crate `foo`, rustc will look in `-L` paths and the +> sysroot for it. + +All Cargo dependencies are provided to the compiler using the +`--extern noprelude:` flag ([?][rationale-noprelude-with-extern]), including +explicit and implicit standard library dependencies. + +*See the following sections for rationale/alternatives:* + +- [*Why prevent rustc from loading root dependencies from the sysroot?*][rationale-root-sysroot-deps] +- [*Why use `noprelude` with `--extern`?*][rationale-noprelude-with-extern] + +## Vendored `rust-src` +[vendored-rust-src]: #vendored-rust-src + +When it is necessary to build the standard library, Cargo will look for sources +in a fixed location in the sysroot ([?][rationale-custom-src-path]): +`lib/rustlib/src`. rustup's `rust-src` component downloads standard library +sources to this location. If the sources are not found, Cargo will emit an error +and recommend the user download `rust-src` if using rustup. + +`rust-src` will contain the sources for the standard library crates as well as +its vendored dependencies ([?][rationale-vendoring]). As a consequence sources +of standard library dependencies will not need be fetched from crates.io. + +> [!NOTE] +> +> Cargo will not perform any checks to ensure that the sources in `rust-src` +> have been modified ([?][rationale-src-modifications]). It will be documented +> that modifying these sources is not supported. + +*See the following sections for rationale/alternatives:* + +- [*Why not allow the source path for the standard library be customised?*][rationale-custom-src-path] +- [*Why vendor standard library dependencies?*][rationale-vendoring] +- [*Why not check if `rust-src` has been modified?*][rationale-src-modifications] + +### `libunwind` +[libunwind]: #libunwind + +`libunwind`'s sources are included in the `rust-src` component so that they can +be used as part of the standard library build on targets which require it. + +## Panic strategies +[panic-strategies]: #panic-strategies + +Panic strategies are unlike other profile settings insofar as they influence +which crates are built and which flags are passed to the standard library build. +For example, if `panic = "unwind"` were set in the Cargo profile then the +`panic_unwind` feature would need to be provided to `std` and `-Cpanic=unwind` +passed to suggest that the compiler use that panic runtime. + +If Cargo is not building `std`, then neither of the panic runtimes will be +built. In this circumstance rustc will continue to throw an error when a +unwinding panic strategy is chosen. + +If the Cargo would build `std` for a project then Cargo's behaviour depends on +whether or not `panic` is set in the profile: + +- If `panic` is not set in the profile then unwinding may still be the default + for the target and Cargo will need to enable the `panic_unwind` feature to the + `sysroot` crate to build `panic_unwind` just in case it is used + +- If `panic` is set to "unwind" then the `panic_unwind` feature of `sysroot` + will be enabled and `-Cpanic=unwind` will be passed + +- If `panic` is set to "abort" then `-Cpanic=abort` will be passed + + - `panic_abort` is a non-optional dependency of `std` so it will always be + built + +Tests, benchmarks, build scripts and proc macros continue to ignore the "panic" +setting and `panic = "unwind"` is always used - which means the standard library +needs to be recompiled again if the user is using "abort". Once +`panic-abort-tests` is stabilised, the standard library can be built with the +profile's panic strategy even for tests and benchmarks. + +In line with Cargo's stance on not parsing the `RUSTFLAGS` environment variable, +it will not be checked for compilation flags that would require additional +crates to be built for compilation to succeed. + +*See the following sections for future possibilities:* + +- [*Avoid building `panic_unwind` unnecessarily*][future-panic_unwind] + +## Building the standard library on a stable toolchain +[building-the-standard-library-on-a-stable-toolchain]: #building-the-standard-library-on-a-stable-toolchain + +rustc will automatically assume `RUSTC_BOOTSTRAP` when the source path of the +crate being compiled is within the same sysroot as the rustc binary being +invoked ([?][rationale-implied-bootstrap]). Cargo will not need to use +`RUSTC_BOOTSTRAP` when compiling the standard library with a stable toolchain. + +*See the following sections for rationale/alternatives:* + +- [*Why allow building from the sysroot with implied `RUSTC_BOOTSTRAP`?*][rationale-implied-bootstrap] + +## Special object files +[special-object-files]: #special-object-files + +A handful of targets require linking against special object files, such as +`windows-gnu`, `linux-musl` and `wasi` targets. For example, `linux-musl` +targets require `crt1.o`, `crti.o`, `crtn.o`, etc. + +Since [rust#76185]/[compiler-team#343], the compiler has a stable +`-Clink-self-contained` flag which will look for special object files in +expected locations, typically populated by the `rust-std` components. Its +behaviour can be forced by `-Clink-self-contained=true`, but is force-enabled +for some targets and inferred for others. + +Rust can start to ship `rust-self-contained` components for any targets which +need it. These components will contain the special object files normally +included in `rust-std`, and will be distributed for all tiers of targets. While +generally these objects are specific to the architecture and C runtime (CRT) +(and so `rust-self-contained-$arch-$crt` could be sufficient and result in fewer +overall components), it's technically possible that Rust could support two +targets with the same architecture and same CRT but different versions of the +CRT, so having target-specific components is most future-proof. These would +replace the `self-contained` directory in existing `rust-std` components. + +As long as these components have been downloaded, as well as any other support +components, such as `rust-mingw`, rustc's `-Clink-self-contained` will be able +to link against the object files and build-std should never fail on account of +missing special object files. + +*See the following sections for future possibilities:* + +- [*Enable local recompilation of special object files/sanitizer runtimes*][future-recompile-special] + +## `compiler-builtins` +[compiler-builtins]: #compiler-builtins + +`compiler-builtins` is always built with `-Ccodegen-units=10000` to force each +intrinsic into its own object file to avoid symbol clashes with libgcc. + +rustc will automatically use a large number of codegen units for the +`compiler-builtins` crate, unless manually specified using the `-Ccodegen-units` +flag (to support users, like Rust for Linux, that prefer a single codegen unit). +This prevents `compiler-builtins` from having to be special-cased in the +standard library workspace. + +> [!NOTE] +> +> [rust#135395] could be resurrected to implement this. + +### `compiler-builtins/mem` +[compiler-builtins-mem]: #compiler-builtinsmem + +The `mem` feature of `compiler_builtins` (and the subsequent +`compiler-builtins-mem` feature of `core`, `alloc`, `std` which forward to +`compiler_builtins/mem`) is required by `no_std` crates because `libc` does not +provide these symbols without `std`. + +It is necessary that the `compiler-builtins-mem` feature of `alloc` and/or +`core` be enabled when `std` is not in the crate graph +([?][rationale-no-weak-linkage]). + +*See the following sections for rationale/alternatives:* + +- [*Why not use weak linkage for `compiler-builtins/mem` symbols?*][rationale-no-weak-linkage] + +### `compiler-builtins/c` +[compiler-builtins-c]: #compiler-builtinsc + +The [`c` feature][background-dependencies] of `compiler_builtins` (which is also +exposed by `core`, `alloc` and `std` through `compiler-builtins-c`) causes its +`build.rs` file to build and link in more optimised C versions of intrinsics. + +It will not be enabled by default because it is possible that the target +platform does not have a suitable C compiler available. The user being able to +enable this manually will be enabled through work on features (see +[*Allow enabling/disabling features with build-std*][future-features] from Stage +1b). + +## Caching +[caching]: #caching + +Standard library artifacts built by build-std will not be shared between crates +or workspaces, as they only exist in the `target` directory of a specific crate +or workspace ([?][rationale-caching]). + +*See the following sections for rationale/alternatives:* + +- [*Why not globally cache builds of the standard library?*][rationale-caching] + +## Cargo subcommands +[cargo-subcommands]: #cargo-subcommands + +As opaque dependencies, any Cargo command which accepts a package spec with `-p` +will only additionally recognise `core`, `alloc` and `std` and none of their +dependencies. Many of Cargo's subcommands will need modification to support +build-std: + +[`cargo clean`][cargo-clean] will additionally delete any builds of the standard +library performed by build-std. + +[`cargo fetch`][cargo-fetch] will not fetch the standard library dependencies as +they are already vendored in the `rust-src` component. + +[`cargo miri`][cargo-miri] is not built into Cargo, it is shipped by miri, but +is mentioned in Cargo's documentation. `cargo miri` is unchanged by this RFC, +but build-std is one step towards `cargo miri` requiring less special support. + +> [!NOTE] +> +> `cargo miri` could be re-implemented using build-std to enable a `miri` +> profile and always rebuild. The `miri` profile would be configured in the +> standard library's workspace, setting the flags/options necessary for `miri`. + +[`cargo report`][cargo-report] will not include reports from the standard +library crates or their dependencies. + +[`cargo update`][cargo-update] will not update the dependencies of `std`, +`alloc` and `core`, as these are vendored as part of the distribution of +`rust-src` and resolved separately from the user's dependencies. Neither will +`std`, `alloc` or `core` be updated, as these are unversioned and always match +the current toolchain version. + +[`cargo vendor`][cargo-vendor] will not vendor standard library dependencies. +Vendoring these and using them later would effectively pin the crate to the +version of the language and toolchain used when vendoring was performed (as the +vendored standard library source would only work with that toolchain version). +Standard library crates are already vendored in the `rust-src` component, so do +not require network access once downloaded. + +The following commands will now build the standard library if required as part +of the compilation of the project, just like any other dependency: + +- [`cargo bench`][cargo-bench] +- [`cargo build`][cargo-build] +- [`cargo check`][cargo-check] +- [`cargo clippy`][cargo-clippy] +- [`cargo doc`][cargo-doc] +- [`cargo fix`][cargo-fix] +- [`cargo run`][cargo-run] +- [`cargo rustc`][cargo-rustc] +- [`cargo rustdoc`][cargo-rustdoc] +- [`cargo test`][cargo-test] + +This stage has no implications for the following Cargo subcommands: + +- [`cargo add`][cargo-add] +- [`cargo remove`][cargo-remove] +- [`cargo fmt`][cargo-fmt] +- [`cargo generate-lockfile`][cargo-generate-lockfile] +- [`cargo help`][cargo-help] +- [`cargo info`][cargo-info] +- [`cargo init`][cargo-init] +- [`cargo install`][cargo-install] +- [`cargo locate-project`][cargo-locate-project] +- [`cargo login`][cargo-login] +- [`cargo logout`][cargo-logout] +- [`cargo metadata`][cargo-metadata] +- [`cargo new`][cargo-new] +- [`cargo owner`][cargo-owner] +- [`cargo package`][cargo-package] +- [`cargo pkgid`][cargo-pkgid] +- [`cargo publish`][cargo-publish] +- [`cargo search`][cargo-search] +- [`cargo tree`][cargo-tree] +- [`cargo uninstall`][cargo-uninstall] +- [`cargo version`][cargo-version] +- [`cargo yank`][cargo-yank] + +## Stability guarantees +[stability-guarantees]: #stability-guarantees + +build-std enables a much greater array of configurations of the standard library +to exist and be produced by stable toolchains than the single configuration that +is distributed today. + +It is not feasible for the Rust project to test every combination of profile +configuration, Cargo feature, target and standard library crate. As such, the +stability of build-std as a mechanism must be separated from the stability +guarantees which apply to configurations of the standard library it enables. + +For example, while a stable build-std mechanism may permit the standard library +to be built for a tier three target, the Rust project continues to make no +commitments or guarantees that the standard library for that target will +function correctly or build at all. + +Cargo and Rust project documentation will clearly document the configurations +which are tested upstream and are guaranteed to work. Any other configurations +are supported on a strictly best-effort basis. The Rust project may later choose +to provide more guarantees for some well-tested configurations (e.g. enabling +sanitisers). + +There are also no guarantees about the exact configuration of the standard +library. Over time, the standard library built by build-std could be changed to +be closer to that of the pre-built standard library. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +This section aims to justify all of the decisions made in the proposed design +from [*Proposal*][proposal] and discuss why alternatives were not chosen. + +## Why put `build-std` in the Cargo config? +[rationale-build-std-in-config]: #why-put-build-std-in-the-cargo-config + +There are various alternatives to putting `build-std` in the Cargo configuration: + +1. Cargo could continue to use an explicit command-line flag to enable + build-std, such as the current `-Zbuild-std` (stabilised as `--build-std`). + + This approach is proven to work, as per the current unstable implementation, + but has a poor user experience, requiring an extra argument to every + invocation of Cargo with almost every subcommand of Cargo. + + However, this approach does not lend itself to use with other future and + current Cargo features. Additional flags would be required to enable Cargo + features (like today's `-Zbuild-std-features`) and would still necessarily be + less fine-grained than being able to enable features on individual standard + library crates. Similarly for public/private dependencies or customising the + profile for the standard library crates. + +2. build-std could be enabled or disabled in the `Cargo.toml`. However, under + which conditions the standard library is rebuilt is better determined by the + user of Cargo, rather than the project being built. + + A user may want to never rebuild the standard library so as to avoid + invalidating the guarantees of their qualified toolchain, or may want to + rebuild unconditionally to further optimise the standard library for their + known deployment platform, or may only want to rebuild as necessary to ensure + the build will succeed. All of these rationale can apply to the same crate in + different circumstances, so it doesn't make sense for a crate to decide this + once in its `Cargo.toml`. + + It would be a waste of resources if a dependency declared that it must always + rebuild the standard library when the pre-built crate would be sufficient and + this could not be overridden. It is also unclear how to aggregate different + configurations of the `build-std` key from different crates in the dependency + graph into a single value. + +While using `build-std` key in the Cargo configuration shares some of the +downsides of using an explicit flag - not having a natural extension point for +other Cargo options exposed to dependencies - [Stage 1b][stage1b] addresses +these concerns. + +↩ [*Proposal*][proposal] + +## Why accept `off` as a value for `build-std`? +[rationale-build-std-off]: #why-accept-off-as-a-value-for-build-std + +While not a default value, the user can specify `off` if they prefer which will +never rebuild the standard library. rustc will still return an error when the +user's target-modifiers do not match the pre-built standard library. + +The `off` value is useful particularly for qualified toolchains where rebuilding +the standard library may invalidate the testing that the qualified toolchain has +undergone. + +↩ [*Proposal*][proposal] + +## Why add `build-std` to the `[target.]` and `[target.]` sections? +[rationale-build-std-target-section]: #why-add-build-std-to-the-targettriple-and-targetcfg-sections + +Supporting `build-std` as a key of both `[build]` and `[target]` sections allows +the greatest flexibility for the user. The overhead of rebuilding the standard +library may not be desirable in general but would be required when building on +targets which do not ship a pre-built standard library. + +↩ [*Proposal*][proposal] + +## Why does `[target]` take precedence over `[build]` for `build-std`? +[rationale-build-std-precedence]: #why-does-target-take-precedence-over-build-for-build-std + +`[target]` configuration is necessarily more narrowly scoped so it makes sense +for it to override a global default in `[build]`. + +↩ [*Proposal*][proposal] + +## Why does "always" rebuild unconditionally? +[rationale-unconditional]: #why-does-always-rebuild-unconditionally + +Rebuilding unconditionally avoids the complexity associated with an automatic +build-std mechanism while still being useful for users of tier three targets. By +leaving an automatic mechanism for a later stage, fewer of the technical +challenges of build-std need to be addressed all at once. + +Having an opt-in mechanism initially, such as `build-std = "always"`, allows for +early issues with build-std to be ironed out without potentially affecting more +users like an automatic mechanism. + +*See [Stage 2][stage2] for the introduction of an automatic build-std +mechanism.* + +↩ [*Proposal*][proposal] + +## Why does "always" rebuild in release profile? +[rationale-release-profile]: #why-does-always-rebuild-in-release-profile + +The release profile most closely matches the existing pre-built standard +library, which has proven itself suitable for a majority of use cases. + +By minimising the differences between a newly-built std and a pre-built std, +there is less chance of the user experiencing bugs or unexpected behaviour from +the well-tested and supported pre-built std. + +*See [Stage 3][stage3] for the introduction of customised standard library +builds.* + +↩ [*Proposal*][proposal] + +## Why add `build-std-crate`? +[rationale-build-std-crate]: #why-add-build-std-crate + +Not all standard library crates will build on all targets. In a `no_std` project +for a tier three target, `build-std-crate` gives the user the ability to limit +which crates are built to those they know they need and will build successfully. + +*See [Stage 1b][stage1b] for an alternative to `build-std-crate`.* + +↩ [*Proposal*][proposal] + +## Why use the lockfile of the `rust-src` component? +[rationale-lockfile]: #why-use-the-lockfile-of-the-rust-src-component + +Using different dependency versions for the standard library would invalidate +the upstream testing of the standard library. In particular, some crates use +unstable APIs when included as a dependency of the standard library meaning that +there is a high risk of build breakage if any package version is changed. + +Using the lockfile included in the `rust-src` component guarantees that the same +dependency versions are used as in the pre-built standard library. As the +standard library does not re-export types from its dependencies, this will not +affect interoperability with the same dependencies of different versions used by +the user's crate. + +Using the lockfile does prevent Cargo from resolving the standard library +dependencies to newer patch versions that may contain security fixes. However, +this is already impossible with the pre-built standard library. + +See +[*Why vendor the standard library's dependencies?*][rationale-vendoring] + +↩ [*Proposal*][proposal] + +### Why not build the standard library in incremental? +[rationale-incremental]: #why-not-build-the-standard-library-in-incremental + +As the standard library sources are never modified, incremental compilation +would only add a compilation time overhead. + +↩ [*Proposal*][proposal] + +### Why not produce a `dylib` for the standard library? +[rationale-no-dylib]: #why-not-produce-a-dylib-for-the-standard-library + +The `std` crate's `Cargo.toml` is configured with +`crate-type = ["rlib", "dylib"]` so it can produce both artifacts. The Rust +project ships both artifacts, with the `dylib` only linked against when +`-Cprefer-dynamic` is enabled. However, the `dylib` is not part of Rust's +stability guarantee so a first-class way of specifying crate types is left to a +future extension. + +*See the following sections for future possibilities:* + +- [*Allow choosing the crate type of the standard library?*][future-crate-type] + +↩ [*Proposal*][proposal] + +## Why use the pre-built standard library for procedural macros and build-scripts? +[rationale-sysroot-for-host-deps]: #why-use-the-pre-built-standard-library-for-procedural-macros-and-build-scripts + +Procedural macros and build scripts always run on the host and need to be built +with a configuration that are compatible with the host toolchain's Cargo and +rustc. There is little advantage to using a custom standard library with +procedural macros or build scripts, as they are not part of the final output +artifact and anywhere they can run already have a toolchain with host tools and +a pre-built standard library. Procedural macros must link against the compiler +which further limits potential use cases to those without `target-modifiers`. + +↩ [*Proposal*][proposal] + +### Why remove `restricted_std`? +[rationale-remove-restricted-std]: #why-remove-restricted_std + +`restricted_std` was originally added as part of a mechanism to enable the +standard library to build on all targets (just with stubbed out functionality), +however stability is not an ideal match for this use case. rustc will still try +to compile unstable code, so this won't help ensure the standard library builds +on all targets. + +Furthermore, when `restricted_std` applies, users must add +`#![feature(restricted_std)]` to opt-in to using the standard library anyway +(conditionally, only for affected targets), and have no mechanism for opting-in +on behalf of their dependencies (including first-party crates like `libtest`). + +↩ [*`restricted_std`*][restricted_std] + +### Why disallow custom targets? +[rationale-disallow-custom-targets]: #why-disallow-custom-targets + +While custom targets can be used on stable today, in practice, they are only +used on nightly as `-Zbuild-std` would need to be used to build at least `core`. +As such, if build-std were to be stabilised, custom targets would become much +more usable on stable toolchains. + +In order to avoid users relying on the [unstable target-spec-json][rust#71009] +format on a stable toolchain, using custom targets with build-std on a stable +toolchain is disallowed by Cargo until another RFC can consider all the +implications of this thoroughly. The idea of rustc disallowing custom targets on +stable is covered in [rust#71009]. + +↩ [*Custom targets*][custom-targets] + +### Why prevent rustc from loading root dependencies from the sysroot? +[rationale-root-sysroot-deps]: #why-prevent-rustc-from-loading-root-dependencies-from-the-sysroot + +Loading root dependencies from the sysroot could be a source of bugs. + +For example, if a crate has an explicit dependency on `core` which is newly +built, then there will be no `alloc` or `std` builds present. A user could still +write `extern crate alloc` and accidentally load `alloc` from the sysroot +(compiled with the default profile settings) and consequently `core` from the +sysroot, conflicting with the newly build `core`. `extern crate alloc` should +only be able to load the `alloc` crate if the crate depends on it in its +`Cargo.toml`. A similar circumstance can occur with dependencies like +`panic_unwind` that the compiler tries to load itself. + +Dependencies of packages can still be loaded from the sysroot, even with +`--no-implicit-sysroot-deps`, to support the circumstance where Cargo uses a +pre-built standard library crate (e.g. +`$sysroot/lib/rustlib/$target/lib/std.rlib`) and needs to load the dependencies +of that crate which are also in the sysroot. + +`--no-implicit-sysroot-deps` is a flag rather than default behaviour to preserve +rustc's usability when invoked outside of Cargo. For example, by compiler +developers when working on rustc. + +`--sysroot=''` is an existing mechanism for disabling the sysroot - this is not +used as it remains desirable to load dependencies from the sysroot as a +fallback. In addition, rustc uses the sysroot path to find `rust-lld` and +similar tools and would not be able to do so if the sysroot were disabled by +providing an empty path. + +↩ [*Preventing implicit sysroot dependencies*][preventing-implicit-sysroot-dependencies] + +### Why use `noprelude` with `--extern`? +[rationale-noprelude-with-extern]: #why-use-noprelude-with---extern + +The `noprelude` modifier for `--extern` is necessary for use of the `--extern` +flag to be equivalent to using a modified sysroot. + +Without `noprelude`, rustc implicitly inserts a `extern crate $name` when using +`--extern`. As a consequence, if a newly-built `alloc` were passed using +`--extern alloc=alloc.rlib` then `extern crate alloc` would not be required, but +it would be if the pre-built `alloc` could be used. This difference in how a +crate is made available to rustc should not be observable to the user. + +↩ [*Preventing implicit sysroot dependencies*][preventing-implicit-sysroot-dependencies] + +### Why not allow the source path for the standard library be customised? +[rationale-custom-src-path]: #why-not-allow-the-source-path-for-the-standard-library-be-customised + +It is not a goal of this proposal to enable or improve the usability of custom +or modified standard libraries. + +↩ [*Vendored `rust-src`*][vendored-rust-src] + +### Why vendor the standard library's dependencies? +[rationale-vendoring]: #why-vendor-the-standard-librarys-dependencies + +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.. + +- Avoid needing to support standard library dependencies in `cargo vendor` +- Avoid needing to support standard library dependencies in `cargo fetch` +- Re-building the standard library does not require an internet connection +- Standard library dependency versions are fixed to those in the `Cargo.lock` + anyway, so initial builds with `build-std` start quicker with these + dependencies already available +- Allow build-std to continue functioning if a `crates.io` dependency is + "yanked" + - This leaves the consequences of a toolchain version using yanked + dependencies the same as without this RFC + +..and few disadvantages: + +- A larger `rust-src` component takes up more disk space and takes longer to + download + - If using build-std, these dependencies would have to be downloaded at build + time, so this is only an issue if build-std is not used and `rust-src` is + downloaded. +- Vendored dependencies can't be updated with the latest security fixes + - This is no different than the pre-built standard library + +How this affects `crates.io`/`rustup` bandwidth usage or user time spent +downloading these crates is unclear and depends on user patterns. If not +vendored, Cargo will "lazily" download them the first time `build-std` is used +but this may happen multiple times if they are cleaned from its cache without +upgrading the toolchain version. + +See +[*Why use the lockfile of the `rust-src` component?*][rationale-lockfile] + +↩ [*Vendored `rust-src`*][vendored-rust-src] + +### Why not check if `rust-src` has been modified? +[rationale-src-modifications]: #why-not-check-if-rust-src-has-been-modified + +It is likely that any protections implemented to check that the sources in +`rust-src` have not been modified could be trivially bypassed. + +Any crate that depends on `rust-src` having been modified would not be usable +when published to crates.io as the required modifications will obviously not be +included. + +↩ [*Vendored `rust-src`*][vendored-rust-src] + +### Why allow building from the sysroot with implied `RUSTC_BOOTSTRAP`? +[rationale-implied-bootstrap]: #why-allow-building-from-the-sysroot-with-implied-rustc_bootstrap + +Cargo needs to be able to build the standard library crates, which inherently +require a nightly toolchain. It could set `RUSTC_BOOTSTRAP` internally to do +this with a stable toolchain, however this is a shared requirement with other +build systems that wish to build an unmodified standard library and want to work +on stable toolchains. + +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. + +It is not sufficient for rustc to special-case the `core`, `alloc` and `std` +crate names as when being built as part of the standard library, dependencies of +the standard library also use unstable features and so these crate would also +need such special-casing, which is not practical. + +↩ [*Building the standard library on a stable toolchain*][building-the-standard-library-on-a-stable-toolchain] + +### Why not use weak linkage for `compiler-builtins/mem` symbols? +[rationale-no-weak-linkage]: #why-not-use-weak-linkage-for-compiler-builtinsmem-symbols + +Since [compiler-builtins#411], the relevant symbols in `compiler_builtins` +already have weak linkage. However, it is nevertheless not possible to simply +remove the `mem` feature and have the symbols always be present. + +Some targets, such as those based on MinGW, do not have sufficient support for +weak definitions (at least with the default linker). Furthermore, weak linkage +has precedence over shared libraries and the symbols of a dynamically-linked +`libc` should be preferred over `compiler_builtins`'s symbols. + +↩ [*`compiler-builtins-mem`*][compiler-builtins-mem] + +### Why not globally cache builds of the standard library? +[rationale-caching]: #why-not-globally-cache-builds-of-the-standard-library + +The standard library is no different than regular dependencies in being able to +benefit from global caching of dependency builds. A generic proposal for global +dependency caching could support the standard library. It is out-of-scope of +this proposal to propose a special-cased mechanism for this that applies only to +the standard library. + +↩ [*Caching*][caching] + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +The following small details are likely to be bikeshed prior to Stage 1a acceptance or +stabilisation and aren't pertinent to the overall design: + +## What should the `build-std` configuration in `.cargo/config` be named? +[unresolved-config-name]: #what-should-the-build-std-configuration-in-cargoconfig-be-named + +What should this configuration option be named? `build-std`? +`rebuild-standard-library`? + +↩ [*Proposal*][proposal] + +## What should the "always" and "off" values of `build-std` be named? +[unresolved-config-values]: #what-should-the-always-and-off-values-of-build-std-be-named + +What is the most intuitive name for the values of the `build-std` setting? +`always`? `manual`? `unconditional`? + +↩ [*Proposal*][proposal] + +## What should `build-std-crate` be named? +[unresolved-build-std-crate-name]: #what-should-build-std-crate-be-named + +What should this configuration option be named? + +↩ [*Proposal*][proposal] + +# Future possibilities +[future-possibilities]: #future-possibilities + +There are many possible follow-ups to Stage 1a: + +## Allow custom targets with build-std +[future-custom-targets]: #allow-custom-targets-with-build-std + +This would require a decision from the relevant teams on the exact stability +guarantees of the target-spec-json format and whether any large changes to +the format are desirable prior to broader use. + +↩ [*Custom targets*][custom-targets] + +## Avoid building `panic_unwind` unnecessarily +[future-panic_unwind]: #avoid-building-panic_unwind-unnecessarily + +This would require adding a `--print default-unwind-strategy` flag to rustc and +using that to avoid building `panic_unwind` if the default is abort for any +given target and `panic` is not set in the profile. + +↩ [*Panic strategies*][panic-strategies] + +## Enable local recompilation of special object files/sanitizer runtimes +[future-recompile-special]: #enable-local-recompilation-of-special-object-filessanitizer-runtimes + +These files are shipped pre-compiled for relevant targets and are not compiled +locally. If a user wishes to customise the compilation of these files like the +standard library, then there is no mechanism to do so. + +↩ [*Special object files*][special-object-files] + +## Allow choosing the crate type of the standard library? +[future-crate-type]: #allow-choosing-the-crate-type-of-the-standard-library + +The standard library supports being built as both a `rlib` and a `dylib`, but +only `dylib` is not part of the project's stability guarantee so only an `rlib` +is built by build-std. This could be relaxed so that a `rlib` and `dylib` are +produced by build-std. + +↩ [*Why not produce a `dylib` for the standard library?*][rationale-no-dylib] + +[background-dependencies]: ./1-background.md#dependencies +[future-features]: ./5-stage-1b.md#allow-enablingdisabling-features-with-build-std +[stage1b]: ./5-stage-1b.md +[stage2]: ./6-stage-2.md +[stage3]: ./7-stage-3.md + +[Opaque dependencies]: https://hackmd.io/@epage/ByGfPtRell + +[compiler-builtins#411]: https://github.com/rust-lang/compiler-builtins/pull/411 +[compiler-team#343]: https://github.com/rust-lang/compiler-team/issues/343 +[rust#76185]: https://github.com/rust-lang/rust/pull/76185 +[rust#71009]: https://github.com/rust-lang/rust/pull/71009 +[rust#135395]: https://github.com/rust-lang/rust/pull/135395 + +[std-build.rs]: https://github.com/rust-lang/rust/blob/f315e6145802e091ff9fceab6db627a4b4ec2b86/library/std/build.rs#L17 + +[cargo-add]: https://doc.rust-lang.org/cargo/commands/cargo-add.html +[cargo-bench]: https://doc.rust-lang.org/cargo/commands/cargo-bench.html +[cargo-build]: https://doc.rust-lang.org/cargo/commands/cargo-build.html +[cargo-check]: https://doc.rust-lang.org/cargo/commands/cargo-check.html +[cargo-clean]: https://doc.rust-lang.org/cargo/commands/cargo-clean.html +[cargo-clippy]: https://doc.rust-lang.org/cargo/commands/cargo-clippy.html +[cargo-doc]: https://doc.rust-lang.org/cargo/commands/cargo-doc.html +[cargo-fetch]: https://doc.rust-lang.org/cargo/commands/cargo-fetch.html +[cargo-fix]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html +[cargo-fmt]: https://doc.rust-lang.org/cargo/commands/cargo-fmt.html +[cargo-generate-lockfile]: https://doc.rust-lang.org/cargo/commands/cargo-generate-lockfile.html +[cargo-help]: https://doc.rust-lang.org/cargo/commands/cargo-help.html +[cargo-info]: https://doc.rust-lang.org/cargo/commands/cargo-info.html +[cargo-init]: https://doc.rust-lang.org/cargo/commands/cargo-init.html +[cargo-install]: https://doc.rust-lang.org/cargo/commands/cargo-install.html +[cargo-locate-project]: https://doc.rust-lang.org/cargo/commands/cargo-locate-project.html +[cargo-login]: https://doc.rust-lang.org/cargo/commands/cargo-login.html +[cargo-logout]: https://doc.rust-lang.org/cargo/commands/cargo-login.html +[cargo-metadata]: https://doc.rust-lang.org/cargo/commands/cargo-metadata.html +[cargo-miri]: https://doc.rust-lang.org/cargo/commands/cargo-miri.html +[cargo-new]: https://doc.rust-lang.org/cargo/commands/cargo-new.html +[cargo-owner]: https://doc.rust-lang.org/cargo/commands/cargo-owner.html +[cargo-package]: https://doc.rust-lang.org/cargo/commands/cargo-package.html +[cargo-pkgid]: https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html +[cargo-publish]: https://doc.rust-lang.org/cargo/commands/cargo-publish.html +[cargo-remove]: https://doc.rust-lang.org/cargo/commands/cargo-remove.html +[cargo-report]: https://doc.rust-lang.org/cargo/commands/cargo-report.html +[cargo-run]: https://doc.rust-lang.org/cargo/commands/cargo-run.html +[cargo-rustc]: https://doc.rust-lang.org/cargo/commands/cargo-rustc.html +[cargo-rustdoc]: https://doc.rust-lang.org/cargo/commands/cargo-rustdoc.html +[cargo-search]: https://doc.rust-lang.org/cargo/commands/cargo-search.html +[cargo-test]: https://doc.rust-lang.org/cargo/commands/cargo-test.html +[cargo-tree]: https://doc.rust-lang.org/cargo/commands/cargo-tree.html +[cargo-uninstall]: https://doc.rust-lang.org/cargo/commands/cargo-uninstall.html +[cargo-update]: https://doc.rust-lang.org/cargo/commands/cargo-update.html +[cargo-vendor]: https://doc.rust-lang.org/cargo/commands/cargo-vendor.html +[cargo-version]: https://doc.rust-lang.org/cargo/commands/cargo-version.html +[cargo-yank]: https://doc.rust-lang.org/cargo/commands/cargo-yank.html \ No newline at end of file diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md new file mode 100644 index 00000000000..d87c8a69708 --- /dev/null +++ b/text/0000-build-std/5-stage-1b.md @@ -0,0 +1,979 @@ +# Proposal +[proposal]: #proposal + +Users can now optionally declare explicit dependencies on the standard library +in their `Cargo.toml` files ([?][rationale-why-explicit-deps]): + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2024" + +[dependencies] +std = { builtin = true } +``` + +`builtin` is a new source of dependency, like registry dependencies (with the +`version` key and optionally the `registry` key), `path` dependencies or `git` +dependencies. `builtin` can only be set to `true` and cannot be combined with +any other dependency source for a given dependency +([?][rationale-builtin-other-sources]). `builtin` can only be used with crates +named `core`, `alloc` or `std` ([?][rationale-no-builtin-other-crates]) on +stable, but can be with any crate name on nightly +([?][rationale-nightly-builtin-crates]). + +Crates without an explicit dependency on the standard library now have a +implicit dependency ([?][rationale-no-migration]) on `std`. In the `hello_world` +crate below, there are no explicit `builtin` dependencies.. + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2024" + +[dependencies] +``` + +..which is equivalent to the following explicit dependency: + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2024" + +[dependencies] +std = { builtin = true } +``` + +A dependency on `std` implies a direct dependency on `alloc` and `core`, and +likewise a dependency on `alloc` implies a direct dependency on `core` +([?][rationale-direct-deps]). Therefore, the following explicit dependency on +`std`: + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2024" + +[dependencies] +std = { builtin = true } +``` + +..is equivalent to: + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2024" + +[dependencies] +std = { builtin = true } +alloc = { builtin = true } +core = { builtin = true } +``` + +Any explicit `builtin` dependency present in the manifest will disable the +implicit dependency on `std`. + +When a `std` dependency is present an additional implicit dependency on the +`test` crate is added for crates that are being tested with the default test +harness. The `test` crate's name, but not its interface, will be stabilised so +Cargo can refer to it. + +crates.io will accept crates published which have `builtin` dependencies. + +Standard library dependencies can be marked as `optional` and be enabled +conditionally by a feature in the crate: + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2024" + +[dependencies] +std = { builtin = true, optional = true } +core = { builtin = true } + +[features] +default = ["std"] +std = ["dep:std"] +``` + +If there is an optional dependency on the standard library then there must be at +least one non-optional dependency on the standard library (e.g. an optional +`std` and non-optional `core` or `alloc`, or an optional `alloc` and +non-optional `core`). `core` cannot be optional. + +Dependencies with `builtin = true` cannot be renamed with the `package` key +([?][rationale-package-key]). It is not possible to perform source replacement +on the `builtin` source using the `[source]` Cargo config table +([?][rationale-source-replacement]). + +Dependencies with `builtin = true` can be specified as platform-specific +dependencies: + +```toml +[target.'cfg(unix)'.dependencies] +std = { builtin = true} +``` + +Implicit and explicit standard library dependencies are added to `Cargo.lock` +files ([?][rationale-cargo-lock]). + +> [!NOTE] +> +> A new version of the `Cargo.lock` file will be introduced to add support for +> packages with a `builtin` source: +> +> ```toml +> [[package]] +> name = "std" +> version = "0.0.0" +> source = "builtin" +> ``` +> +> The package version of `std`, `alloc` and `core` will be fixed at `0.0.0`. The +> optional lockfile fields `dependencies` and `checksum` will not be present for +> `builtin` dependencies. + +*See the following sections for rationale/alternatives:* + +- [*Why not replace `#![no_std]` as the source-of-truth for whether a crate depends on `std`?*][rationale-replace-no_std] +- [*Why explicitly declare dependencies on the standard library in `Cargo.toml`?*][rationale-why-explicit-deps] +- [*Why disallow builtin dependencies to be combined with other sources?*][rationale-builtin-other-sources] +- [*Why disallow builtin dependencies on other crates?*][rationale-no-builtin-other-crates] +- [*Why allow all names for `builtin` crates on nightly?*][rationale-nightly-builtin-crates] +- [*Why not migrate to always requiring explicit standard library dependencies?*][rationale-no-migration] +- [*Why must `std`, `alloc` and `core` always be considered direct dependencies?*][rationale-direct-deps] +- [*Why disallow renaming standard library dependencies?*][rationale-package-key] +- [*Why disallow source replacement on `builtin` packages?*][rationale-source-replacement] +- [*Why add standard library dependencies to Cargo.lock?*][rationale-cargo-lock] + +*See the following sections for relevant unresolved questions:* + +- [*What syntax is used to identify dependencies on the standard library in `Cargo.toml`?*][unresolved-dep-syntax] +- [*What is the format for builtin dependencies in `Cargo.lock`?*][unresolved-lockfile] + +*See the following sections for future possibilities:* + +- [*Allow `builtin` source replacement*][future-source-replacement] + +## Non-`builtin` standard library dependencies +[non-builtin-standard-library-dependencies]: #non-builtin-standard-library-dependencies + +Cargo already supports `path` and `git` dependencies for crates named `core`, +`alloc` and `std` which continue to be supported and work: + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2024" + +[dependencies] +std = { path = "../my_std" } # already supported by Cargo +``` + +A `core`/`alloc`/`std` dependency with a `path`/`git` source can be combined +with `builtin` dependencies: + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2024" + +[dependencies] +std = { path = "../my_std" } +core = { builtin = true } +``` + +Crates with these dependency sources will remain unable to be published to +crates.io. + +## Patches +[patches]: #patches + +On nightly toolchains, it is permitted to patch the standard library +dependencies with `path` and `git` sources (or any other source) +([?][rationale-patching]): + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2024" + +[dependencies] +std = { builtin = true } + +[patch.builtin] # permitted on nightly +std = { .. } + +[patch.builtin] # permitted on nightly +std = { path = "../libstd" } +``` + +As with dependencies, crates with `path`/`git` patches for `core`, `alloc` or +`std` are not accepted by crates.io. + +*See the following sections for rationale/alternatives:* + +- [*Why permit patching of the standard library dependencies on nightly?*][rationale-patching] + +*See the following sections for relevant unresolved questions:* + +- [*What syntax is used to patch dependencies on the standard library in `Cargo.toml`?*][unresolved-patch-syntax] + +## Features +[features]: #features + +On a stable toolchain, it is not permitted to enable or disable features of +explicit standard library dependencies ([?][rationale-features]), as in the +below example: + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2024" + +[dependencies] +std = { builtin = true, features = [ "foo" ] } # not permitted +# ..or.. +std = { builtin = true, default-features = false } # not permitted +``` + +*See the following sections for rationale/alternatives:* + +- [*Why limit enabling standard library features to nightly?*][rationale-features] + +*See the following sections for future possibilities:* + +- [*Allow enabling/disabling features with build-std*][future-features] + +## Public and private dependencies +[public-and-private-dependencies]: #public-and-private-dependencies + +Implicit dependencies on the standard library default to being public +dependencies ([?][rationale-implicit-public]). When a standard library is +explicitly written, then it will be private by default, like any other written +dependency, unless explicitly marked as public ([?][rationale-explicit-private]). + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2024" + +[dependencies] +``` + +..is equivalent to the following explicit dependency on `std`: + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2024" + +[dependencies] +std = { builtin = true, public = true } +``` + +*See the following sections for rationale/alternatives:* + +- [*Why default to public for the implicit standard library dependencies?*][rationale-implicit-public] +- [*Why follow the default privacy of explicit standard library dependencies?*][rationale-explicit-private] + +## `dev-dependencies` and `build-dependencies` +[dev-dependencies-and-build-dependencies]: #dev-dependencies-and-build-dependencies + +Explicit dependencies on the standard library are not supported in +`build-dependencies` ([?][rationale-no-deps-in-build-deps]). + +Implicit and explicit dependencies on the standard library are supported for +`dev-dependencies` in the same way as regular `dependencies`. + +## Registries +[registries]: #registries + +Standard library dependencies will be present in the registry index +([?][rationale-cargo-index]). A `builtin_deps` key is added to the +[index's JSON schema][cargo-json-schema] ([?][rationale-cargo-builtindeps]). +`builtin_deps` is similar to the existing `deps` key and contains a list of JSON +objects, each representing a dependency that is "builtin" to the Rust toolchain +and cannot otherwise be found in the registry. + +> [!NOTE] +> +> It is expected that the keys of these objects will be: +> +> - `name` +> - String containing name of the `builtin` package. Can shadow the names of +> other packages in the registry (except those packages in the `deps` key +> of the current package) ([?][rationale-cargo-index-shadowing]) +> +> - `features`: +> - An array of strings containing enabled features in order to support changing +> the standard library features on nightly. Optional, empty by default. +> +> - `optional`, `default_features`, `target`, `kind`: +> - These keys have the same definition as in the `deps` key. +> +> The keys `req`, `registry` and `package` from `deps` are not required per the +> limitations on builtin dependencies. +> +> The key is optional and its default value will be the implicit builtin +> dependencies: +> +> ```json +> "builtin_deps" : [ +> { +> "name": "std", +> "features": [], +> "optional": false, +> "default_features": true, +> "target": null, +> "kind": "normal", +> }, +> { +> "name": "alloc", +> ... # as above +> }, +> { +> "name": "core", +> ... # as above +> } +> ] +> ``` + +*See the following sections for rationale/alternatives:* + +- [*Why add standard library crates to Cargo's index?*][rationale-cargo-index] +- [*Why add a new key to Cargo's registry index JSON schema?*][rationale-cargo-builtindeps] +- [*Why can `builtin_deps` shadow other packages in the registry?*][rationale-cargo-index-shadowing] + +## Cargo subcommands +[cargo-subcommands]: #cargo-subcommands + +As opaque dependencies, any Cargo command which accepts a package spec with `-p` +will only additionally recognise `core`, `alloc` and `std` and none of their +dependencies. Many of Cargo's subcommands will need modification to support +build-std: + +[`cargo add`][cargo-add] will add `core`, `alloc` or `std` explicitly to the +manifest if invoked with those crate names: + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2024" + +[dependencies] +std = { builtin = true } # <-- this would be added +``` + +[`cargo info`][cargo-info] will learn how to print information for the built-in +`std`, `alloc` and `core` dependencies: + +```shell-session +$ cargo info std +std +rust standard library +license: Apache 2.0 + MIT +rust-version: 1.86.0 +documentation: https://doc.rust-lang.org/1.86.0/std/index.html +``` + +```shell-session +$ cargo info alloc +alloc +rust standard library +license: Apache 2.0 + MIT +rust-version: 1.86.0 +documentation: https://doc.rust-lang.org/1.86.0/alloc/index.html +``` + +```shell-session +$ cargo info core +core +rust standard library +license: Apache 2.0 + MIT +rust-version: 1.86.0 +documentation: https://doc.rust-lang.org/1.86.0/core/index.html +``` + +[`cargo metadata`][cargo-metadata] will emit `std`, `alloc` and `core` +dependencies to the metadata emitted by `cargo metadata` (when those crates are +dependencies). None of the standard library's dependencies will be included. +`source` would be set to `builtin` and the remaining fields would be set like +any other dependency. + +> [!NOTE] +> +> `cargo metadata` output could look as follows: +> +> ```json +> { +> "packages": [ +> { +> /* ... */ +> "dependencies": [ +> { +> "name": "std", +> "source": "builtin", +> "req": "*", +> "kind": null, +> "rename": null, +> "optional": false, +> "uses_default_features": true, +> "features": ["compiler-builtins-mem"], +> "target": null, +> "public": true +> } +> ], +> /* ... */ +> } +> ] +> } +> ``` + +[`cargo pkgid`][cargo-pkgid] when passed `-p core` would print `builtin#core` as +the source, likewise with `alloc` and `std`. + +[`cargo remove`][cargo-remove] will remove `core`, `alloc` or `std` explicitly +from the manifest if invoked with those crate names: + +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2024" + +[dependencies] +std = { builtin = true } # <-- this would be removed +``` + +[`cargo tree`][cargo-tree] will show `std`, `alloc` and `core` at appropriate +places in the tree of dependencies. `alloc` will always be shown as a dependency +of `std`, and `core` a dependency of `alloc`. As opaque dependencies, none of +the other dependencies of `std`, `alloc` or `core` will be shown. Neither `std`, +`alloc` or `core` will have a version number. + +> [!NOTE] +> +> `cargo tree` output could look as follows: +> +> ```shell-session +> $ cargo tree +> myproject v0.1.0 (/myproject) +> ├── rand v0.7.3 +> │ ├── getrandom v0.1.14 +> │ │ ├── cfg-if v0.1.10 +> │ │ │ └── core v0.0.0 +> │ │ ├── libc v0.2.68 +> │ │ │ └── core v0.0.0 +> │ │ └── core v0.0.0 +> │ ├── libc v0.2.68 (*) +> │ │ └── core v0.0.0 +> │ ├── rand_chacha v0.2.2 +> │ │ ├── ppv-lite86 v0.2.6 +> │ │ │ └── core v0.0.0 +> │ │ ├── rand_core v0.5.1 +> │ │ │ ├── getrandom v0.1.14 (*) +> │ │ │ └── core v0.0.0 +> │ │ └── std v0.0.0 +> │ │ └── alloc v0.0.0 +> │ │ └── core v0.0.0 +> │ ├── rand_core v0.5.1 (*) +> │ └── std v0.0.0 (*) +> └── std v0.0.0 (*) +> ``` + +This stage has no implications for the following Cargo subcommands: + +- [`cargo bench`][cargo-bench] +- [`cargo build`][cargo-build] +- [`cargo check`][cargo-check] +- [`cargo clean`][cargo-clean] +- [`cargo clippy`][cargo-clippy] +- [`cargo doc`][cargo-doc] +- [`cargo fetch`][cargo-fetch] +- [`cargo fix`][cargo-fix] +- [`cargo fmt`][cargo-fmt] +- [`cargo generate-lockfile`][cargo-generate-lockfile] +- [`cargo help`][cargo-help] +- [`cargo init`][cargo-init] +- [`cargo install`][cargo-install] +- [`cargo locate-project`][cargo-locate-project] +- [`cargo login`][cargo-login] +- [`cargo logout`][cargo-logout] +- [`cargo miri`][cargo-miri] +- [`cargo new`][cargo-new] +- [`cargo owner`][cargo-owner] +- [`cargo package`][cargo-package] +- [`cargo publish`][cargo-publish] +- [`cargo report`][cargo-report] +- [`cargo run`][cargo-run] +- [`cargo rustc`][cargo-rustc] +- [`cargo rustdoc`][cargo-rustdoc] +- [`cargo search`][cargo-search] +- [`cargo test`][cargo-test] +- [`cargo uninstall`][cargo-uninstall] +- [`cargo update`][cargo-update] +- [`cargo vendor`][cargo-vendor] +- [`cargo version`][cargo-version] +- [`cargo yank`][cargo-yank] + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +This section aims to justify all of the decisions made in the proposed design +from [*Proposal*][proposal] and discuss why alternatives were not chosen. + +## Why not replace `#![no_std]` as the source-of-truth for whether a crate depends on `std`? +[rationale-replace-no_std]: #why-not-replace-no_std-as-the-source-of-truth-for-whether-a-crate-depends-on-std + +Crates can currently use the crate attribute `#![no_std]` to indicate a lack of +dependency on `std`. With `Cargo.toml` being used to express a dependency on the +standard library (or lack thereof), it is unintuitive for there to be two +sources-of-truth for this information. + +`#![no_std]` serves two purposes - it stops the compiler from loading `std` from +the sysroot and adding `extern crate std`, and it prevents the user from +depending on anything from `std` accidentally. + +`#![no_std]` could hypothetically be replaced by a lint to prevent use of the +standard library and a change to the compiler so that it loads the `std` +speculatively unless it is used. + +However, while rustc does have some support for speculatively loading crates, it +is not possible to do so and not declare them as a dependency in cross-crate +metadata. + +↩ [*Proposal*][proposal] + +## Why explicitly declare dependencies on the standard library in `Cargo.toml`? +[rationale-why-explicit-deps]: #why-explicitly-declare-dependencies-on-the-standard-library-in-cargotoml + +If there are no explicit dependencies on standard library crates, Cargo would +need to be able to determine which standard library crates to build when this is +required: + +- Cargo could unconditionally build `std`, `alloc` and `core`. Not only would + this be unnecessary and wasteful for `no_std` crates in the embedded + ecosystem, but sometimes a target may not support building `std` at all and + this would cause the build to fail. + +- rustc could support a `--print` value that would print whether the crate + declares itself as `#![no_std]` crate, and based on this, Cargo could build + `std` or only `core`. This would require asking rustc to parse crates' + sources while resolving dependencies, slowing build times. Alternatively, + Cargo can already read Rust source to detect frontmatter (for `cargo script`) + so it could additionally look for `#![no_std]` itself. Regardless of how it + determines a crate is no-std, Cargo would also need to know whether to build + `alloc` too, which checking for `#![no_std]` does not help with. Cargo could + go further and ask rustc whether a crate (or its dependencies) used `alloc`, + but this seems needlessly complicated. + +- Cargo could allow the user to specify which crates are required to be built, + such as with the existing options to the `-Zbuild-std=` flag. Stage 1a + proposes a `build-std-crates` flag to enable explicit dependencies to be a + separate part of this RFC. + +Furthermore, supporting explicit dependencies on standard library crates enables +use of other Cargo features that apply to dependencies in a natural and +intuitive way. If there were not explicit standard library dependencies and +enabling features on the `std` crate was desirable, then a mechanism other than +the standard syntax for this would be necessary, such as a flag (e.g. +`-Zbuild-std-features`) or option in Cargo's configuration. This also applies to +optional dependencies, public/private features, etc. + +↩ [*Proposal*][proposal] + +## Why disallow builtin dependencies to be combined with other sources? +[rationale-builtin-other-sources]: #why-disallow-builtin-dependencies-to-be-combined-with-other-sources + +If using `path`/`git` sources with `builtin` dependencies worked in the same way +as using `path`/`git` sources with `version` sources, then: crates with +`path`/`git` standard library dependencies could be pushed to crates.io. + +This is not desirable as it is unclear that supporting `path`/`git` sources +which shadow standard library crates was a deliberate choice and so enabling +that pattern to be used more widely when not necessary is needlessly permissive. + +In addition, when combined with a `git`/`path` source, the `version` constraint +also applies to package from the `git`/`path` source. If `version` were used +alongside `builtin`, then this behaviour would be a poor fit as.. + +- ..the `std`, `alloc` and `core` crates all currently have a version of `0.0.0` + +- ..choosing different version requirements for different `builtin` crates has + no purpose + +↩ [*Proposal*][proposal] + +## Why disallow builtin dependencies on other crates? +[rationale-no-builtin-other-crates]: #why-disallow-builtin-dependencies-on-other-crates + +`builtin` dependencies could be accepted on two other crates - dependencies of +the standard library, like `compiler_builtins`, or other crates in the sysroot +added manually by users, however: + +- The standard library's dependencies are not part of the stable interface of + the standard library and it is not desirable that users can observe their + existence or depend on them directly + +- Other crates in the sysroot added by users are not something that can + reasonably be supported by build-std and these crates should become regular + dependencies + +↩ [*Proposal*][proposal] + +## Why allow all names for `builtin` crates on nightly? +[rationale-nightly-builtin-crates]: #why-allow-all-names-for-builtin-crates-on-nightly + +For any crate shipped with the standard library in the sysroot, the user can +already write an `extern crate` declaration to use it. All crates other than +`std`, `alloc` or `core` are marked unstable either explicitly or implicitly +with the use of `-Zforce-unstable-if-unmarked` so this does not allow items from +these crates to be used on stable. + +For example, some users write benchmarks using `libtest` and have written +`extern crate test` without the `#[cfg(test)]` attribute to load the crate. +There may be other niche uses of unstable sysroot crates that this enables to +continue on nightly toolchains. + +All names are permitted for `builtin` crates rather than an allowlist to avoid +Cargo needing to hardcode the names of many of the crates in the sysroot, which +are inherently unstable. + +↩ [*Proposal*][proposal] + +## Why not migrate to always requiring explicit standard library dependencies? +[rationale-no-migration]: #why-not-migrate-to-always-requiring-explicit-standard-library-dependencies + +Explicit standard library dependencies with `builtin = true` will necessarily +only be understood by newer versions of Cargo. + +If all packages were required to add explicit dependencies (perhaps over an +edition or through some other mechanism), then every crate would require the +newest version of Cargo to be understood, effectively raising the MSRV of every +Rust crate. + +If only `no_std` crates (or crates with a `std` feature) add explicit +dependencies on `core` or `alloc` then a much smaller percentage of the crates +ecosystem will require the newest Cargo versions for their new explicit standard +library dependencies to be understood. + +Alternative syntaxes, such as requiring `version = "*"` for explicit standard +library dependencies, could be worthwhile to maintain a greater level of +compatibility with older toolchain versions. Any currently accepted syntax would +necessarily be interpreted differently by the build-std-supporting versions of +Cargo, so this approach has its own complications. For example, while +`version = "*"` would be understood by older versions of Cargo, it would attempt +to find the standard library crates on crates.io and fail unless empty crates +were published named `core`, `alloc` and `std`. This is not a build-std specific +issue and is true of any RFC adding to what can be written in `Cargo.toml`. + +↩ [*Proposal*][proposal] + +## Why must `std`, `alloc` and `core` always be considered direct dependencies? +[rationale-direct-deps]: #why-must-std-alloc-and-core-always-be-considered-direct-dependencies + +When a crate depends on `std`, the user can also write `extern crate alloc` or +`extern crate core` - this is equivalent to having a direct dependency on these +crates which is not added to the extern prelude. + +If `alloc` and `core` were considered indirect dependencies in this +circumstance, then they would be located in a `-L dependency=` directory, which +rustc would not search when loading a crate from `extern crate`. + +> [!NOTE] +> +> `alloc` and `core` must always be passed with `--extern`. + +↩ [*Proposal*][proposal] + +## Why disallow renaming standard library dependencies? +[rationale-package-key]: #why-disallow-renaming-standard-library-dependencies + +Cargo allows [renaming dependencies][cargo-docs-renaming] with the `package` +key, which allows user code to refer to dependencies by names which do not +match their `package` name in their respective `Cargo.toml` files. + +However, rustc expects the standard library crates to be present with their +existing names - for example, `core` is always added to the +[extern prelude][rust-extern-prelude]. + +Alternatively, a mechanism could be added to rustc so that it could be informed +of the user's names for `builtin` crates. + +↩ [*Proposal*][proposal] + +## Why disallow source replacement on `builtin` packages? +[rationale-source-replacement]: #why-disallow-source-replacement-on-builtin-packages + +Modifying the source code of the standard library in the `rust-src` component is +not supported. Source replacement of the `builtin` source could be a way to +support this in future but this is out-of-scope for this proposal. + +See [*Allow `builtin` source replacement*][future-source-replacement]. + +↩ [*Proposal*][proposal] + +## Why add standard library dependencies to `Cargo.lock`? +[rationale-cargo-lock]: #why-add-standard-library-dependencies-to-cargolock + +`Cargo.lock` is a direct serialisation of a resolve and that must be a two-way +non-lossy process in order to make the `Cargo.lock` useful without doing further +resolution to fill in missing `builtin` packages. + +↩ [*Proposal*][proposal] + +## Why permit patching of the standard library dependencies on nightly? +[rationale-patching]: #why-permit-patching-of-the-standard-library-dependencies-on-nightly + +Being able to patch `builtin = true` dependencies and replace their source with +a `path` dependency is required to be able to replace `rustc_dep_of_std`. As +crates which use these sources cannot be published to crates.io, this would not +enable a usable general-purpose mechanism for crates to modify the standard +library sources. This capability is restricted to nightly as that is all that is +required for it to be used in replacing `rustc_dep_of_std`. + +↩ [*Patches*][patches] + +## Why limit enabling standard library features to nightly? +[rationale-features]: #why-limit-enabling-standard-library-features-to-nightly + +If it were possible to enable features of the standard library crates on stable +then all of the standard library's current features would immediately be held to +the same stability guarantees as the rest of the standard library, which is not +desirable. See +[*Allow enabling/disabling features with build-std*][future-features] + +↩ [*Features*][features] + +## Why default to public for the implicit standard library dependencies? +[rationale-implicit-public]: #why-default-to-public-for-the-implicit-standard-library-dependencies + +There are crates building on stable which re-export from the standard library. +If the implicit standard library dependency were not public then these crates +would start to trigger the `exported_private_dependencies` lint when upgrading +to a version of Cargo with an implicit standard library dependency. + +↩ [*Public and private dependencies*][public-and-private-dependencies] + +## Why follow the default privacy of explicit standard library dependencies? +[rationale-explicit-private]: #why-follow-the-default-privacy-of-explicit-standard-library-dependencies + +This may be unintuitive when a user first writes an explicit standard library +dependency, triggering the `exported_private_dependency` lint, but this would be +caught immediately by the user. However, it is also unintuitive that the default +for privacy of a explicitly written dependency would depend on which crate the +dependency was (i.e. the standard library has a different default than +everything else). + +↩ [*Public and private dependencies*][public-and-private-dependencies] + +## Why not support explicit standard library dependencies in `build-dependencies`? +[rationale-no-deps-in-build-deps]: #why-not-support-explicit-standard-library-dependencies-in-build-dependencies + +`build-dependencies` only apply to build scripts which are run on the host +toolchain. There is little advantage to using a custom standard library with +build scripts as they are not part of the final output artifact and anywhere +they can run already has a toolchain with host tools and a pre-built standard +library. + +↩ [*`dev-dependencies` and `build-dependencies`*][dev-dependencies-and-build-dependencies] + +## Why add standard library crates to Cargo's index? +[rationale-cargo-index]: #why-add-standard-library-crates-to-cargos-index + +When Cargo builds the dependency graph, it is driven by the index (not +`Cargo.toml`), so builtin dependencies need to be included in the index. + +↩ [*Registries*][registries] + +## Why add a new key to Cargo's registry index JSON schema? +[rationale-cargo-builtindeps]: #why-add-a-new-key-to-cargos-registry-index-json-schema + +Cargo's [registry index schema][cargo-json-schema] is versioned and making a +behaviour-of-Cargo-modifying change to the existing `deps` keys would be a +breaking change. Each package is published under one particular version of the +schema, meaning that older versions of Cargo cannot use newer versions of +packages which are defined using a schema it does not have knowledge of. + +Cargo ignores packages published under an unsupported schema version, so older +versions of Cargo cannot use newer versions of packages relying on these +features. New schema versions are disruptive to users on older toolchains and +should be avoided where possible. + +Some new fields, including `rust-version`, were added to all versions of the +schema. Cargo ignores fields it does not have knowledge of, so older versions of +Cargo will simply not use `rust-version` and its presence does not change their +behaviour. + +Existing versions of Cargo already function correctly without knowledge of +crate's standard library dependencies. A new top-level key will be ignored by +older versions of Cargo, while newer versions will understand it. This is a +different approach to that taken when artifact dependencies were added to the +schema, as those do not have a suitable representation in older versions of +Cargo. + +The obvious alternative to a `builtin_deps` key is to modify `deps` entries with +a new `builtin: bool` field and to increment the version of the schema. However, +these entries would not be understood by older versions of Cargo which would +look in the registry to find these packages and fail to do so. + +That approach could be made to work if dummy packages for `core`/`alloc`/`std` +were added to registries. Older versions of Cargo would pass these to rustc +via `--extern` and shadow the real standard library dependencies in the sysroot, +so these packages would need to contain `extern crate std; pub use std::*;` (and +similar for `alloc`/`core`) to try and load the pre-built libraries from the +sysroot (this is the same approach as packages like [embed-rs][embed-rs-source] +take today, using `path` dependencies for the standard library to shadow it). + +↩ [*Registries*][registries] + +## Why can `builtin_deps` shadow other packages in the registry? +[rationale-cargo-index-shadowing]: #why-can-builtin_deps-shadow-other-packages-in-the-registry + +While `crates.io` forbids certain crate names including `std`, `alloc` and +`core`, third party registries may allow them without a warning. The schema +needs a way to refer to packages with the same name either in the registry or +builtin, which `builtin_deps` allows. + +`builtin_deps` names are not allowed to shadow names of packages in `deps` as +these would conflict when passed to rustc via `--extern`. + +↩ [*Registries*][registries] + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +The following small details are likely to be bikeshed prior to Stage 1b acceptance or +stabilisation and aren't pertinent to the overall design: + +## What syntax is used to identify dependencies on the standard library in `Cargo.toml`? +[unresolved-dep-syntax]: #what-syntax-is-used-to-identify-dependencies-on-the-standard-library-in-cargotoml + +What syntax should be used for the explicit standard library dependencies? +`builtin = true`? `sysroot = true`? `version = "*"`? + +↩ [*Proposal*][proposal] + +## What is the format for builtin dependencies in `Cargo.lock`? +[unresolved-lockfile]: #what-is-the-format-for-builtin-dependencies-in-cargolock + +How should `builtin` deps be represented in lockfiles? Is `builtin = true` +appropriate? Could the `source` field be reused with the string "builtin" or +should it stay only as a URL+scheme? + +↩ [*Proposal*][proposal] + +## What syntax is used to patch dependencies on the standard library in `Cargo.toml`? +[unresolved-patch-syntax]: #what-syntax-is-used-to-patch-dependencies-on-the-standard-library-in-cargotoml + +`[patch.builtin]` is the natural syntax given `builtin` is a new source, but may +be needlessly different to existing packages. + +↩ [*Patches*][patches] + +# Future possibilities +[future-possibilities]: #future-possibilities + +There are many possible follow-ups to Stage 1b: + +## Allow enabling/disabling features with build-std +[future-features]: #allow-enablingdisabling-features-with-build-std + +This would require the library team be comfortable with the features declared on +the standard library being part of the stable interface of the standard library. + +The behaviour of disabling default features has been highlighted as a potential +cause of breaking changes. + +Alternatively, this could be enabled alongside another proposal which would +allow the standard library to define some features as stable and others as +unstable. + +↩ [*Features*][features] + +## Allow `builtin` source replacement +[future-source-replacement]: #allow-builtin-source-replacement + +This involves allowing the user to blanket-override the standard library sources +with a `[source.builtin]` section of the Cargo configuration. + +As [rationale-source-replacement] details it is unclear if users need to do this +or if it's even something the Rust project wishes to support. + +↩ [*Proposal*][proposal] + +## `rustc_dep_of_std` +[future-rustc_dep_of_std]: #rustc_dep_of_std + +With first-class explicit dependencies on the standard library, +`rustc_dep_of_std` is rendered unnecessary and explicit dependencies on the +standard library can always be present in the `Cargo.toml` of the standard +library's dependencies. + +The `core`, `alloc` and `std` dependencies can be patched in the standard +library's workspace to point to the local copy of the crates. This avoids +`crates.io` dependencies needing to add support for `rustc_dep_of_std` before +the standard library can depend on them. + +↩ [*Proposal*][proposal] + +[cargo-docs-renaming]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml +[cargo-json-schema]: https://doc.rust-lang.org/cargo/reference/registry-index.html#json-schema +[embed-rs-source]: https://github.com/embed-rs/stm32f7-discovery/blob/e2bf713263791c028c2a897f2eb1830d7f09eceb/core/src/lib.rs#L7 +[rust-extern-prelude]: https://doc.rust-lang.org/reference/names/preludes.html#extern-prelude + +[cargo-add]: https://doc.rust-lang.org/cargo/commands/cargo-add.html +[cargo-bench]: https://doc.rust-lang.org/cargo/commands/cargo-bench.html +[cargo-build]: https://doc.rust-lang.org/cargo/commands/cargo-build.html +[cargo-check]: https://doc.rust-lang.org/cargo/commands/cargo-check.html +[cargo-clean]: https://doc.rust-lang.org/cargo/commands/cargo-clean.html +[cargo-clippy]: https://doc.rust-lang.org/cargo/commands/cargo-clippy.html +[cargo-doc]: https://doc.rust-lang.org/cargo/commands/cargo-doc.html +[cargo-fetch]: https://doc.rust-lang.org/cargo/commands/cargo-fetch.html +[cargo-fix]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html +[cargo-fmt]: https://doc.rust-lang.org/cargo/commands/cargo-fmt.html +[cargo-generate-lockfile]: https://doc.rust-lang.org/cargo/commands/cargo-generate-lockfile.html +[cargo-help]: https://doc.rust-lang.org/cargo/commands/cargo-help.html +[cargo-info]: https://doc.rust-lang.org/cargo/commands/cargo-info.html +[cargo-init]: https://doc.rust-lang.org/cargo/commands/cargo-init.html +[cargo-install]: https://doc.rust-lang.org/cargo/commands/cargo-install.html +[cargo-locate-project]: https://doc.rust-lang.org/cargo/commands/cargo-locate-project.html +[cargo-login]: https://doc.rust-lang.org/cargo/commands/cargo-login.html +[cargo-logout]: https://doc.rust-lang.org/cargo/commands/cargo-login.html +[cargo-metadata]: https://doc.rust-lang.org/cargo/commands/cargo-metadata.html +[cargo-miri]: https://doc.rust-lang.org/cargo/commands/cargo-miri.html +[cargo-new]: https://doc.rust-lang.org/cargo/commands/cargo-new.html +[cargo-owner]: https://doc.rust-lang.org/cargo/commands/cargo-owner.html +[cargo-package]: https://doc.rust-lang.org/cargo/commands/cargo-package.html +[cargo-pkgid]: https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html +[cargo-publish]: https://doc.rust-lang.org/cargo/commands/cargo-publish.html +[cargo-remove]: https://doc.rust-lang.org/cargo/commands/cargo-remove.html +[cargo-report]: https://doc.rust-lang.org/cargo/commands/cargo-report.html +[cargo-run]: https://doc.rust-lang.org/cargo/commands/cargo-run.html +[cargo-rustc]: https://doc.rust-lang.org/cargo/commands/cargo-rustc.html +[cargo-rustdoc]: https://doc.rust-lang.org/cargo/commands/cargo-rustdoc.html +[cargo-search]: https://doc.rust-lang.org/cargo/commands/cargo-search.html +[cargo-test]: https://doc.rust-lang.org/cargo/commands/cargo-test.html +[cargo-tree]: https://doc.rust-lang.org/cargo/commands/cargo-tree.html +[cargo-uninstall]: https://doc.rust-lang.org/cargo/commands/cargo-uninstall.html +[cargo-update]: https://doc.rust-lang.org/cargo/commands/cargo-update.html +[cargo-vendor]: https://doc.rust-lang.org/cargo/commands/cargo-vendor.html +[cargo-version]: https://doc.rust-lang.org/cargo/commands/cargo-version.html +[cargo-yank]: https://doc.rust-lang.org/cargo/commands/cargo-yank.html \ No newline at end of file diff --git a/text/0000-build-std/6-stage-2.md b/text/0000-build-std/6-stage-2.md new file mode 100644 index 00000000000..0126d2fa62a --- /dev/null +++ b/text/0000-build-std/6-stage-2.md @@ -0,0 +1,157 @@ +# Proposal +[proposal]: #proposal + +The `build-std` option in the Cargo configuration will be extended with a new +value: + +```toml +[build] +build-std = "compatible" # or `always`/`off` +``` + +"compatible" will become the default value for `build-std` ([?][rationale-default]). + +When `build-std` is set to "compatible", then the standard library crates will +be rebuilt automatically ([?][rationale-why-automatic]) when a pre-built +standard library is not present or the pre-built standard library is +incompatible with the rest of the crate (due to use of target modifiers). + +> [!NOTE] +> +> rustc will be extended with the ability to determine whether an existing +> `rlib` artefact is compatible with the flags passed to rustc +> ([?][rationale-rustc-support]). +> +> ```shell-session +> $ rustc -Zreg-struct-return core/lib.rs -o libcore.rlib +> $ rustc --emit compatibility $cargo_flags libcore.rlib +> error: mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `core` +> ``` +> +> In the above example, rustc compiles libcore with the `-Zreg-struct-return` +> target modifier to create an `rlib`, and then is invoked to check the +> compatibility of the flags Cargo would have passed to the crate against those +> used with `libcore.rlib`. In this instance, the `rlib` was compiled with +> `-Zreg-struct-return` and this example assumes that `$cargo_flags` does not +> pass this flag, so rustc reports a mismatch. +> +> Cargo can use this mechanism to determine whether it needs to rebuild the +> standard library to ensure compatibility. + +The standard library will be rebuilt in its release profile and will only vary +in the target modifier flags necessarily for it to be compatible +([?][rationale-release-profile]). This is primarily useful for prospective users +of target modifier flags. + +Pre-built available? | User's profile | Target modifiers changed? | Standard library re-built? +-------------------- | -------------- | ------------------------- | -------------------------- +No | N/A | N/A | Yes, std's `release` +Yes | `dev` | Unchanged | Yes, std's `release` +Yes | `release` | Unchanged | No +Yes | `release` | Changed | Yes, std's `release` + +*It is assumed that changing a target modifier would be part of Cargo profiles, +hence why there is no row for "target modifiers changed, profile unchanged".* + +All of rustc's target modifiers are unstable as they cannot be used without +build-std, so Cargo does not expose any configuration for target modifiers +currently. + +As with the "always" option, the exact crates from the standard library to be +built are determined by the `build-std-crate` option or explicit dependencies on +the standard library if [*Stage 1b*][stage1b] was implemented. + +*See the following sections for rationale/alternatives:* + +- [*Why default to "compatible"?*][rationale-default] +- [*Why rebuild the standard library automatically?*][rationale-why-automatic] +- [*Why add compatibility checks in rustc to support build-std?*][rationale-rustc-support] +- [*Why build in release profile?*][rationale-release-profile] + +*See the following sections for relevant unresolved questions:* + +- [*What should the "compatible" value of `build-std` be named?*][unresolved-compatible] +- [*What should the interface to rustc compatibility checking be?*][unresolved-rustc-compat-interface] + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +This section aims to justify all of the decisions made in the proposed design +from [*Proposal*][proposal] and discuss why alternatives were not chosen. + +## Why default to "compatible"? +[rationale-default]: #why-default-to-compatible + +"compatible" will only trigger when it is necessary to ensure that a user's +current configuration will build successfully. It shouldn't trigger rebuilds for +the user or change the standard library they are using if it isn't strictly +required. + +If the default where not "compatible" then when the user enabled a target +modifier through Cargo (when such options are exposed), the user would +immediately face a compilation error and need to go learn about +`build-std = "compatible"` anyway. + +↩ [*Proposal*][proposal] + +## Why rebuild the standard library automatically? +[rationale-why-automatic]: #why-rebuild-the-standard-library-automatically + +Rebuilds of the standard library happening transparently reduce the requirement +that users learn about build-std as something to enable and configure. Combined +with explicit dependencies on the standard library crates from +[Stage 1b][stage1b] or `build-std-crate` from [Stage 1a][stage1a], build-std can +avoid any cost on users that do not require it (by triggering automatically when +a target modifier is changed, and having no unnecessary rebuilds otherwise). + +↩ [*Proposal*][proposal] + +## Why add compatibility checks in rustc to support build-std? +[rationale-rustc-support]: #why-add-compatibility-checks-in-rustc-to-support-build-std + +Without support from rustc, Cargo would need to assume that the pre-built +standard library's configuration is entirely configured in its Cargo profile and +would need to compare the profile of the standard library with the profile of +the user's crate and know which rustc flags are target modifiers. + +↩ [*Proposal*][proposal] + +## Why build in release profile? +[rationale-release-profile]: #why-build-in-release-profile + +As in +[Stage 1a's *"Why does "always" rebuild in release profile?"*][stage1a-why-release], +building in the release profile minimises the differences between a newly-built +std and pre-built std, keeping the implications of this stage of the proposal +small. + +↩ [*Proposal*][proposal] + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +The following small details are likely to be bikeshed prior to Stage 2 acceptance or +stabilisation and aren't pertinent to the overall design: + +## What should the "compatible" value of `build-std` be named? +[unresolved-compatible]: #what-should-the-compatible-value-of-build-std-be-named + +It could be named "target-modifiers" or "automatic". + +↩ [*Proposal*][proposal] + +## What should the interface to rustc compatibility checking be? +[unresolved-rustc-compat-interface]: #what-should-the-interface-to-rustc-compatibility-checking-be + +Should it an `--emit` flag? a `--print` flag? + +↩ [*Proposal*][proposal] + +# Future possibilities +[future-possibilities]: #future-possibilities + +There are not currently any documented follow-ups to Stage 2. + +[stage1a]: ./4-stage-1a.md#proposal +[stage1a-why-release]: ./4-stage-1a.md#why-does-always-rebuild-in-release-profile +[stage1b]: ./5-stage-1b.md#proposal \ No newline at end of file diff --git a/text/0000-build-std/7-stage-3.md b/text/0000-build-std/7-stage-3.md new file mode 100644 index 00000000000..9056ba3c057 --- /dev/null +++ b/text/0000-build-std/7-stage-3.md @@ -0,0 +1,187 @@ +# Proposal +[proposal]: #proposal + +Cargo will also permit `build-std` to be set as part of the `[profile]` section +([?][rationale-profile]). `build-std` configuration locations precedence is +updated as follows ([?][rationale-profile-precedence]): + +1. `[target.]` +2. `[target.]` +3. `[profile]` +4. `[build]` + +The `build-std` option in the Cargo configuration will be extended with two new +values - "compatible-profile" or "match-profile": + +```toml +[build] +build-std = "match-profile" # or `compatible-profile`/`compatible`/`always`/`off` +``` + +"match-profile" will become the default value for the release profile +([?][rationale-default], [?][rationale-why-not-always-rebuild]). The `bench` +profile inherits this default from `release`. + +Like `build-std = "compatible"`, when set to either "compatible-profile" or +"match-profile", then the standard library crates will be rebuilt +automatically when a pre-built standard library is not present. + +- "compatible-profile" rebuilds the standard library if the user is using a + different profile than the default "release" profile of the pre-built standard + library or a rebuild is necessary to maintain compatibility with the user's + crate ([?][rationale-compatible-profile]). + + Cargo will build the standard library using the same profile as the user, as + defined in the standard library workspace + ([?][rationale-compatible-profile-std]). It will vary only in the target modifiers + necessary to maintain compatibility with the user's crates. + + Pre-built available? | User's profile | Target modifiers changed? | Standard library re-built? + -------------------- | -------------- | ------------------------- | -------------------------- + No | `dev` | N/A | Yes, std's `dev` + No | `release` | N/A | Yes, std's `release` + Yes | `dev` | N/A | Yes, std's `dev` + Yes | `release` | Unchanged | No + Yes | `release` | Changed | Yes, std's `release` + +- "match-profile" rebuilds the standard library using the configuration of the + user's current profile ([?][rationale-match-profile]). Cargo will check + whether the compilation flags it would intend to use for the standard library + match those used with the pre-built standard library by asking rustc. + + Pre-built available? | User's profile | Target modifiers changed? | Standard library re-built? + -------------------- | -------------- | ------------------------- | -------------------------- + No | `dev` | N/A | Yes, user's `dev` + No | `release` | N/A | Yes, user's `release` + Yes | `dev` | N/A | Yes, user's `dev` + Yes | `release` | Unchanged | Yes, user's `release` + Yes | `release` | Changed | Yes, user's `release` + + > [!NOTE] + > + > rustc's compatibility checking from [Stage 2][stage2] will be extended to + > allow checking for any mismatch in relevant compilation flags (e.g. + > excluding things like dependency rlib search paths which will necessarily + > differ). rustc will not be able to serialise the value of each flag into + > rlib metadata due to performance overhead but will be able to serialise and + > compare a hash of these values. + +The above examples apply to any other profile too, such as `bench` or `test`. +These options are primarily useful for users wanting to use the same codegen +flags with the standard library or have a more debuggable standard library. + +As with the "always" option, the exact crates from the standard library to be +built are determined by the `build-std-crate` option or explicit dependencies on +the standard library if [*Stage 1b*][stage1b] was implemented. + +*See the following sections for rationale/alternatives:* + +- [*Why permit `build-std` in `[profile]`?*][rationale-profile] +- [*Why does `[profile]` have higher precedence than `[build]` and lower than `[target]`?*][rationale-profile-precedence] +- [*Why have "match-profile" as the default for the release profile?*][rationale-default] +- [*Why not always default to "match-profile"?*][rationale-why-not-always-rebuild] +- [*Why add "compatible-profile"?*][rationale-compatible-profile] +- [*Why does "compatible-profile" use the standard library's profiles?*][rationale-compatible-profile-std] +- [*Why add "match-profile"?*][rationale-match-profile] + +*See the following sections for relevant unresolved questions:* + +- [*What should the "match-profile" and "compatible-profile" values of `build-std` be named?*][unresolved-naming] + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +This section aims to justify all of the decisions made in the proposed design +from [*Proposal*][proposal] and discuss why alternatives were not chosen. + +## Why permit `build-std` in `[profile]`? +[rationale-profile]: #why-permit-build-std-in-profile + +Configurations like "match-profile" for `build-std` make most sense when +combined with Cargo profiles that aim to maximise the optimisation of the final +binary. It is more likely that users would want to use "match-profile" with the +release profile than by default (as in `[build]`) or for a specific target (as +in `[target]`). + +↩ [*Proposal*][proposal] + +## Why does `[profile]` have higher precedence than `[build]` and lower than `[target]`? +[rationale-profile-precedence]: #why-does-profile-have-higher-precedence-than-build-and-lower-than-target + +`[target]` configuration is more narrowly scoped than `[profile]` which is in +turn more narrowly scoped than the global default in `[build]`. + +↩ [*Proposal*][proposal] + +## Why have "match-profile" as the default for the release profile? +[rationale-default]: #why-have-match-profile-as-the-default-for-the-release-profile + +`build-std = "match-profile"` is intended to be used when additional time +spent building the standard library is not a problem and the quality of the +final artifact is paramount. This corresponds closely with the release profile, +where additional time spent on optimisations (e.g. with `-Ctarget-cpu`) is +acceptable. Always re-building the standard library with the user's profile +configuration in release mode is likely to result in a more optimised build than +with the pre-built standard library and is thus a reasonable default for the +`release` and `bench` profiles. + +↩ [*Proposal*][proposal] + +### Why not always default to "match-profile"? +[rationale-why-not-always-rebuild]: #why-not-always-default-to-match-profile + +Cargo's users don't currently expect that changing any part of their profile +configuration, such as trying a different optimisation level, would trigger a +rebuild of the standard library. For small projects, rebuilding the standard +library could be a significant increase in the overall build time for a project. + +If `build-std = "match-profile"` were the default, the standard library +could be rebuilt quite frequently without much benefit. Especially as the +pre-built standard library is built using the release profile, all debug profile +builds would immediately trigger a rebuild of the standard library. + +↩ [*Proposal*][proposal] + +### Why add "compatible-profile"? +[rationale-compatible-profile]: #why-add-compatible-profile + +"compatible-profile" is useful for when users want a more debuggable standard +library while keeping rebuilds of the standard library to a minimum. + +↩ [*Proposal*][proposal] + +### Why does "compatible-profile" use the standard library's profiles? +[rationale-compatible-profile-std]: #why-does-compatible-profile-use-the-standard-librarys-profiles + +By using the standard library's profile definitions, the library team will be +able to define a "dev" profile that is most useful for the standard library. + +↩ [*Proposal*][proposal] + +### Why add "match-profile"? +[rationale-match-profile]: #why-add-match-profile + +"match-profile" is useful for rebuilding the standard library with the same +codegen flags as the rest of the user's project, such as using `-Ctarget-cpu` to +gain additional optimisations. + +↩ [*Proposal*][proposal] + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +The following small details are likely to be bikeshed prior to Stage 3 acceptance or +stabilisation and aren't pertinent to the overall design: + +## What should the "match-profile" and "compatible-profile" values of `build-std` be named? +[unresolved-naming]: #what-should-the-match-profile-and-compatible-profile-values-of-build-std-be-named + +It could be named something else. + +# Future possibilities +[future-possibilities]: #future-possibilities + +There are not currently any documented follow-ups to Stage 3. + +[stage1b]: ./5-stage-1b.md#proposal +[stage2]: ./6-stage-2.md \ No newline at end of file diff --git a/text/0000-build-std/8-appendix-summary-of-changes.md b/text/0000-build-std/8-appendix-summary-of-changes.md new file mode 100644 index 00000000000..342ea179fe8 --- /dev/null +++ b/text/0000-build-std/8-appendix-summary-of-changes.md @@ -0,0 +1,83 @@ +# Appendix I: Summary of changes +[appendix-i]: #appendix-i-summary-of-changes + +There are many features proposed in this RFC for different parts of the project: + +- Bootstrap/infra/release + - [Vendoring standard library sources into `rust-src`](./4-stage-1a.md#vendored-rust-src) (Stage 1a) + - [`rust-self-contained` components](./4-stage-1a.md#special-object-files) (Stage 1a) + - [Testing build-std in rust-lang/rust CI][constraints-on-the-standard-library] +- Cargo + - [`build-std = "always"`](./4-stage-1a.md) (Stage 1a) + - [Extending Cargo subcommmands](./4-stage-1a.md#cargo-subcommands) + - [Prohibiting custom targets](./4-stage-1a.md#custom-targets) (Stage 1a) + - [Explicit dependencies](./5-stage-1b.md#proposal) (Stage 1b) + - [Lockfile changes](./5-stage-1b.md#proposal) + - [Registry changes](./5-stage-1b.md#registries) + - [Extending Cargo subcommmands](./5-stage-1b.md#cargo-subcommands) + - [`build-std = "compatible"`](./6-stage-2.md#proposal) (Stage 2) + - [`build-std = "compatible-profile"` / `build-std = "match-profile"`](./7-stage-3.md) (Stage 3) +- Compiler + - [Loading `panic_unwind` from `-L dependency=`](./4-stage-1a.md#proposal) (Stage 1a) + - [`--no-implicit-sysroot-deps`](./4-stage-1a.md#preventing-implicit-sysroot-dependencies) (Stage 1a) + - [Assuming `RUSTC_BOOTSTRAP` for sysroot builds](./4-stage-1a.md#building-the-standard-library-on-a-stable-toolchain) (Stage 1a) + - [Forcing many codegen-units for `compiler-builtins`](./4-stage-1a.md#compiler-builtins) (Stage 1a) + - [Checking compatibility of flags and rlibs](./6-stage-2.md#proposal) (Stage 2) +- Project-wide + - [Documenting build-std stability guarantees](./4-stage-1a.md#stability-guarantees) (Stage 1a) +- Standard library + - [Removing `restricted_std`](./4-stage-1a.md#restricted_std) (Stage 1a) + - [Moving configuration into the standard library's profile](./4-stage-1a.md) (Stage 1a) + +## Constraints on the standard library, compiler and bootstrap +[constraints-on-the-standard-library]: #constraints-on-the-standard-library-compiler-and-bootstrap + +A stable mechanism for building the standard library imposes some constraints on +the rest of the toolchain that would need to be upheld: + +- No further customisation of the pre-built standard library through any means + other than the profile in `Cargo.toml` +- No new C dependencies on the standard library +- The standard library continues to exist in its own workspace, with its own + lockfile +- The name of the `test` crate becomes stable (but not its interface) +- The `panic-unwind` and `compiler-builtins-mem` `sysroot` features become + stable so Cargo can refer to them + - This should not necessitate a "stable/unstable features" mechanism, rather a + guarantee from the library team that they're happy for these to stay + +> [!NOTE] +> +> Cargo could be made a [JOSH] subtree of the [rust-lang/rust] so that all +> relevant parts of the toolchain can be updated in tandem when this is +> necessary. + +## Unresolved questions +[unresolved-questions]: #unresolved-questions + +The following are all of the unresolved questions from all stages of the RFC: + +- [*What should the `build-std` configuration in `.cargo/config` be named?*][unresolved-config-name] +- [*What should the "always" and "off" values of `build-std` be named?*][unresolved-config-values] +- [*What should `build-std-crate` be named?*][unresolved-build-std-crate-name] + +## Future possibilities +[future-possibilities]: #future-possibilities + +The following are all of the future possibilities from all stages of the RFC: + +- [*Allow custom targets with build-std*][future-custom-targets] +- [*Avoid building `panic_unwind` unnecessarily*][future-panic_unwind] +- [*Enable local recompilation of special object files/sanitizer runtimes*][future-recompile-special] +- [*Allow choosing the crate type of the standard library?*][future-crate-type] + +[future-crate-type]: ./4-stage-1a.md#allow-choosing-the-crate-type-of-the-standard-library +[future-custom-targets]: ./4-stage-1a.md#allow-custom-targets-with-build-std +[future-panic_unwind]: ./4-stage-1a.md#avoid-building-panic_unwind-unnecessarily +[future-recompile-special]: ./4-stage-1a.md#enable-local-recompilation-of-special-object-filessanitizer-runtimes +[unresolved-build-std-crate-name]: ./4-stage-1a.md#what-should-build-std-crate-be-named +[unresolved-config-name]: ./4-stage-1a.md#what-should-the-build-std-configuration-in-cargoconfig-be-named +[unresolved-config-values]: ./4-stage-1a.md#what-should-the-always-and-off-values-of-build-std-be-named + +[JOSH]: https://josh-project.github.io/josh/intro.html +[rust-lang/rust]: https://github.com/rust-lang/rust \ No newline at end of file diff --git a/text/0000-build-std/4-appendix-literature-review.md b/text/0000-build-std/9-appendix-literature-review.md similarity index 100% rename from text/0000-build-std/4-appendix-literature-review.md rename to text/0000-build-std/9-appendix-literature-review.md From a04b43c39abddba98568532b125e252264bc3210 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 22 Jul 2025 12:18:07 +0000 Subject: [PATCH 14/96] 1b/future: stable features that will not be usable --- text/0000-build-std/5-stage-1b.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index d87c8a69708..fc04d757f41 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -906,6 +906,11 @@ Alternatively, this could be enabled alongside another proposal which would allow the standard library to define some features as stable and others as unstable. +As there are some features that Cargo will set itself when appropriate (e.g. to +enable or disable [panic runtimes][panic-strategies] or +[`compiler-builtins/mem`][compiler-builtins-mem]), Cargo may need to always +prevent some otherwise stable features from being toggled as it controls those. + ↩ [*Features*][features] ## Allow `builtin` source replacement @@ -939,6 +944,9 @@ the standard library can depend on them. [embed-rs-source]: https://github.com/embed-rs/stm32f7-discovery/blob/e2bf713263791c028c2a897f2eb1830d7f09eceb/core/src/lib.rs#L7 [rust-extern-prelude]: https://doc.rust-lang.org/reference/names/preludes.html#extern-prelude +[panic-strategies]: ./4-stage-1a.md#panic-strategies +[compiler-builtins-mem]: ./4-stage-1a.md#compiler-builtinsmem + [cargo-add]: https://doc.rust-lang.org/cargo/commands/cargo-add.html [cargo-bench]: https://doc.rust-lang.org/cargo/commands/cargo-bench.html [cargo-build]: https://doc.rust-lang.org/cargo/commands/cargo-build.html From 8c9797ad5ac2f2879f8fbb9c1f455afe81a55842 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 22 Jul 2025 12:23:47 +0000 Subject: [PATCH 15/96] 1a: document interactions with `no_std` --- text/0000-build-std/4-stage-1a.md | 34 +++++++++++++++++++++++++++++++ text/0000-build-std/5-stage-1b.md | 23 --------------------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 207f3c50137..31f7cfd9be8 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -124,6 +124,18 @@ newly-built, as appropriate). - [*What should the "always" and "off" values of `build-std` be named?*][unresolved-config-values] - [*What should `build-std-crate` be named?*][unresolved-build-std-crate-name] +## Interactions with `#![no_std]` +[interactions-with-no_std]: #interactions-with-no_std + +Behaviour of crates using `#![no_std]` will change even if the standard library +is rebuilt and passed via `--extern` to rustc. Due to `#![no_std]`, rustc will +not automatically attempt to load std, but if the user writes `extern crate std` +then the rebuilt std will be found. + +*See the following sections for rationale/alternatives:* + +- [*Why not replace `#![no_std]` as the source-of-truth for whether a crate depends on `std`?*][rationale-replace-no_std] + ## `restricted_std` [restricted_std]: #restricted_std @@ -643,6 +655,28 @@ which further limits potential use cases to those without `target-modifiers`. ↩ [*Proposal*][proposal] +## Why not replace `#![no_std]` as the source-of-truth for whether a crate depends on `std`? +[rationale-replace-no_std]: #why-not-replace-no_std-as-the-source-of-truth-for-whether-a-crate-depends-on-std + +Crates can currently use the crate attribute `#![no_std]` to indicate a lack of +dependency on `std`. With `Cargo.toml` being used to express a dependency on the +standard library (or lack thereof), it is unintuitive for there to be two +sources-of-truth for this information. + +`#![no_std]` serves two purposes - it stops the compiler from loading `std` from +the sysroot and adding `extern crate std`, and it prevents the user from +depending on anything from `std` accidentally. + +`#![no_std]` could hypothetically be replaced by a lint to prevent use of the +standard library and a change to the compiler so that it loads the `std` +speculatively unless it is used. + +However, while rustc does have some support for speculatively loading crates, it +is not possible to do so and not declare them as a dependency in cross-crate +metadata. + +↩ [*Interactions with `#![no_std]`*][interactions-with-no_std] + ### Why remove `restricted_std`? [rationale-remove-restricted-std]: #why-remove-restricted_std diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index fc04d757f41..79129ea01d0 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -144,7 +144,6 @@ files ([?][rationale-cargo-lock]). *See the following sections for rationale/alternatives:* -- [*Why not replace `#![no_std]` as the source-of-truth for whether a crate depends on `std`?*][rationale-replace-no_std] - [*Why explicitly declare dependencies on the standard library in `Cargo.toml`?*][rationale-why-explicit-deps] - [*Why disallow builtin dependencies to be combined with other sources?*][rationale-builtin-other-sources] - [*Why disallow builtin dependencies on other crates?*][rationale-no-builtin-other-crates] @@ -539,28 +538,6 @@ This stage has no implications for the following Cargo subcommands: This section aims to justify all of the decisions made in the proposed design from [*Proposal*][proposal] and discuss why alternatives were not chosen. -## Why not replace `#![no_std]` as the source-of-truth for whether a crate depends on `std`? -[rationale-replace-no_std]: #why-not-replace-no_std-as-the-source-of-truth-for-whether-a-crate-depends-on-std - -Crates can currently use the crate attribute `#![no_std]` to indicate a lack of -dependency on `std`. With `Cargo.toml` being used to express a dependency on the -standard library (or lack thereof), it is unintuitive for there to be two -sources-of-truth for this information. - -`#![no_std]` serves two purposes - it stops the compiler from loading `std` from -the sysroot and adding `extern crate std`, and it prevents the user from -depending on anything from `std` accidentally. - -`#![no_std]` could hypothetically be replaced by a lint to prevent use of the -standard library and a change to the compiler so that it loads the `std` -speculatively unless it is used. - -However, while rustc does have some support for speculatively loading crates, it -is not possible to do so and not declare them as a dependency in cross-crate -metadata. - -↩ [*Proposal*][proposal] - ## Why explicitly declare dependencies on the standard library in `Cargo.toml`? [rationale-why-explicit-deps]: #why-explicitly-declare-dependencies-on-the-standard-library-in-cargotoml From fc8e473cfa009e7da206c19d5c579e538b3b87cd Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 22 Jul 2025 12:26:57 +0000 Subject: [PATCH 16/96] 1b: mention `cargo add` interactions w/ features --- text/0000-build-std/5-stage-1b.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 79129ea01d0..8e17fe6485f 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -380,6 +380,10 @@ edition = "2024" std = { builtin = true } # <-- this would be added ``` +If attempting to add `core`, `alloc` or `std` with features then this will +succeed but building the crate will require nightly, as described in +[*Features*][features]. + [`cargo info`][cargo-info] will learn how to print information for the built-in `std`, `alloc` and `core` dependencies: From e6d9effba14c4f8c4e2b0e5f491a59743bb98f8d Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 22 Jul 2025 12:36:34 +0000 Subject: [PATCH 17/96] 1a: mention `html_root_url` for generated docs --- text/0000-build-std/4-stage-1a.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 31f7cfd9be8..c523246b7cd 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -365,6 +365,19 @@ or workspace ([?][rationale-caching]). - [*Why not globally cache builds of the standard library?*][rationale-caching] +## Generated documentation +[generated-documentation]: #generated-documentation + +When running `cargo doc` for a project to generate documentation and rebuilding +the standard library, the generated documentation for the user's crates will +link to the locally generated documentation for the `core`, `alloc` and `std` +crates, rather than the upstream hosted generation as is typical for non-locally +built standard libraries. + +*See the following sections for rationale/alternatives:* + +- [*Why not link to hosted standard library documentation in generated docs?*][rationale-generated-docs] + ## Cargo subcommands [cargo-subcommands]: #cargo-subcommands @@ -860,6 +873,16 @@ the standard library. ↩ [*Caching*][caching] +## Why not link to hosted standard library documentation in generated docs? +[rationale-generated-docs]: #why-not-link-to-hosted-standard-library-documentation-in-generated-docs + +Cargo would need to pass `-Zcrate-attr="doc(html_root_url=..)"` to the standard +library crates when building them but doesn't have the required information to +know what url to provide. Cargo would require knowledge of the current toolchain +channel to build the correct url and doesn't know this. + +↩ [*Generated documentation*][generated-documentation] + # Unresolved questions [unresolved-questions]: #unresolved-questions From 31239ce83af01335c811f99a445b0f8a66b015f6 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 28 Jul 2025 04:34:25 +0000 Subject: [PATCH 18/96] 1b: remove trailing spaces --- text/0000-build-std/5-stage-1b.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 8e17fe6485f..6893be3f78a 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -328,10 +328,10 @@ and cannot otherwise be found in the registry. > > The keys `req`, `registry` and `package` from `deps` are not required per the > limitations on builtin dependencies. -> +> > The key is optional and its default value will be the implicit builtin > dependencies: -> +> > ```json > "builtin_deps" : [ > { @@ -679,7 +679,7 @@ circumstance, then they would be located in a `-L dependency=` directory, which rustc would not search when loading a crate from `extern crate`. > [!NOTE] -> +> > `alloc` and `core` must always be passed with `--extern`. ↩ [*Proposal*][proposal] From 879dc0f79779bd93701b65df1186ee7a66b6fc21 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 28 Jul 2025 04:34:59 +0000 Subject: [PATCH 19/96] 1a: clarify use of `libunwind` --- text/0000-build-std/4-stage-1a.md | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index c523246b7cd..79657e82094 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -217,12 +217,6 @@ of standard library dependencies will not need be fetched from crates.io. - [*Why vendor standard library dependencies?*][rationale-vendoring] - [*Why not check if `rust-src` has been modified?*][rationale-src-modifications] -### `libunwind` -[libunwind]: #libunwind - -`libunwind`'s sources are included in the `rust-src` component so that they can -be used as part of the standard library build on targets which require it. - ## Panic strategies [panic-strategies]: #panic-strategies @@ -261,6 +255,15 @@ In line with Cargo's stance on not parsing the `RUSTFLAGS` environment variable, it will not be checked for compilation flags that would require additional crates to be built for compilation to succeed. +> [!NOTE] +> +> The `unwind` crate will continue to link to the system's `libunwind` which +> will need to match the target modifiers used by the standard library to +> guarantee a successful build. Likewise, if `llvm-libunwind`, +> `-Clink-self-contained=yes` or `-Ctarget-feature=+crt-static` are used and the +> distributed `libunwind` is used then it will also need to match the target +> modifiers of the standard library to guarantee a successful build. + *See the following sections for future possibilities:* - [*Avoid building `panic_unwind` unnecessarily*][future-panic_unwind] @@ -277,14 +280,14 @@ invoked ([?][rationale-implied-bootstrap]). Cargo will not need to use - [*Why allow building from the sysroot with implied `RUSTC_BOOTSTRAP`?*][rationale-implied-bootstrap] -## Special object files -[special-object-files]: #special-object-files +## Self-contained objects +[self-contained-objects]: #self-contained-objects A handful of targets require linking against special object files, such as `windows-gnu`, `linux-musl` and `wasi` targets. For example, `linux-musl` targets require `crt1.o`, `crti.o`, `crtn.o`, etc. -Since [rust#76185]/[compiler-team#343], the compiler has a stable +Since [rust#76158]/[compiler-team#343], the compiler has a stable `-Clink-self-contained` flag which will look for special object files in expected locations, typically populated by the `rust-std` components. Its behaviour can be forced by `-Clink-self-contained=true`, but is force-enabled @@ -300,6 +303,9 @@ targets with the same architecture and same CRT but different versions of the CRT, so having target-specific components is most future-proof. These would replace the `self-contained` directory in existing `rust-std` components. +Similarly, for any architectures which require it, LLVM's `libunwind` will be +built and shipped in the `rust-self-contained` component. + As long as these components have been downloaded, as well as any other support components, such as `rust-mingw`, rustc's `-Clink-self-contained` will be able to link against the object files and build-std should never fail on account of @@ -942,7 +948,7 @@ These files are shipped pre-compiled for relevant targets and are not compiled locally. If a user wishes to customise the compilation of these files like the standard library, then there is no mechanism to do so. -↩ [*Special object files*][special-object-files] +↩ [*Self-contained objects*][self-contained-objects] ## Allow choosing the crate type of the standard library? [future-crate-type]: #allow-choosing-the-crate-type-of-the-standard-library @@ -964,8 +970,9 @@ produced by build-std. [compiler-builtins#411]: https://github.com/rust-lang/compiler-builtins/pull/411 [compiler-team#343]: https://github.com/rust-lang/compiler-team/issues/343 -[rust#76185]: https://github.com/rust-lang/rust/pull/76185 +[rust#76158]: https://github.com/rust-lang/rust/pull/76158 [rust#71009]: https://github.com/rust-lang/rust/pull/71009 +[rust#84124]: https://github.com/rust-lang/rust/pull/84124 [rust#135395]: https://github.com/rust-lang/rust/pull/135395 [std-build.rs]: https://github.com/rust-lang/rust/blob/f315e6145802e091ff9fceab6db627a4b4ec2b86/library/std/build.rs#L17 From e38471326f5998308555a8af3ce1fa75694936a6 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 28 Jul 2025 04:26:57 +0000 Subject: [PATCH 20/96] 1a: mention multi-target projects --- text/0000-build-std/4-stage-1a.md | 9 +++++---- text/0000-build-std/6-stage-2.md | 10 ++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 79657e82094..20d6a271a59 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -96,13 +96,14 @@ standard library will determine which crates are built instead. Otherwise, > > The standard library will always be a non-incremental build > ([?][rationale-incremental]), with no `depinfo` produced, and only a `rlib` -> produced (no `dylib`) ([?][rationale-no-dylib]). It will be built into the +> produced (no `dylib`) ([?][rationale-no-dylib]). It will be built in the Cargo > `target` directory of the crate or workspace like any other dependency. The host pre-built standard library will always be used for procedural macros -and build scripts ([?][rationale-sysroot-for-host-deps]). Artifact dependencies -use the same standard library as the rest of the crate (pre-built or -newly-built, as appropriate). +and build scripts ([?][rationale-sysroot-for-host-deps]). Multi-target projects +(resulting from the `target` field in artifact dependencies or the use of +`per-pkg-target` fields) may result in the standard library being built multiple +times - once for each target in the project. *See the following sections for rationale/alternatives:* diff --git a/text/0000-build-std/6-stage-2.md b/text/0000-build-std/6-stage-2.md index 0126d2fa62a..8051a41eb1a 100644 --- a/text/0000-build-std/6-stage-2.md +++ b/text/0000-build-std/6-stage-2.md @@ -61,6 +61,16 @@ As with the "always" option, the exact crates from the standard library to be built are determined by the `build-std-crate` option or explicit dependencies on the standard library if [*Stage 1b*][stage1b] was implemented. +Multi-target projects (resulting from the "target" field in artifact +dependencies or the use of `per-pkg-target` fields) results in the decision to +rebuild the standard library being made multiple times - once for each target in +the project. + +As Cargo does not have per-target profiles nor a way to change the standard +library's profile on a per-target basis, the only way to configure the standard +library differently for different targets is with the use of the `[target]` +sections in the Cargo config. + *See the following sections for rationale/alternatives:* - [*Why default to "compatible"?*][rationale-default] From b7ccf2b29d99bb2d31a3f1adeda1159ae1878be7 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 28 Jul 2025 04:27:50 +0000 Subject: [PATCH 21/96] 1a/2: minor wording tweaks --- text/0000-build-std/4-stage-1a.md | 37 +++++++++++++++++-------------- text/0000-build-std/6-stage-2.md | 2 +- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 20d6a271a59..ecdc618d0b1 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -43,7 +43,7 @@ useful for users of tier three targets. > as is feasible. Alongside `build-std`, a `build-std-crate` key will be introduced -([?][rationale-build-std-crate]), which can be used to specify which crate from +([?][rationale-build-std-crate]), which can be used to specify which crates from the standard library is to be built. Only "core", "alloc" and "std" are valid values for `build-std-crate`. @@ -71,7 +71,7 @@ standard library will determine which crates are built instead. Otherwise, > the dependencies of the `core`, `alloc` or `std` standard library crates > individually (via profile overrides, for example). > -> - The profiles defined by the standard library will be used. +> - The profile defined by the standard library will be used. > > Cargo will resolves the dependencies of opaque dependencies, such as the > standard library, separately in their own workspaces. The "roots" of such a @@ -128,10 +128,10 @@ times - once for each target in the project. ## Interactions with `#![no_std]` [interactions-with-no_std]: #interactions-with-no_std -Behaviour of crates using `#![no_std]` will change even if the standard library -is rebuilt and passed via `--extern` to rustc. Due to `#![no_std]`, rustc will -not automatically attempt to load std, but if the user writes `extern crate std` -then the rebuilt std will be found. +Behaviour of crates using `#![no_std]` will not change whether or not `std` is +rebuilt and passed via `--extern` to rustc, and `#![no_std]` will still be +required in order for `rustc` to not attempt to load `std` and add it to the +extern prelude. *See the following sections for rationale/alternatives:* @@ -365,8 +365,8 @@ enable this manually will be enabled through work on features (see [caching]: #caching Standard library artifacts built by build-std will not be shared between crates -or workspaces, as they only exist in the `target` directory of a specific crate -or workspace ([?][rationale-caching]). +or workspaces, as they only exist in Cargo's target directory for a specific +crate or workspace ([?][rationale-caching]). *See the following sections for rationale/alternatives:* @@ -518,7 +518,7 @@ There are various alternatives to putting `build-std` in the Cargo configuration 2. build-std could be enabled or disabled in the `Cargo.toml`. However, under which conditions the standard library is rebuilt is better determined by the - user of Cargo, rather than the project being built. + user of Cargo, rather than the package being built. A user may want to never rebuild the standard library so as to avoid invalidating the guarantees of their qualified toolchain, or may want to @@ -764,14 +764,17 @@ providing an empty path. ### Why use `noprelude` with `--extern`? [rationale-noprelude-with-extern]: #why-use-noprelude-with---extern -The `noprelude` modifier for `--extern` is necessary for use of the `--extern` -flag to be equivalent to using a modified sysroot. +rustc's existing behaviour of implicitly loading `std` and adding it to the +extern prelude will not be changed as part of this RFC. Adding The `noprelude` +modifier for `--extern` is necessary for use of the `--extern` flag to be +equivalent to loading from a sysroot. Without `noprelude`, rustc implicitly inserts a `extern crate $name` when using `--extern`. As a consequence, if a newly-built `alloc` were passed using -`--extern alloc=alloc.rlib` then `extern crate alloc` would not be required, but -it would be if the pre-built `alloc` could be used. This difference in how a -crate is made available to rustc should not be observable to the user. +`--extern alloc=alloc.rlib` then `extern crate alloc` would not be required to +use the locally-built `alloc`, but it would be to use the pre-built `alloc`. This +difference in how a crate is made available to rustc should not be observable to +the user. ↩ [*Preventing implicit sysroot dependencies*][preventing-implicit-sysroot-dependencies] @@ -849,9 +852,9 @@ stable toolchain would require that it be possible to build `core` without nightly. It is not sufficient for rustc to special-case the `core`, `alloc` and `std` -crate names as when being built as part of the standard library, dependencies of -the standard library also use unstable features and so these crate would also -need such special-casing, which is not practical. +crate names as, when being built as part of the standard library, dependencies +of the standard library also use unstable features and it is not practical to +special-case all of these crates. ↩ [*Building the standard library on a stable toolchain*][building-the-standard-library-on-a-stable-toolchain] diff --git a/text/0000-build-std/6-stage-2.md b/text/0000-build-std/6-stage-2.md index 8051a41eb1a..5ec821ce12b 100644 --- a/text/0000-build-std/6-stage-2.md +++ b/text/0000-build-std/6-stage-2.md @@ -153,7 +153,7 @@ It could be named "target-modifiers" or "automatic". ## What should the interface to rustc compatibility checking be? [unresolved-rustc-compat-interface]: #what-should-the-interface-to-rustc-compatibility-checking-be -Should it an `--emit` flag? a `--print` flag? +Should it be an `--emit` flag? A `--print` flag? ↩ [*Proposal*][proposal] From 0f2d6055b746250a4440df9b68268fa3c153f6a7 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 28 Jul 2025 04:28:40 +0000 Subject: [PATCH 22/96] 1a: `rustc-src` is a default component --- text/0000-build-std/4-stage-1a.md | 5 +++-- text/0000-build-std/8-appendix-summary-of-changes.md | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index ecdc618d0b1..e67d30be71d 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -199,8 +199,9 @@ explicit and implicit standard library dependencies. When it is necessary to build the standard library, Cargo will look for sources in a fixed location in the sysroot ([?][rationale-custom-src-path]): `lib/rustlib/src`. rustup's `rust-src` component downloads standard library -sources to this location. If the sources are not found, Cargo will emit an error -and recommend the user download `rust-src` if using rustup. +sources to this location and will be made a default component. If the sources +are not found, Cargo will emit an error and recommend the user download +`rust-src` if using rustup. `rust-src` will contain the sources for the standard library crates as well as its vendored dependencies ([?][rationale-vendoring]). As a consequence sources diff --git a/text/0000-build-std/8-appendix-summary-of-changes.md b/text/0000-build-std/8-appendix-summary-of-changes.md index 342ea179fe8..6c691f650ab 100644 --- a/text/0000-build-std/8-appendix-summary-of-changes.md +++ b/text/0000-build-std/8-appendix-summary-of-changes.md @@ -5,6 +5,7 @@ There are many features proposed in this RFC for different parts of the project: - Bootstrap/infra/release - [Vendoring standard library sources into `rust-src`](./4-stage-1a.md#vendored-rust-src) (Stage 1a) + - [`rust-src` is a default component](./4-stage-1a.md#vendored-rust-src) (Stage 1a) - [`rust-self-contained` components](./4-stage-1a.md#special-object-files) (Stage 1a) - [Testing build-std in rust-lang/rust CI][constraints-on-the-standard-library] - Cargo From 948b09a60d81e793f6e83776d59a7c8768ac6a9a Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 28 Jul 2025 04:30:40 +0000 Subject: [PATCH 23/96] 1a: clarify built crates --- text/0000-build-std/4-stage-1a.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index e67d30be71d..aa68d8cf15b 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -57,6 +57,9 @@ will not be used unless explicitly set and the crate graph's dependencies on the standard library will determine which crates are built instead. Otherwise, `build-std-crate` will default to "std". +If `std` is to be built and Cargo is building a test using the default test +harness then Cargo will also build the `test` crate. + > [!NOTE] > > Inspired by the concept of [opaque dependencies][Opaque dependencies], the @@ -74,18 +77,17 @@ standard library will determine which crates are built instead. Otherwise, > - The profile defined by the standard library will be used. > > Cargo will resolves the dependencies of opaque dependencies, such as the -> standard library, separately in their own workspaces. The "roots" of such a -> resolve are defined as the unified set of packages that any crate in the -> dependency graph has a explicit dependency on and those which Cargo infers a -> direct dependency on. A dependency on the roots are added to all crates in the -> "parent" resolve. +> standard library, separately in their own workspaces. The root of such a +> resolve will be the crate specified in `build-std-crates`, or, if stage 1b is +> implemented, the unified set of packages that any crate in the dependency has +> a direct dependency on. A dependency on the relevant roots are added to all +> crates in the "parent" resolve. > > Regardless of which standard library crates are being built, Cargo will build > the `sysroot` crate of the standard library workspace. `alloc` and `std` will > be optional dependencies of the `sysroot` crate which will be enabled when the -> user has requested them. The sysroot always depends on the `proc_macro` and -> `test` crates. Panic runtimes are dependencies of `std` and will be enabled -> depending on the features that Cargo passes to `std` (see +> user has requested them. Panic runtimes are dependencies of `std` and will be +> enabled depending on the features that Cargo passes to `std` (see > [*Panic strategies*][panic-strategies]). > > rustc loads panic runtimes in a different way to most dependencies, and @@ -680,9 +682,10 @@ which further limits potential use cases to those without `target-modifiers`. [rationale-replace-no_std]: #why-not-replace-no_std-as-the-source-of-truth-for-whether-a-crate-depends-on-std Crates can currently use the crate attribute `#![no_std]` to indicate a lack of -dependency on `std`. With `Cargo.toml` being used to express a dependency on the -standard library (or lack thereof), it is unintuitive for there to be two -sources-of-truth for this information. +dependency on `std`. With `build-std-crates` or explicit dependencies (as in +[Stage 1b][stage1b]) allowing the user to specify a dependency on the standard +library, it is unintuitive for there to be two sources-of-truth for this +information. `#![no_std]` serves two purposes - it stops the compiler from loading `std` from the sysroot and adding `extern crate std`, and it prevents the user from From 7567120284f629b97e62d19fdcac706d6e4ae2d9 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 28 Jul 2025 04:31:06 +0000 Subject: [PATCH 24/96] 1a: mention `compiler-builtins` profile override --- text/0000-build-std/4-stage-1a.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index aa68d8cf15b..118bde75857 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -323,7 +323,8 @@ missing special object files. [compiler-builtins]: #compiler-builtins `compiler-builtins` is always built with `-Ccodegen-units=10000` to force each -intrinsic into its own object file to avoid symbol clashes with libgcc. +intrinsic into its own object file to avoid symbol clashes with libgcc. This is +currently enforced with a profile override in the standard library's workspace. rustc will automatically use a large number of codegen units for the `compiler-builtins` crate, unless manually specified using the `-Ccodegen-units` From 7c2f707b1dd412273f8520dd21b2845a8c40667f Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 28 Jul 2025 04:31:33 +0000 Subject: [PATCH 25/96] 1a: mention `CFLAGS` w/ `compiler-builtins/c` --- text/0000-build-std/4-stage-1a.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 118bde75857..83ec1e67002 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -363,7 +363,8 @@ It will not be enabled by default because it is possible that the target platform does not have a suitable C compiler available. The user being able to enable this manually will be enabled through work on features (see [*Allow enabling/disabling features with build-std*][future-features] from Stage -1b). +1b). Once the user can enable `compiler-builtins/c`, they will need to manually +configure `CFLAGS` to ensure that the C components will link with Rust code. ## Caching [caching]: #caching From 6878be566e8aafa0a3a4ff73d17e1893af4d330e Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 28 Jul 2025 05:12:48 +0000 Subject: [PATCH 26/96] 1a: clarify needing `libc` for `mem` feature --- text/0000-build-std/4-stage-1a.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 83ec1e67002..3e2ffdd2ccb 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -341,11 +341,11 @@ standard library workspace. The `mem` feature of `compiler_builtins` (and the subsequent `compiler-builtins-mem` feature of `core`, `alloc`, `std` which forward to -`compiler_builtins/mem`) is required by `no_std` crates because `libc` does not -provide these symbols without `std`. +`compiler_builtins/mem`) is required by `no_std` crates as a `std` dependency +will not be providing these symbols through its dependency on `libc`. It is necessary that the `compiler-builtins-mem` feature of `alloc` and/or -`core` be enabled when `std` is not in the crate graph +`core` be enabled when `libc` is not in the crate graph ([?][rationale-no-weak-linkage]). *See the following sections for rationale/alternatives:* From 9d0d546815642c5c9ab41e8e590ba0d0448a4bcd Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 28 Jul 2025 05:13:06 +0000 Subject: [PATCH 27/96] 1a/3: move stability guarantees --- text/0000-build-std/4-stage-1a.md | 27 ------------------------- text/0000-build-std/7-stage-3.md | 33 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 3e2ffdd2ccb..cf27eb84300 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -469,33 +469,6 @@ This stage has no implications for the following Cargo subcommands: - [`cargo version`][cargo-version] - [`cargo yank`][cargo-yank] -## Stability guarantees -[stability-guarantees]: #stability-guarantees - -build-std enables a much greater array of configurations of the standard library -to exist and be produced by stable toolchains than the single configuration that -is distributed today. - -It is not feasible for the Rust project to test every combination of profile -configuration, Cargo feature, target and standard library crate. As such, the -stability of build-std as a mechanism must be separated from the stability -guarantees which apply to configurations of the standard library it enables. - -For example, while a stable build-std mechanism may permit the standard library -to be built for a tier three target, the Rust project continues to make no -commitments or guarantees that the standard library for that target will -function correctly or build at all. - -Cargo and Rust project documentation will clearly document the configurations -which are tested upstream and are guaranteed to work. Any other configurations -are supported on a strictly best-effort basis. The Rust project may later choose -to provide more guarantees for some well-tested configurations (e.g. enabling -sanitisers). - -There are also no guarantees about the exact configuration of the standard -library. Over time, the standard library built by build-std could be changed to -be closer to that of the pre-built standard library. - # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives diff --git a/text/0000-build-std/7-stage-3.md b/text/0000-build-std/7-stage-3.md index 9056ba3c057..6c76be95763 100644 --- a/text/0000-build-std/7-stage-3.md +++ b/text/0000-build-std/7-stage-3.md @@ -88,6 +88,39 @@ the standard library if [*Stage 1b*][stage1b] was implemented. - [*What should the "match-profile" and "compatible-profile" values of `build-std` be named?*][unresolved-naming] +## Stability guarantees +[stability-guarantees]: #stability-guarantees + +build-std enables a much greater array of configurations of the standard library +to exist and be produced by stable toolchains than the single configuration that +is distributed today. + +It is not feasible for the Rust project to test every combination of profile +configuration, Cargo feature, target and standard library crate. As such, the +stability of build-std as a mechanism must be separated from the stability +guarantees which apply to configurations of the standard library it enables. + +For example, while a stable build-std mechanism may permit the standard library +to be built for a tier three target, the Rust project continues to make no +commitments or guarantees that the standard library for that target will +function correctly or build at all. Even on a tier one target, the Rust project +cannot test every possible variation of the standard library that build-std +enables. + +The tier of a target no longer determines whether the availability of the +standard library, but rather the level of support provided for the standard +library on the target. + +Cargo and Rust project documentation will clearly document the configurations +which are tested upstream and are guaranteed to work. Any other configurations +are supported on a strictly best-effort basis. The Rust project may later choose +to provide more guarantees for some well-tested configurations (e.g. enabling +sanitisers). + +There are also no guarantees about the exact configuration of the standard +library. Over time, the standard library built by build-std could be changed to +be closer to that of the pre-built standard library. + # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives From f78429bff907e84735b794c7224485d23bba4d22 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 28 Jul 2025 05:13:18 +0000 Subject: [PATCH 28/96] 1a: mention stubbed standard library --- text/0000-build-std/4-stage-1a.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index cf27eb84300..94560bdcf31 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -690,6 +690,10 @@ Furthermore, when `restricted_std` applies, users must add (conditionally, only for affected targets), and have no mechanism for opting-in on behalf of their dependencies (including first-party crates like `libtest`). +It is still valuable for the standard library to be able to compile on as many +targets as possible using the `unsupported` module in its platform abstraction +layer, but this mechanism does not use `restricted_std`. + ↩ [*`restricted_std`*][restricted_std] ### Why disallow custom targets? From 3315d130b24b79ce134a8149bb062fb5583725ac Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 31 Jul 2025 21:51:35 +0000 Subject: [PATCH 29/96] 1a: remove unused link --- text/0000-build-std/4-stage-1a.md | 1 - 1 file changed, 1 deletion(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 94560bdcf31..77b280d1cf3 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -959,7 +959,6 @@ produced by build-std. [compiler-team#343]: https://github.com/rust-lang/compiler-team/issues/343 [rust#76158]: https://github.com/rust-lang/rust/pull/76158 [rust#71009]: https://github.com/rust-lang/rust/pull/71009 -[rust#84124]: https://github.com/rust-lang/rust/pull/84124 [rust#135395]: https://github.com/rust-lang/rust/pull/135395 [std-build.rs]: https://github.com/rust-lang/rust/blob/f315e6145802e091ff9fceab6db627a4b4ec2b86/library/std/build.rs#L17 From 4a786a3d1183f8821125308535146d61608d5045 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 31 Jul 2025 21:52:07 +0000 Subject: [PATCH 30/96] 1b: fix future possibility list ordering --- text/0000-build-std/5-stage-1b.md | 45 ++++++++++++++++--------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 6893be3f78a..ad6077d54af 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -162,6 +162,7 @@ files ([?][rationale-cargo-lock]). *See the following sections for future possibilities:* - [*Allow `builtin` source replacement*][future-source-replacement] +- [*Remove `rustc_dep_of_std`*][future-rustc_dep_of_std] ## Non-`builtin` standard library dependencies [non-builtin-standard-library-dependencies]: #non-builtin-standard-library-dependencies @@ -874,26 +875,6 @@ be needlessly different to existing packages. There are many possible follow-ups to Stage 1b: -## Allow enabling/disabling features with build-std -[future-features]: #allow-enablingdisabling-features-with-build-std - -This would require the library team be comfortable with the features declared on -the standard library being part of the stable interface of the standard library. - -The behaviour of disabling default features has been highlighted as a potential -cause of breaking changes. - -Alternatively, this could be enabled alongside another proposal which would -allow the standard library to define some features as stable and others as -unstable. - -As there are some features that Cargo will set itself when appropriate (e.g. to -enable or disable [panic runtimes][panic-strategies] or -[`compiler-builtins/mem`][compiler-builtins-mem]), Cargo may need to always -prevent some otherwise stable features from being toggled as it controls those. - -↩ [*Features*][features] - ## Allow `builtin` source replacement [future-source-replacement]: #allow-builtin-source-replacement @@ -905,8 +886,8 @@ or if it's even something the Rust project wishes to support. ↩ [*Proposal*][proposal] -## `rustc_dep_of_std` -[future-rustc_dep_of_std]: #rustc_dep_of_std +## Remove `rustc_dep_of_std` +[future-rustc_dep_of_std]: #remove-rustc_dep_of_std With first-class explicit dependencies on the standard library, `rustc_dep_of_std` is rendered unnecessary and explicit dependencies on the @@ -920,6 +901,26 @@ the standard library can depend on them. ↩ [*Proposal*][proposal] +## Allow enabling/disabling features with build-std +[future-features]: #allow-enablingdisabling-features-with-build-std + +This would require the library team be comfortable with the features declared on +the standard library being part of the stable interface of the standard library. + +The behaviour of disabling default features has been highlighted as a potential +cause of breaking changes. + +Alternatively, this could be enabled alongside another proposal which would +allow the standard library to define some features as stable and others as +unstable. + +As there are some features that Cargo will set itself when appropriate (e.g. to +enable or disable [panic runtimes][panic-strategies] or +[`compiler-builtins/mem`][compiler-builtins-mem]), Cargo may need to always +prevent some otherwise stable features from being toggled as it controls those. + +↩ [*Features*][features] + [cargo-docs-renaming]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml [cargo-json-schema]: https://doc.rust-lang.org/cargo/reference/registry-index.html#json-schema [embed-rs-source]: https://github.com/embed-rs/stm32f7-discovery/blob/e2bf713263791c028c2a897f2eb1830d7f09eceb/core/src/lib.rs#L7 From a98253b9834a4b50fd20f36b02000a0b864ce59e Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 31 Jul 2025 21:57:13 +0000 Subject: [PATCH 31/96] 1a/1b: `no_std` usability solutions --- text/0000-build-std/4-stage-1a.md | 8 +++----- text/0000-build-std/5-stage-1b.md | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 77b280d1cf3..709141f460a 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -668,11 +668,9 @@ depending on anything from `std` accidentally. `#![no_std]` could hypothetically be replaced by a lint to prevent use of the standard library and a change to the compiler so that it loads the `std` -speculatively unless it is used. - -However, while rustc does have some support for speculatively loading crates, it -is not possible to do so and not declare them as a dependency in cross-crate -metadata. +speculatively unless it is used. However, while rustc does have some support for +speculatively loading crates, it is not possible to do so and not declare them +as a dependency in cross-crate metadata. ↩ [*Interactions with `#![no_std]`*][interactions-with-no_std] diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index ad6077d54af..1397eae9a19 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -161,6 +161,7 @@ files ([?][rationale-cargo-lock]). *See the following sections for future possibilities:* +- [*Warn when `no_std` crates accidentally have a dependency on `std`*][future-no_std-warning] - [*Allow `builtin` source replacement*][future-source-replacement] - [*Remove `rustc_dep_of_std`*][future-rustc_dep_of_std] @@ -579,6 +580,11 @@ the standard syntax for this would be necessary, such as a flag (e.g. `-Zbuild-std-features`) or option in Cargo's configuration. This also applies to optional dependencies, public/private features, etc. +Users already use Cargo features to toggle `#![no_std]` in crates which support +building without the standard library. When dependencies on the standard library +are exposed in `Cargo.toml` then they can be made optional and enabled by the +existing Cargo features that crates already have. + ↩ [*Proposal*][proposal] ## Why disallow builtin dependencies to be combined with other sources? @@ -875,6 +881,17 @@ be needlessly different to existing packages. There are many possible follow-ups to Stage 1b: +## Warn when `no_std` crates accidentally have a dependency on `std` +[future-no_std-warning]: #warn-when-no_std-crates-accidentally-have-a-dependency-on-std + +Cargo could emit a warning or lint when a root crate without an explicit +dependency on `std` or `alloc` has a dependency on `std` or `alloc` via a +dependency. When writing a `no_std` crate, then it is desirable to avoid any +unexpected dependency on standard library crates and this would cause the crate +to fail to compile on targets where those crates are not supported. + +↩ [*Proposal*][proposal] + ## Allow `builtin` source replacement [future-source-replacement]: #allow-builtin-source-replacement From 0ec9846034451f20968fcdef595afd86c9d7b324 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 6 Aug 2025 01:53:31 +0000 Subject: [PATCH 32/96] intro: stages have value --- text/0000-build-std/0-introduction.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/text/0000-build-std/0-introduction.md b/text/0000-build-std/0-introduction.md index 5119329b3db..1af436d9a21 100644 --- a/text/0000-build-std/0-introduction.md +++ b/text/0000-build-std/0-introduction.md @@ -13,7 +13,7 @@ Writing style: - Text is wrapped at ~80 characters, except for headings - Use the passive voice - + - Items in bullet point lists shouldn't end with a period - Avoid introducing sections that only include other sections and no written @@ -74,7 +74,7 @@ Git: - Try to keep each individual change to a single commit and describe that change in the commit message - + - This makes it easier to review and catch-up - Keep the first line of commit messages limited to 50 characters and the @@ -168,9 +168,10 @@ could proceed. # Contents [contents]: #contents -This RFC has been split into multiple stages. Each stage is a -self-contained proposal building on the previous, which could be accepted, -implemented and stabilised on its own. +This RFC has been split into multiple stages. Each stage is a self-contained +proposal building on the previous and aim to have value independent of later +stages. As such, stages should be able to be accepted, implemented and +stabilised sequentially. of other stages. As build-std is a complex feature with many interdependent design decisions, it is challenging to draft a proposal that is small enough to have an achievable @@ -180,8 +181,8 @@ this - each stage can have a small and achievable scope, while still allowing a reviewer to skip ahead and get a sense of what is planned and how that builds on what came before. -Later stages are less detailed and complete than the previous stages, intended -to indicate the intended direction that the RFC will take and help provide +Later stages may be less detailed and complete than the previous stages and +serve to to indicate the direction that build-std will take and help provide context for the proposals of earlier stages. 1. [Summary][summary] (you are here) @@ -190,7 +191,7 @@ context for the proposals of earlier stages. the structure of the RFC - [Proposal-wide rationale and alternatives][rationale-and-alternatives] - + 2. [Background](./1-background.md) - Detailed explanations of how relevant and impacted parts of the Rust @@ -228,7 +229,7 @@ context for the proposals of earlier stages. - Enables Cargo to determine which standard library crates are required by the crate graph without `build-std-crates` being set - + - Necessary for future extensions which support public/private standard library dependencies or enabling features of the standard library @@ -270,17 +271,17 @@ context for the proposals of earlier stages. - [Future possibilities](./7-stage-3.md#future-possibilities) 9. [Appendix I: Summary of changes](./8-appendix-summary-of-changes.md) - + - Summary of each of the changes from each stage which would need implemented in the Rust toolchain, grouped by the project team whose purview the change would fall under 10. [Appendix II: Exhaustive literature review](./9-appendix-literature-review.md) - + - More detailed summaries of the relevant issues, discussions, pull requests and proposals that comprise the history of the build-std feature since 2015 - + - [*History*](./2-history.md) aims to summarise this content further and cover everything that should be necessary to understand the proposal From 6fc1500e38741a4c5290986667dc43ff48ca03a4 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 6 Aug 2025 01:54:14 +0000 Subject: [PATCH 33/96] intro: clarify Cargo artifact deps --- text/0000-build-std/0-introduction.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-build-std/0-introduction.md b/text/0000-build-std/0-introduction.md index 1af436d9a21..1d0c2c863ec 100644 --- a/text/0000-build-std/0-introduction.md +++ b/text/0000-build-std/0-introduction.md @@ -316,8 +316,8 @@ 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 artifact dependencies, it may be desirable to build -with a different standard library and if rustup was creating different +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 From 517f6c05f0b363b42336543da5a72392ac15c015 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 6 Aug 2025 02:00:46 +0000 Subject: [PATCH 34/96] 1a: rustc unchanged w/r/t custom targets --- text/0000-build-std/4-stage-1a.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 709141f460a..125f5dfedb3 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -67,13 +67,13 @@ harness then Cargo will also build the `test` crate. > > - The lockfile included in the standard library source will be used when > resolving the standard library's dependencies ([?][rationale-lockfile]). -> +> > - The dependencies of the standard library crates are entirely opaque to the > user. Different semver-compatible versions of these dependencies can > exist in the user's resolve. The user cannot control compilation any of > the dependencies of the `core`, `alloc` or `std` standard library crates > individually (via profile overrides, for example). -> +> > - The profile defined by the standard library will be used. > > Cargo will resolves the dependencies of opaque dependencies, such as the @@ -160,6 +160,11 @@ and will emit an error ([?][rationale-disallow-custom-targets]). > Cargo could detect use of a custom target either by comparing it with the list > of built-in targets that rustc reports knowing about (via `--print target-list`) > or by checking if a file exists at the path matching the provided target name. +> +> This does not require any changes to rustc. If it is invoked to build the +> standard library then it will continue to do so, as is possible today, it is +> only the build-std functionality in Cargo that will not support custom targets +> initially. Custom targets can still be used with build-std on nightly toolchains provided that `-Zunstable-options` is provided to Cargo. From d4976275204ef43246dedc236b3b6cfedec4f105 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 6 Aug 2025 02:02:44 +0000 Subject: [PATCH 35/96] 1a: clarify unwind guarantees --- text/0000-build-std/4-stage-1a.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 125f5dfedb3..c8b7066d923 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -267,11 +267,11 @@ crates to be built for compilation to succeed. > [!NOTE] > > The `unwind` crate will continue to link to the system's `libunwind` which -> will need to match the target modifiers used by the standard library to -> guarantee a successful build. Likewise, if `llvm-libunwind`, -> `-Clink-self-contained=yes` or `-Ctarget-feature=+crt-static` are used and the -> distributed `libunwind` is used then it will also need to match the target -> modifiers of the standard library to guarantee a successful build. +> will need to match the target modifiers used by the standard library to avoid +> incompatibilities. Likewise, if `llvm-libunwind`, `-Clink-self-contained=yes` +> or `-Ctarget-feature=+crt-static` are used and the distributed `libunwind` is +> used then it will also need to match the target modifiers of the standard +> library to avoid incompatibilities. *See the following sections for future possibilities:* From fa57ac1a1c19f699d69d655162d88e72634a9ffc Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 6 Aug 2025 03:12:49 +0000 Subject: [PATCH 36/96] 1a: clarify no dylib --- text/0000-build-std/4-stage-1a.md | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index c8b7066d923..87a253e296f 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -632,16 +632,16 @@ would only add a compilation time overhead. ### Why not produce a `dylib` for the standard library? [rationale-no-dylib]: #why-not-produce-a-dylib-for-the-standard-library -The `std` crate's `Cargo.toml` is configured with -`crate-type = ["rlib", "dylib"]` so it can produce both artifacts. The Rust -project ships both artifacts, with the `dylib` only linked against when -`-Cprefer-dynamic` is enabled. However, the `dylib` is not part of Rust's -stability guarantee so a first-class way of specifying crate types is left to a -future extension. +The standard library supports being built as both a `rlib` and a `dylib` and +both are shipped as part of the `rust-std` component. As it does not contain a +metadata hash, it can be rebuilt unnecessarily when toolchain versions 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`. *See the following sections for future possibilities:* -- [*Allow choosing the crate type of the standard library?*][future-crate-type] +- [*Build both `dylib` and `rlib` variants of the standard library*][future-crate-type] ↩ [*Proposal*][proposal] @@ -940,13 +940,10 @@ standard library, then there is no mechanism to do so. ↩ [*Self-contained objects*][self-contained-objects] -## Allow choosing the crate type of the standard library? -[future-crate-type]: #allow-choosing-the-crate-type-of-the-standard-library +## Build both `dylib` and `rlib` variants of the standard library +[future-crate-type]: #build-both-dylib-and-rlib-variants-of-the-standard-library -The standard library supports being built as both a `rlib` and a `dylib`, but -only `dylib` is not part of the project's stability guarantee so only an `rlib` -is built by build-std. This could be relaxed so that a `rlib` and `dylib` are -produced by build-std. +build-std could build both the `dylib` and `rlib` of the standard library. ↩ [*Why not produce a `dylib` for the standard library?*][rationale-no-dylib] From 7177e96b228610285b8932134de58eb6132ccefb Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 7 Aug 2025 16:23:59 +0100 Subject: [PATCH 37/96] Changed `build-std=off` to "never" --- text/0000-build-std/0-introduction.md | 2 +- text/0000-build-std/4-stage-1a.md | 30 +++++++++---------- text/0000-build-std/6-stage-2.md | 2 +- text/0000-build-std/7-stage-3.md | 2 +- .../8-appendix-summary-of-changes.md | 4 +-- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/text/0000-build-std/0-introduction.md b/text/0000-build-std/0-introduction.md index 1d0c2c863ec..aa2499e923a 100644 --- a/text/0000-build-std/0-introduction.md +++ b/text/0000-build-std/0-introduction.md @@ -210,7 +210,7 @@ context for the proposals of earlier stages. 5. [Stage 1a: build-std=always](./4-stage-1a.md) - - Proposes adding a `build-std = "always|off"` option to the Cargo + - Proposes adding a `build-std = "always|never"` option to the Cargo configuration which will unconditionally re-build the standard library crates listed in the `build-std-crates` option diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 87a253e296f..5c849469693 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -3,11 +3,11 @@ Cargo configuration will contain a new key `build-std` under the `[build]` section ([?][rationale-build-std-in-config]), permitting one of two values - -"off" ([?][rationale-build-std-off]) or "always", defaulting to "off": +"never" ([?][rationale-build-std-never]) or "always", defaulting to "never": ```toml [build] -build-std = "always" # or `off` +build-std = "always" # or `never` ``` `build-std` can also be specified in the `[target.]` and @@ -15,7 +15,7 @@ build-std = "always" # or `off` ```toml [target.aarch64-unknown-illumos] -build-std = "always" # or `off` +build-std = "always" # or `never` ``` The `build-std` configuration locations have the following precedence @@ -110,7 +110,7 @@ times - once for each target in the project. *See the following sections for rationale/alternatives:* - [*Why put `build-std` in the Cargo config?*][rationale-build-std-in-config] -- [*Why accept `off` as a value for `build-std`?*][rationale-build-std-off] +- [*Why accept `never` as a value for `build-std`?*][rationale-build-std-never] - [*Why add `build-std` to the `[target.]` and `[target.]` sections?*][rationale-build-std-target-section] - [*Why does `[target]` take precedence over `[build]` for `build-std`?*][rationale-build-std-precedence] - [*Why does "always" rebuild unconditionally?*][rationale-unconditional] @@ -124,7 +124,7 @@ times - once for each target in the project. *See the following sections for relevant unresolved questions:* - [*What should the `build-std` configuration in `.cargo/config` be named?*][unresolved-config-name] -- [*What should the "always" and "off" values of `build-std` be named?*][unresolved-config-values] +- [*What should the "always" and "never" values of `build-std` be named?*][unresolved-config-values] - [*What should `build-std-crate` be named?*][unresolved-build-std-crate-name] ## Interactions with `#![no_std]` @@ -524,16 +524,16 @@ these concerns. ↩ [*Proposal*][proposal] -## Why accept `off` as a value for `build-std`? -[rationale-build-std-off]: #why-accept-off-as-a-value-for-build-std +## Why accept `never` as a value for `build-std`? +[rationale-build-std-never]: #why-accept-never-as-a-value-for-build-std -While not a default value, the user can specify `off` if they prefer which will -never rebuild the standard library. rustc will still return an error when the -user's target-modifiers do not match the pre-built standard library. +The user can specify `never` (the default value) if they prefer which will never +rebuild the standard library. rustc will still return an error when the user's +target-modifiers do not match the pre-built standard library. -The `off` value is useful particularly for qualified toolchains where rebuilding -the standard library may invalidate the testing that the qualified toolchain has -undergone. +The `never` value is useful particularly for qualified toolchains where +rebuilding the standard library may invalidate the testing that the qualified +toolchain has undergone. ↩ [*Proposal*][proposal] @@ -893,8 +893,8 @@ What should this configuration option be named? `build-std`? ↩ [*Proposal*][proposal] -## What should the "always" and "off" values of `build-std` be named? -[unresolved-config-values]: #what-should-the-always-and-off-values-of-build-std-be-named +## What should the "always" and "never" values of `build-std` be named? +[unresolved-config-values]: #what-should-the-always-and-never-values-of-build-std-be-named What is the most intuitive name for the values of the `build-std` setting? `always`? `manual`? `unconditional`? diff --git a/text/0000-build-std/6-stage-2.md b/text/0000-build-std/6-stage-2.md index 5ec821ce12b..9d72f19a47a 100644 --- a/text/0000-build-std/6-stage-2.md +++ b/text/0000-build-std/6-stage-2.md @@ -6,7 +6,7 @@ value: ```toml [build] -build-std = "compatible" # or `always`/`off` +build-std = "compatible" # or `always`/`never` ``` "compatible" will become the default value for `build-std` ([?][rationale-default]). diff --git a/text/0000-build-std/7-stage-3.md b/text/0000-build-std/7-stage-3.md index 6c76be95763..a34ca097e9e 100644 --- a/text/0000-build-std/7-stage-3.md +++ b/text/0000-build-std/7-stage-3.md @@ -15,7 +15,7 @@ values - "compatible-profile" or "match-profile": ```toml [build] -build-std = "match-profile" # or `compatible-profile`/`compatible`/`always`/`off` +build-std = "match-profile" # or `compatible-profile`/`compatible`/`always`/`never` ``` "match-profile" will become the default value for the release profile diff --git a/text/0000-build-std/8-appendix-summary-of-changes.md b/text/0000-build-std/8-appendix-summary-of-changes.md index 6c691f650ab..89d067c33f0 100644 --- a/text/0000-build-std/8-appendix-summary-of-changes.md +++ b/text/0000-build-std/8-appendix-summary-of-changes.md @@ -59,7 +59,7 @@ the rest of the toolchain that would need to be upheld: The following are all of the unresolved questions from all stages of the RFC: - [*What should the `build-std` configuration in `.cargo/config` be named?*][unresolved-config-name] -- [*What should the "always" and "off" values of `build-std` be named?*][unresolved-config-values] +- [*What should the "always" and "never" values of `build-std` be named?*][unresolved-config-values] - [*What should `build-std-crate` be named?*][unresolved-build-std-crate-name] ## Future possibilities @@ -78,7 +78,7 @@ The following are all of the future possibilities from all stages of the RFC: [future-recompile-special]: ./4-stage-1a.md#enable-local-recompilation-of-special-object-filessanitizer-runtimes [unresolved-build-std-crate-name]: ./4-stage-1a.md#what-should-build-std-crate-be-named [unresolved-config-name]: ./4-stage-1a.md#what-should-the-build-std-configuration-in-cargoconfig-be-named -[unresolved-config-values]: ./4-stage-1a.md#what-should-the-always-and-off-values-of-build-std-be-named +[unresolved-config-values]: ./4-stage-1a.md#what-should-the-always-and-never-values-of-build-std-be-named [JOSH]: https://josh-project.github.io/josh/intro.html [rust-lang/rust]: https://github.com/rust-lang/rust \ No newline at end of file From a0c04391841e587cb3158a01900377bac299d60a Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 7 Aug 2025 16:27:17 +0100 Subject: [PATCH 38/96] Fix broken appendix links --- text/0000-build-std/8-appendix-summary-of-changes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/0000-build-std/8-appendix-summary-of-changes.md b/text/0000-build-std/8-appendix-summary-of-changes.md index 89d067c33f0..0e50eca9ab3 100644 --- a/text/0000-build-std/8-appendix-summary-of-changes.md +++ b/text/0000-build-std/8-appendix-summary-of-changes.md @@ -6,7 +6,7 @@ There are many features proposed in this RFC for different parts of the project: - Bootstrap/infra/release - [Vendoring standard library sources into `rust-src`](./4-stage-1a.md#vendored-rust-src) (Stage 1a) - [`rust-src` is a default component](./4-stage-1a.md#vendored-rust-src) (Stage 1a) - - [`rust-self-contained` components](./4-stage-1a.md#special-object-files) (Stage 1a) + - [`rust-self-contained` components](./4-stage-1a.md##self-contained-objects) (Stage 1a) - [Testing build-std in rust-lang/rust CI][constraints-on-the-standard-library] - Cargo - [`build-std = "always"`](./4-stage-1a.md) (Stage 1a) @@ -25,7 +25,7 @@ There are many features proposed in this RFC for different parts of the project: - [Forcing many codegen-units for `compiler-builtins`](./4-stage-1a.md#compiler-builtins) (Stage 1a) - [Checking compatibility of flags and rlibs](./6-stage-2.md#proposal) (Stage 2) - Project-wide - - [Documenting build-std stability guarantees](./4-stage-1a.md#stability-guarantees) (Stage 1a) + - [Documenting build-std stability guarantees](./7-stage-3.md#stability-guarantees) (Stage 1a) - Standard library - [Removing `restricted_std`](./4-stage-1a.md#restricted_std) (Stage 1a) - [Moving configuration into the standard library's profile](./4-stage-1a.md) (Stage 1a) @@ -72,7 +72,7 @@ The following are all of the future possibilities from all stages of the RFC: - [*Enable local recompilation of special object files/sanitizer runtimes*][future-recompile-special] - [*Allow choosing the crate type of the standard library?*][future-crate-type] -[future-crate-type]: ./4-stage-1a.md#allow-choosing-the-crate-type-of-the-standard-library +[future-crate-type]: ./4-stage-1a.md#build-both-dylib-and-rlib-variants-of-the-standard-library [future-custom-targets]: ./4-stage-1a.md#allow-custom-targets-with-build-std [future-panic_unwind]: ./4-stage-1a.md#avoid-building-panic_unwind-unnecessarily [future-recompile-special]: ./4-stage-1a.md#enable-local-recompilation-of-special-object-filessanitizer-runtimes From 1fea59a7cd3b675aa36e0fdcc860ac5f92f521a8 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 7 Aug 2025 16:56:49 +0100 Subject: [PATCH 39/96] Move compiler-builtins-c discussion to future possibilities --- text/0000-build-std/4-stage-1a.md | 20 ++++---------------- text/0000-build-std/5-stage-1b.md | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 5c849469693..bb902b2116c 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -341,6 +341,9 @@ standard library workspace. > > [rust#135395] could be resurrected to implement this. +See [*Allow local builds of `compiler-rt` intrinsics*][future-compiler-builtins-c] +for discussion of the `compiler-builtins-c` feature. + ### `compiler-builtins/mem` [compiler-builtins-mem]: #compiler-builtinsmem @@ -357,20 +360,6 @@ It is necessary that the `compiler-builtins-mem` feature of `alloc` and/or - [*Why not use weak linkage for `compiler-builtins/mem` symbols?*][rationale-no-weak-linkage] -### `compiler-builtins/c` -[compiler-builtins-c]: #compiler-builtinsc - -The [`c` feature][background-dependencies] of `compiler_builtins` (which is also -exposed by `core`, `alloc` and `std` through `compiler-builtins-c`) causes its -`build.rs` file to build and link in more optimised C versions of intrinsics. - -It will not be enabled by default because it is possible that the target -platform does not have a suitable C compiler available. The user being able to -enable this manually will be enabled through work on features (see -[*Allow enabling/disabling features with build-std*][future-features] from Stage -1b). Once the user can enable `compiler-builtins/c`, they will need to manually -configure `CFLAGS` to ensure that the C components will link with Rust code. - ## Caching [caching]: #caching @@ -947,8 +936,7 @@ build-std could build both the `dylib` and `rlib` of the standard library. ↩ [*Why not produce a `dylib` for the standard library?*][rationale-no-dylib] -[background-dependencies]: ./1-background.md#dependencies -[future-features]: ./5-stage-1b.md#allow-enablingdisabling-features-with-build-std +[future-compiler-builtins-c]: ./5-stage-1b.md#allow-local-builds-of-compiler-rt-intrinsics [stage1b]: ./5-stage-1b.md [stage2]: ./6-stage-2.md [stage3]: ./7-stage-3.md diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 1397eae9a19..c88781b4c91 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -938,6 +938,21 @@ prevent some otherwise stable features from being toggled as it controls those. ↩ [*Features*][features] +## Allow local builds of `compiler-rt` intrinsics +[future-compiler-builtins-c]: #allow-local-builds-of-compiler-rt-intrinsics + +The [`c` feature][background-dependencies] of `compiler_builtins` (which is also +exposed by `core`, `alloc` and `std` through `compiler-builtins-c`) causes its +`build.rs` file to build and link in more optimised C versions of intrinsics. + +It will not be enabled by default because it is possible that the target +platform does not have a suitable C compiler available. The user being able to +enable this manually will be enabled through work on features (see +[*Allow enabling/disabling features with build-std*][future-features]). Once the +user can enable `compiler-builtins/c`, they will need to manually configure +`CFLAGS` to ensure that the C components will link with Rust code. + +[background-dependencies]: ./1-background.md#dependencies [cargo-docs-renaming]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml [cargo-json-schema]: https://doc.rust-lang.org/cargo/reference/registry-index.html#json-schema [embed-rs-source]: https://github.com/embed-rs/stm32f7-discovery/blob/e2bf713263791c028c2a897f2eb1830d7f09eceb/core/src/lib.rs#L7 From ff37ab8779deea23f10c5dd3b458cc9976cab568 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 7 Aug 2025 17:09:27 +0100 Subject: [PATCH 40/96] Clarify similarities to other immutable sources --- text/0000-build-std/4-stage-1a.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index bb902b2116c..68bec562fea 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -613,8 +613,10 @@ See ### Why not build the standard library in incremental? [rationale-incremental]: #why-not-build-the-standard-library-in-incremental -As the standard library sources are never modified, incremental compilation -would only add a compilation time overhead. +The standard library sources are not intended to be modified locally, similarly +to those Cargo fetches from `registry` or `git` sources. Incremental compilation +would only add a compilation time overhead for any package sources which do not +change. ↩ [*Proposal*][proposal] @@ -804,7 +806,8 @@ See ### Why not check if `rust-src` has been modified? [rationale-src-modifications]: #why-not-check-if-rust-src-has-been-modified -It is likely that any protections implemented to check that the sources in +This is in line with other immutable dependency sources (like registry or git). +It is also likely that any protections implemented to check that the sources in `rust-src` have not been modified could be trivially bypassed. Any crate that depends on `rust-src` having been modified would not be usable From b3fbeae30288f2200abf34cc15dab541aefcc251 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 11 Aug 2025 11:11:16 +0100 Subject: [PATCH 41/96] Expand rationale for prebuilt stdlib for build scripts/proc_macros --- text/0000-build-std/4-stage-1a.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 68bec562fea..3a02fec6099 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -639,13 +639,17 @@ conservative and not include the `dylib`. ## Why use the pre-built standard library for procedural macros and build-scripts? [rationale-sysroot-for-host-deps]: #why-use-the-pre-built-standard-library-for-procedural-macros-and-build-scripts -Procedural macros and build scripts always run on the host and need to be built -with a configuration that are compatible with the host toolchain's Cargo and -rustc. There is little advantage to using a custom standard library with -procedural macros or build scripts, as they are not part of the final output -artifact and anywhere they can run already have a toolchain with host tools and -a pre-built standard library. Procedural macros must link against the compiler -which further limits potential use cases to those without `target-modifiers`. +Procedural macros always run on the host and need to be built with a +configuration that are compatible with the host toolchain's rustc as they need +to be linked against it. Similarly, build scripts do not inherit `RUSTFLAGS` +from the environment so the standard library they link against must be built +with a configuration compatible with the target's default. + +There is little advantage to using a custom standard library with procedural +macros or build scripts as they are not part of the final output artifact and +anywhere they can run already have a toolchain with host tools and a pre-built +standard library. The fact that any configuration cannot change +`target-modifiers` further limits any potential uses. ↩ [*Proposal*][proposal] From 5aaad19e565fedff1423a9fc17fb854a2d3ead39 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 11 Aug 2025 11:11:58 +0100 Subject: [PATCH 42/96] Link to global caching issue --- text/0000-build-std/4-stage-1a.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 3a02fec6099..0380a6b95c9 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -859,9 +859,9 @@ has precedence over shared libraries and the symbols of a dynamically-linked The standard library is no different than regular dependencies in being able to benefit from global caching of dependency builds. A generic proposal for global -dependency caching could support the standard library. It is out-of-scope of -this proposal to propose a special-cased mechanism for this that applies only to -the standard library. +dependency caching is being worked on as part of [cargo#5931] and could support +the standard library. It is out-of-scope of this proposal to propose a +special-cased mechanism for this that applies only to the standard library. ↩ [*Caching*][caching] @@ -950,6 +950,7 @@ build-std could build both the `dylib` and `rlib` of the standard library. [Opaque dependencies]: https://hackmd.io/@epage/ByGfPtRell +[cargo#5931]: https://github.com/rust-lang/cargo/issues/5931 [compiler-builtins#411]: https://github.com/rust-lang/compiler-builtins/pull/411 [compiler-team#343]: https://github.com/rust-lang/compiler-team/issues/343 [rust#76158]: https://github.com/rust-lang/rust/pull/76158 From 8f4f17759410a4ece2dcaa997d46ed94ceaf2c17 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 11 Aug 2025 11:21:38 +0100 Subject: [PATCH 43/96] Reword unconditional rationale --- text/0000-build-std/4-stage-1a.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 0380a6b95c9..a35fdf44592 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -544,13 +544,13 @@ for it to override a global default in `[build]`. ↩ [*Proposal*][proposal] -## Why does "always" rebuild unconditionally? -[rationale-unconditional]: #why-does-always-rebuild-unconditionally +## Why have a manual "always" option instead of a "when-needed" mode? +[rationale-unconditional]: #why-have-a-manual-always-option-instead-of-a-when-needed-mode -Rebuilding unconditionally avoids the complexity associated with an automatic -build-std mechanism while still being useful for users of tier three targets. By -leaving an automatic mechanism for a later stage, fewer of the technical -challenges of build-std need to be addressed all at once. +Always using a locally-built standard library avoids the complexity associated +with an automatic build-std mechanism while still being useful for users of tier +three targets. By leaving an automatic mechanism for a later stage, fewer of the +technical challenges of build-std need to be addressed all at once. Having an opt-in mechanism initially, such as `build-std = "always"`, allows for early issues with build-std to be ironed out without potentially affecting more From c06dbb584037cd900b52e5ee57ea78b888bcfd54 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 11 Aug 2025 14:10:49 +0100 Subject: [PATCH 44/96] Clarify RUSTFLAGS --- text/0000-build-std/4-stage-1a.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index a35fdf44592..fc2fc6f50dd 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -32,7 +32,8 @@ the dependencies of the current crate. When `build-std` is set to "always", then the standard library will be unconditionally recompiled ([?][rationale-unconditional]) in its release profile as part of every clean build ([?][rationale-release-profile]). This is primarily -useful for users of tier three targets. +useful for users of tier three targets. Like with other dependencies the build +will inherit variables like `RUSTFLAGS` from the environment. > [!NOTE] > From 19bf02aa2d2e6ff4a1d247836bb23834eeef33b5 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 11 Aug 2025 15:00:39 +0100 Subject: [PATCH 45/96] Clarify that any proposals for nightly require an unstable feature --- text/0000-build-std/4-stage-1a.md | 2 +- text/0000-build-std/5-stage-1b.md | 35 +++++++++++++++---------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index fc2fc6f50dd..b8e8f435a70 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -825,7 +825,7 @@ included. [rationale-implied-bootstrap]: #why-allow-building-from-the-sysroot-with-implied-rustc_bootstrap Cargo needs to be able to build the standard library crates, which inherently -require a nightly toolchain. It could set `RUSTC_BOOTSTRAP` internally to do +require unstable features. It could set `RUSTC_BOOTSTRAP` internally to do this with a stable toolchain, however this is a shared requirement with other build systems that wish to build an unmodified standard library and want to work on stable toolchains. diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index c88781b4c91..2b37028ffb7 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -20,8 +20,8 @@ dependencies. `builtin` can only be set to `true` and cannot be combined with any other dependency source for a given dependency ([?][rationale-builtin-other-sources]). `builtin` can only be used with crates named `core`, `alloc` or `std` ([?][rationale-no-builtin-other-crates]) on -stable, but can be with any crate name on nightly -([?][rationale-nightly-builtin-crates]). +stable. Use with any crate name is gated on a perma-unstable `cargo-feature` +([?][rationale-unstable-builtin-crates]). Crates without an explicit dependency on the standard library now have a implicit dependency ([?][rationale-no-migration]) on `std`. In the `hello_world` @@ -147,7 +147,7 @@ files ([?][rationale-cargo-lock]). - [*Why explicitly declare dependencies on the standard library in `Cargo.toml`?*][rationale-why-explicit-deps] - [*Why disallow builtin dependencies to be combined with other sources?*][rationale-builtin-other-sources] - [*Why disallow builtin dependencies on other crates?*][rationale-no-builtin-other-crates] -- [*Why allow all names for `builtin` crates on nightly?*][rationale-nightly-builtin-crates] +- [*Why unstably allow all names for `builtin` crates?*][rationale-unstable-builtin-crates] - [*Why not migrate to always requiring explicit standard library dependencies?*][rationale-no-migration] - [*Why must `std`, `alloc` and `core` always be considered direct dependencies?*][rationale-direct-deps] - [*Why disallow renaming standard library dependencies?*][rationale-package-key] @@ -201,7 +201,7 @@ crates.io. ## Patches [patches]: #patches -On nightly toolchains, it is permitted to patch the standard library +Under a perma-unstable fetaure it is permitted to patch the standard library dependencies with `path` and `git` sources (or any other source) ([?][rationale-patching]): @@ -226,7 +226,7 @@ As with dependencies, crates with `path`/`git` patches for `core`, `alloc` or *See the following sections for rationale/alternatives:* -- [*Why permit patching of the standard library dependencies on nightly?*][rationale-patching] +- [*Why unstably permit patching of the standard library dependencies?*][rationale-patching] *See the following sections for relevant unresolved questions:* @@ -253,7 +253,7 @@ std = { builtin = true, default-features = false } # not permitted *See the following sections for rationale/alternatives:* -- [*Why limit enabling standard library features to nightly?*][rationale-features] +- [*Why limit enabling standard library features to an unstable feature?*][rationale-features] *See the following sections for future possibilities:* @@ -383,7 +383,7 @@ std = { builtin = true } # <-- this would be added ``` If attempting to add `core`, `alloc` or `std` with features then this will -succeed but building the crate will require nightly, as described in +fail unless the required `cargo-feature` is enabled as described in [*Features*][features]. [`cargo info`][cargo-info] will learn how to print information for the built-in @@ -626,8 +626,8 @@ added manually by users, however: ↩ [*Proposal*][proposal] -## Why allow all names for `builtin` crates on nightly? -[rationale-nightly-builtin-crates]: #why-allow-all-names-for-builtin-crates-on-nightly +## Why unstably allow all names for `builtin` crates? +[rationale-unstable-builtin-crates]: #why-unstably-allow-all-names-for-builtin-crates For any crate shipped with the standard library in the sysroot, the user can already write an `extern crate` declaration to use it. All crates other than @@ -640,9 +640,8 @@ For example, some users write benchmarks using `libtest` and have written There may be other niche uses of unstable sysroot crates that this enables to continue on nightly toolchains. -All names are permitted for `builtin` crates rather than an allowlist to avoid -Cargo needing to hardcode the names of many of the crates in the sysroot, which -are inherently unstable. +An allowlist of `builtin` crate names isn't used here to avoid Cargo needing to +hardcode the names of many crates in the sysroot which are inherently unstable. ↩ [*Proposal*][proposal] @@ -727,20 +726,20 @@ resolution to fill in missing `builtin` packages. ↩ [*Proposal*][proposal] -## Why permit patching of the standard library dependencies on nightly? -[rationale-patching]: #why-permit-patching-of-the-standard-library-dependencies-on-nightly +## Why unstably permit patching of the standard library dependencies? +[rationale-patching]: #why-unstably-permit-patching-of-the-standard-library-dependencies Being able to patch `builtin = true` dependencies and replace their source with a `path` dependency is required to be able to replace `rustc_dep_of_std`. As crates which use these sources cannot be published to crates.io, this would not enable a usable general-purpose mechanism for crates to modify the standard -library sources. This capability is restricted to nightly as that is all that is -required for it to be used in replacing `rustc_dep_of_std`. +library sources. This capability is restricted to nightly toolchains as that is +all that is required for it to be used in replacing `rustc_dep_of_std`. ↩ [*Patches*][patches] -## Why limit enabling standard library features to nightly? -[rationale-features]: #why-limit-enabling-standard-library-features-to-nightly +## Why limit enabling standard library features to an unstable feature? +[rationale-features]: #why-limit-enabling-standard-library-features-to-an-unstable-feature If it were possible to enable features of the standard library crates on stable then all of the standard library's current features would immediately be held to From b87cf3e61b2542341f6f01bc11a65cdc7483fd52 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 11 Aug 2025 15:02:55 +0100 Subject: [PATCH 46/96] Clarify the release profile used --- text/0000-build-std/4-stage-1a.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index b8e8f435a70..3593b629022 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -30,10 +30,11 @@ As the Cargo configuration is local to the current installation of Cargo the dependencies of the current crate. When `build-std` is set to "always", then the standard library will be -unconditionally recompiled ([?][rationale-unconditional]) in its release profile -as part of every clean build ([?][rationale-release-profile]). This is primarily -useful for users of tier three targets. Like with other dependencies the build -will inherit variables like `RUSTFLAGS` from the environment. +unconditionally recompiled ([?][rationale-unconditional]) in the release profile +defined in its workspace as part of every clean build +([?][rationale-release-profile]). This is primarily useful for users of tier +three targets. Like with other dependencies the build will inherit variables +like `RUSTFLAGS` from the environment. > [!NOTE] > From afdb3758954dacdcc065a8d98e823296f5bdf871 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 11 Aug 2025 15:16:49 +0100 Subject: [PATCH 47/96] Removed a redundant rationale around build-dependencies --- text/0000-build-std/5-stage-1b.md | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 2b37028ffb7..47a10deab15 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -296,12 +296,13 @@ std = { builtin = true, public = true } ## `dev-dependencies` and `build-dependencies` [dev-dependencies-and-build-dependencies]: #dev-dependencies-and-build-dependencies -Explicit dependencies on the standard library are not supported in -`build-dependencies` ([?][rationale-no-deps-in-build-deps]). - Implicit and explicit dependencies on the standard library are supported for `dev-dependencies` in the same way as regular `dependencies`. +Build scripts and proc macros continue to use the prebuilt standard library as +in stage 1a, and so explicit dependencies on the standard library are not +supported in `build-dependencies`. + ## Registries [registries]: #registries @@ -771,17 +772,6 @@ everything else). ↩ [*Public and private dependencies*][public-and-private-dependencies] -## Why not support explicit standard library dependencies in `build-dependencies`? -[rationale-no-deps-in-build-deps]: #why-not-support-explicit-standard-library-dependencies-in-build-dependencies - -`build-dependencies` only apply to build scripts which are run on the host -toolchain. There is little advantage to using a custom standard library with -build scripts as they are not part of the final output artifact and anywhere -they can run already has a toolchain with host tools and a pre-built standard -library. - -↩ [*`dev-dependencies` and `build-dependencies`*][dev-dependencies-and-build-dependencies] - ## Why add standard library crates to Cargo's index? [rationale-cargo-index]: #why-add-standard-library-crates-to-cargos-index From 58884ea60f4f725f0bf8254bc8a01c438660682a Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 11 Aug 2025 15:29:51 +0100 Subject: [PATCH 48/96] Removed implied direct dependencies --- text/0000-build-std/5-stage-1b.md | 53 +++---------------------------- 1 file changed, 4 insertions(+), 49 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 47a10deab15..284076adc96 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -24,8 +24,8 @@ stable. Use with any crate name is gated on a perma-unstable `cargo-feature` ([?][rationale-unstable-builtin-crates]). Crates without an explicit dependency on the standard library now have a -implicit dependency ([?][rationale-no-migration]) on `std`. In the `hello_world` -crate below, there are no explicit `builtin` dependencies.. +implicit dependency ([?][rationale-no-migration]) on `std`, `alloc` and `core`. +In the `hello_world` crate below, there are no explicit `builtin` dependencies.. ```toml [package] @@ -36,34 +36,7 @@ edition = "2024" [dependencies] ``` -..which is equivalent to the following explicit dependency: - -```toml -[package] -name = "hello_world" -version = "0.1.0" -edition = "2024" - -[dependencies] -std = { builtin = true } -``` - -A dependency on `std` implies a direct dependency on `alloc` and `core`, and -likewise a dependency on `alloc` implies a direct dependency on `core` -([?][rationale-direct-deps]). Therefore, the following explicit dependency on -`std`: - -```toml -[package] -name = "hello_world" -version = "0.1.0" -edition = "2024" - -[dependencies] -std = { builtin = true } -``` - -..is equivalent to: +..which is equivalent to the following explicit dependencies: ```toml [package] @@ -78,7 +51,7 @@ core = { builtin = true } ``` Any explicit `builtin` dependency present in the manifest will disable the -implicit dependency on `std`. +implicit dependencies. When a `std` dependency is present an additional implicit dependency on the `test` crate is added for crates that are being tested with the default test @@ -149,7 +122,6 @@ files ([?][rationale-cargo-lock]). - [*Why disallow builtin dependencies on other crates?*][rationale-no-builtin-other-crates] - [*Why unstably allow all names for `builtin` crates?*][rationale-unstable-builtin-crates] - [*Why not migrate to always requiring explicit standard library dependencies?*][rationale-no-migration] -- [*Why must `std`, `alloc` and `core` always be considered direct dependencies?*][rationale-direct-deps] - [*Why disallow renaming standard library dependencies?*][rationale-package-key] - [*Why disallow source replacement on `builtin` packages?*][rationale-source-replacement] - [*Why add standard library dependencies to Cargo.lock?*][rationale-cargo-lock] @@ -674,23 +646,6 @@ issue and is true of any RFC adding to what can be written in `Cargo.toml`. ↩ [*Proposal*][proposal] -## Why must `std`, `alloc` and `core` always be considered direct dependencies? -[rationale-direct-deps]: #why-must-std-alloc-and-core-always-be-considered-direct-dependencies - -When a crate depends on `std`, the user can also write `extern crate alloc` or -`extern crate core` - this is equivalent to having a direct dependency on these -crates which is not added to the extern prelude. - -If `alloc` and `core` were considered indirect dependencies in this -circumstance, then they would be located in a `-L dependency=` directory, which -rustc would not search when loading a crate from `extern crate`. - -> [!NOTE] -> -> `alloc` and `core` must always be passed with `--extern`. - -↩ [*Proposal*][proposal] - ## Why disallow renaming standard library dependencies? [rationale-package-key]: #why-disallow-renaming-standard-library-dependencies From 9355da7e244ef8623c088d5fb9d31e5c5f2caa7c Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 11 Aug 2025 16:06:31 +0100 Subject: [PATCH 49/96] Clarified no-migration rationale and emphasised the increase in boilerplate --- text/0000-build-std/5-stage-1b.md | 44 ++++++++++++++++++------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 284076adc96..3c52950fd3c 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -621,28 +621,32 @@ hardcode the names of many crates in the sysroot which are inherently unstable. ## Why not migrate to always requiring explicit standard library dependencies? [rationale-no-migration]: #why-not-migrate-to-always-requiring-explicit-standard-library-dependencies -Explicit standard library dependencies with `builtin = true` will necessarily -only be understood by newer versions of Cargo. - -If all packages were required to add explicit dependencies (perhaps over an -edition or through some other mechanism), then every crate would require the -newest version of Cargo to be understood, effectively raising the MSRV of every -Rust crate. +Requiring explicit `builtin` dependencies would, for one, increase the +boilerplate required for users of Cargo and make the minimal `Cargo.toml` file +larger. -If only `no_std` crates (or crates with a `std` feature) add explicit -dependencies on `core` or `alloc` then a much smaller percentage of the crates -ecosystem will require the newest Cargo versions for their new explicit standard -library dependencies to be understood. +Explicit standard library dependencies with `builtin = true` will necessarily +only be understood by newer versions of Cargo. If there were no implicit +dependencies then adding `builtin` dependencies to a crate would mean that Cargo +has to make a decision on builtins for every crate in the dependency graph. This +either means that every crate in a project would also require explicit `builtin` +dependencies in order for Cargo to resolve them, putting a lot of pressure on +every Rust crate to raise their MSRV. + +This proposal puts less pressure on the ecosystem to upgrade - `no_std` crates +(or crates with a `std` feature) will benefit from adding explicit dependencies +to allow them to be easily used on `no_std` targets but users can still work +around any legacy crates in the graph with [`build-std-crates`][stage1a]. Alternative syntaxes, such as requiring `version = "*"` for explicit standard -library dependencies, could be worthwhile to maintain a greater level of -compatibility with older toolchain versions. Any currently accepted syntax would -necessarily be interpreted differently by the build-std-supporting versions of -Cargo, so this approach has its own complications. For example, while -`version = "*"` would be understood by older versions of Cargo, it would attempt -to find the standard library crates on crates.io and fail unless empty crates -were published named `core`, `alloc` and `std`. This is not a build-std specific -issue and is true of any RFC adding to what can be written in `Cargo.toml`. +library dependencies, were considered to maintain a greater level of +compatibility with older toolchain versions. However, any older version of Cargo +would try to look for a specified dependency somewhere - if this lookup failed +then the resolve would fail, and if it succeeded (by perhaps finding an empty +`std` crate on crates.io) then these would override the prebuilt std when passed +to rustc via `--extern`. It is not possible to direct any older version of Cargo +to ignore a dependency. This is not a build-std specific issue and is true of +any RFC adding to what can be written in `Cargo.toml`. ↩ [*Proposal*][proposal] @@ -896,6 +900,8 @@ enable this manually will be enabled through work on features (see user can enable `compiler-builtins/c`, they will need to manually configure `CFLAGS` to ensure that the C components will link with Rust code. +[stage1a]: ./4-stage-1a.md + [background-dependencies]: ./1-background.md#dependencies [cargo-docs-renaming]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml [cargo-json-schema]: https://doc.rust-lang.org/cargo/reference/registry-index.html#json-schema From 97fa089e96373d0de0a31701adb4dd6f99fb2600 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 11 Aug 2025 16:47:25 +0100 Subject: [PATCH 50/96] Clarified dev-dependencies --- text/0000-build-std/5-stage-1b.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 3c52950fd3c..8c0c18c1381 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -269,7 +269,8 @@ std = { builtin = true, public = true } [dev-dependencies-and-build-dependencies]: #dev-dependencies-and-build-dependencies Implicit and explicit dependencies on the standard library are supported for -`dev-dependencies` in the same way as regular `dependencies`. +`dev-dependencies` in the same way as regular `dependencies`. Any `builtin` +dependencies specified are also available as `dev-dependencies` as usual. Build scripts and proc macros continue to use the prebuilt standard library as in stage 1a, and so explicit dependencies on the standard library are not From 0678fb52f6c5c4453a62a4437abbbca2936a542e Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 11 Aug 2025 16:48:30 +0100 Subject: [PATCH 51/96] Formatting fix --- text/0000-build-std/5-stage-1b.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 8c0c18c1381..07d5f9b665f 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -296,11 +296,12 @@ and cannot otherwise be found in the registry. > of the current package) ([?][rationale-cargo-index-shadowing]) > > - `features`: -> - An array of strings containing enabled features in order to support changing -> the standard library features on nightly. Optional, empty by default. +> - An array of strings containing enabled features in order to support +> changing the standard library features on nightly. Optional, empty by +> default. > > - `optional`, `default_features`, `target`, `kind`: -> - These keys have the same definition as in the `deps` key. +> - These keys have the same definition as in the `deps` key > > The keys `req`, `registry` and `package` from `deps` are not required per the > limitations on builtin dependencies. From af14747b86a96494d6ab9c5ca04118daf40a768d Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 11 Aug 2025 16:55:40 +0100 Subject: [PATCH 52/96] Add `--builtin` flag to `cargo add` --- text/0000-build-std/5-stage-1b.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 07d5f9b665f..2e6cc6f9687 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -344,8 +344,8 @@ will only additionally recognise `core`, `alloc` and `std` and none of their dependencies. Many of Cargo's subcommands will need modification to support build-std: -[`cargo add`][cargo-add] will add `core`, `alloc` or `std` explicitly to the -manifest if invoked with those crate names: +[`cargo add`][cargo-add] will gain a `--builtin` flag to allow for adding crates +with a `builtin` source: ```toml [package] @@ -357,9 +357,12 @@ edition = "2024" std = { builtin = true } # <-- this would be added ``` -If attempting to add `core`, `alloc` or `std` with features then this will -fail unless the required `cargo-feature` is enabled as described in -[*Features*][features]. +If attempting to add a crate name outside of `core`, `alloc` or `std` this will +fail unless the required `cargo-feature` is added to allow other `builtin` crate +names as described in [the rationale][rationale-unstable-builtin-crates]. + +If attempting to add a `builtin` crate with features then this will fail unless +the required `cargo-feature` is enabled as described in [*Features*][features]. [`cargo info`][cargo-info] will learn how to print information for the built-in `std`, `alloc` and `core` dependencies: From f385be6bc49454ef402c5001f25ca38fca5aab37 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 11 Aug 2025 17:06:58 +0100 Subject: [PATCH 53/96] Clarified inferred deps in the registry index --- text/0000-build-std/5-stage-1b.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 2e6cc6f9687..fbcaca3760d 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -306,8 +306,8 @@ and cannot otherwise be found in the registry. > The keys `req`, `registry` and `package` from `deps` are not required per the > limitations on builtin dependencies. > -> The key is optional and its default value will be the implicit builtin -> dependencies: +> The `builtin_deps` key is optional and if not present its default value will +> be the implicit builtin dependencies: > > ```json > "builtin_deps" : [ @@ -329,6 +329,10 @@ and cannot otherwise be found in the registry. > } > ] > ``` +> +> When producing a registry index entry for a package Cargo will not serialise +> any `builtin` dependencies it inferred. This allows the set of inferred +> packages to change in the future if needed. *See the following sections for rationale/alternatives:* From d3479577363ca0f30eaf2a9443b2d20b3a8fc93c Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Tue, 12 Aug 2025 16:53:10 +0100 Subject: [PATCH 54/96] Cargo will perform the check for at least one non-optional builtin --- text/0000-build-std/5-stage-1b.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index fbcaca3760d..9b908f1d484 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -78,10 +78,10 @@ default = ["std"] std = ["dep:std"] ``` -If there is an optional dependency on the standard library then there must be at -least one non-optional dependency on the standard library (e.g. an optional -`std` and non-optional `core` or `alloc`, or an optional `alloc` and -non-optional `core`). `core` cannot be optional. +If there is an optional dependency on the standard library then Cargo will +validate that there is at least one non-optional dependency on the standard +library (e.g. an optional `std` and non-optional `core` or `alloc`, or an +optional `alloc` and non-optional `core`). `core` cannot be optional. Dependencies with `builtin = true` cannot be renamed with the `package` key ([?][rationale-package-key]). It is not possible to perform source replacement From 488aafb306351cf7e7a09f244b3511415db7a99b Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Wed, 13 Aug 2025 18:37:24 +0100 Subject: [PATCH 55/96] Note the inconsistency with sharing host-mode dependencies --- text/0000-build-std/4-stage-1a.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 3593b629022..6b4539fb2e1 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -644,14 +644,21 @@ conservative and not include the `dylib`. Procedural macros always run on the host and need to be built with a configuration that are compatible with the host toolchain's rustc as they need to be linked against it. Similarly, build scripts do not inherit `RUSTFLAGS` -from the environment so the standard library they link against must be built -with a configuration compatible with the target's default. +from the environment (a deliberate deicsion made for `1.55`), so neither can the +standard library they link against. This means neither can use the standard +library that the user may have customised with target modifiers. + +This does introduce a perhaps surprising inconsistency for users where when +building without `--target` different hostmode dependencies use different +versions of the standard library. This is unavoidable while allowing users to +customise the standard library with target modifiers. There is little advantage to using a custom standard library with procedural macros or build scripts as they are not part of the final output artifact and anywhere they can run already have a toolchain with host tools and a pre-built standard library. The fact that any configuration cannot change -`target-modifiers` further limits any potential uses. +`target-modifiers` further limits any potential uses. If desired this feature +can be added in the future by extending the features proposed in this RFC. ↩ [*Proposal*][proposal] From f19cc6bf4ff5cf2f9692996f31e2d9a66f6d0c7d Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Wed, 13 Aug 2025 18:59:08 +0100 Subject: [PATCH 56/96] Unresolved RUSTFLAGS --- text/0000-build-std/4-stage-1a.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 6b4539fb2e1..f17bf92c4c1 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -34,7 +34,7 @@ unconditionally recompiled ([?][rationale-unconditional]) in the release profile defined in its workspace as part of every clean build ([?][rationale-release-profile]). This is primarily useful for users of tier three targets. Like with other dependencies the build will inherit variables -like `RUSTFLAGS` from the environment. +like `RUSTFLAGS` from the environment (see [unresolved-inherit-rustflags]). > [!NOTE] > @@ -128,6 +128,7 @@ times - once for each target in the project. - [*What should the `build-std` configuration in `.cargo/config` be named?*][unresolved-config-name] - [*What should the "always" and "never" values of `build-std` be named?*][unresolved-config-values] - [*What should `build-std-crate` be named?*][unresolved-build-std-crate-name] +- [*Should the standard library inherit RUSTFLAGS?*][unresolved-inherit-rustflags] ## Interactions with `#![no_std]` [interactions-with-no_std]: #interactions-with-no_std @@ -913,6 +914,14 @@ What should this configuration option be named? ↩ [*Proposal*][proposal] +## Should the standard library inherit RUSTFLAGS? +[unresolved-inherit-rustflags]: #should-the-standard-library-inherit-rustflags + +The original opaque dependencies model gave them their own `RUSTFLAGS`. This RFC +currently diverges from that - can the two be unified in some way? + +↩ [*Proposal*][proposal] + # Future possibilities [future-possibilities]: #future-possibilities From 88094de0ed19194516e9dcccdc95edeef67c7d0b Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 14 Aug 2025 11:27:17 +0100 Subject: [PATCH 57/96] Rework implicit deps rationale --- text/0000-build-std/5-stage-1b.md | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 9b908f1d484..d98c22ce229 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -121,7 +121,7 @@ files ([?][rationale-cargo-lock]). - [*Why disallow builtin dependencies to be combined with other sources?*][rationale-builtin-other-sources] - [*Why disallow builtin dependencies on other crates?*][rationale-no-builtin-other-crates] - [*Why unstably allow all names for `builtin` crates?*][rationale-unstable-builtin-crates] -- [*Why not migrate to always requiring explicit standard library dependencies?*][rationale-no-migration] +- [*Why not require builtin dependencies instead of supporting implicit ones?*][rationale-no-migration] - [*Why disallow renaming standard library dependencies?*][rationale-package-key] - [*Why disallow source replacement on `builtin` packages?*][rationale-source-replacement] - [*Why add standard library dependencies to Cargo.lock?*][rationale-cargo-lock] @@ -627,25 +627,25 @@ hardcode the names of many crates in the sysroot which are inherently unstable. ↩ [*Proposal*][proposal] -## Why not migrate to always requiring explicit standard library dependencies? -[rationale-no-migration]: #why-not-migrate-to-always-requiring-explicit-standard-library-dependencies +## Why not require builtin dependencies instead of supporting implicit ones? +[rationale-no-migration]: #why-not-require-builtin-dependencies-instead-of-supporting-implicit-ones -Requiring explicit `builtin` dependencies would, for one, increase the -boilerplate required for users of Cargo and make the minimal `Cargo.toml` file -larger. +Requiring explicit `builtin` dependencies (which would have to happen on a new +edition) would, for one, increase the boilerplate required for users of Cargo +and make the minimal `Cargo.toml` file larger. -Explicit standard library dependencies with `builtin = true` will necessarily -only be understood by newer versions of Cargo. If there were no implicit -dependencies then adding `builtin` dependencies to a crate would mean that Cargo -has to make a decision on builtins for every crate in the dependency graph. This -either means that every crate in a project would also require explicit `builtin` -dependencies in order for Cargo to resolve them, putting a lot of pressure on -every Rust crate to raise their MSRV. +Cargo must always continue to support old manifests, meaning it must support +crates without builtin dependencies and crates with builtin dependencies. It +must also support crate graphs with a mixture of these types of manifest in +order for crates to migrate before their dependencies do. Implicit dependencies +are required to allow Cargo to resolve `builtin` dependencies and pass them +correctly to crates which support them while the ecosystem migrates. This proposal puts less pressure on the ecosystem to upgrade - `no_std` crates -(or crates with a `std` feature) will benefit from adding explicit dependencies -to allow them to be easily used on `no_std` targets but users can still work -around any legacy crates in the graph with [`build-std-crates`][stage1a]. +(or crates with a `std` feature) will still benefit from adding explicit +dependencies to allow them to be easily used on `no_std` targets but users can +still work around any legacy crates in the graph with +[`build-std-crates`][stage1a]. Alternative syntaxes, such as requiring `version = "*"` for explicit standard library dependencies, were considered to maintain a greater level of From 39c0f05e9ef159985b20529a3a2cf5b4f6ea44f2 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 14 Aug 2025 11:43:47 +0100 Subject: [PATCH 58/96] Rework manifest compatibility --- text/0000-build-std/5-stage-1b.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index d98c22ce229..a66dc562774 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -647,15 +647,15 @@ dependencies to allow them to be easily used on `no_std` targets but users can still work around any legacy crates in the graph with [`build-std-crates`][stage1a]. -Alternative syntaxes, such as requiring `version = "*"` for explicit standard -library dependencies, were considered to maintain a greater level of -compatibility with older toolchain versions. However, any older version of Cargo -would try to look for a specified dependency somewhere - if this lookup failed -then the resolve would fail, and if it succeeded (by perhaps finding an empty -`std` crate on crates.io) then these would override the prebuilt std when passed -to rustc via `--extern`. It is not possible to direct any older version of Cargo -to ignore a dependency. This is not a build-std specific issue and is true of -any RFC adding to what can be written in `Cargo.toml`. +Alternative syntaxes for explicit standard library dependencies were considered +to maintain manifest compatibility with older versions of Cargo. However, there +is no way for older versions of Cargo to behave correctly when encountering a +builtin dependency (i.e. ignore them). Builtin dependencies must also be treated +differently when serialising the registry index schema by adding them to a +separate field for dependencies, which older versions of Cargo would not be +aware of. Requiring a new Cargo version to understand the manifest is common +for new Cargo features, but we do maintain compatibility for index entries as +described in [registries]. ↩ [*Proposal*][proposal] @@ -812,7 +812,7 @@ stabilisation and aren't pertinent to the overall design: [unresolved-dep-syntax]: #what-syntax-is-used-to-identify-dependencies-on-the-standard-library-in-cargotoml What syntax should be used for the explicit standard library dependencies? -`builtin = true`? `sysroot = true`? `version = "*"`? +`builtin = true`? `sysroot = true`? ↩ [*Proposal*][proposal] From 1e6184b78b2834565b1167831ed06d6dd9cca027 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 14 Aug 2025 12:06:50 +0100 Subject: [PATCH 59/96] Draw attention to build-dependencies --- text/0000-build-std/5-stage-1b.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index a66dc562774..e35e8762b11 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -276,6 +276,11 @@ Build scripts and proc macros continue to use the prebuilt standard library as in stage 1a, and so explicit dependencies on the standard library are not supported in `build-dependencies`. +*See the following sections for relevant unresolved questions:* + +- [*Should we support `build-dependencies`?*][unresolved-build-deps] + + ## Registries [registries]: #registries @@ -833,6 +838,22 @@ be needlessly different to existing packages. ↩ [*Patches*][patches] +## Should we support `build-dependencies`? +[unresolved-build-deps]: #should-we-support-build-dependencies + +Allowing `builtin` dependencies to be regular and `dev` dependencies but not +`build` dependencies is inconsistent with other dependencies. + +Cargo supports changing the profiles of these dependencies in a +`[profile.dev.build-override]` section, and while this proposal does not allow +changing the profile of the standard library and we expect that the use cases +for doing so for build dependenies are minimal (see +[stage1a][stage1a-host-deps]), users may expect to be able to do so. What they +may not expect, however, is the increase in build times from needing to build +the standard library an additional time for these dependencies. + +↩ [*Dev-dependencies and build-dependencies*][dev-dependencies-and-build-dependencies] + # Future possibilities [future-possibilities]: #future-possibilities @@ -910,6 +931,7 @@ user can enable `compiler-builtins/c`, they will need to manually configure `CFLAGS` to ensure that the C components will link with Rust code. [stage1a]: ./4-stage-1a.md +[stage1a-host-deps]: ./4-stage-1a.md#why-use-the-pre-built-standard-library-for-procedural-macros-and-build-scripts [background-dependencies]: ./1-background.md#dependencies [cargo-docs-renaming]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml From 22a9b855136cd99004e60637f47659fedee32d2b Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 10:45:49 +0000 Subject: [PATCH 60/96] 1a: elaborate on why host-mode uses pre-built std --- text/0000-build-std/4-stage-1a.md | 59 +++++++++++++++++++------------ text/0000-build-std/5-stage-1b.md | 10 +++--- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index f17bf92c4c1..3342e23a0f5 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -104,10 +104,11 @@ harness then Cargo will also build the `test` crate. > `target` directory of the crate or workspace like any other dependency. The host pre-built standard library will always be used for procedural macros -and build scripts ([?][rationale-sysroot-for-host-deps]). Multi-target projects -(resulting from the `target` field in artifact dependencies or the use of -`per-pkg-target` fields) may result in the standard library being built multiple -times - once for each target in the project. +and build scripts ([?][rationale-host-deps-cross], +[?][rationale-host-deps-host]). Multi-target projects (resulting from the +`target` field in artifact dependencies or the use of `per-pkg-target` fields) +may result in the standard library being built multiple times - once for each +target in the project. *See the following sections for rationale/alternatives:* @@ -121,7 +122,8 @@ times - once for each target in the project. - [*Why use the lockfile of the `rust-src` component?*][rationale-lockfile] - [*Why not build the standard library in incremental?*][rationale-incremental] - [*Why not produce a `dylib` for the standard library?*][rationale-no-dylib] -- [*Why use the pre-built standard library for procedural macros and build-scripts?*][rationale-sysroot-for-host-deps] +- [*Why use the pre-built standard library for procedural macros and build scripts in host mode?*][rationale-host-deps-host] +- [*Why use the pre-built standard library for procedural macros and build scripts in cross-compile mode?*][rationale-host-deps-cross] *See the following sections for relevant unresolved questions:* @@ -639,27 +641,38 @@ conservative and not include the `dylib`. ↩ [*Proposal*][proposal] -## Why use the pre-built standard library for procedural macros and build-scripts? -[rationale-sysroot-for-host-deps]: #why-use-the-pre-built-standard-library-for-procedural-macros-and-build-scripts +## Why use the pre-built standard library for procedural macros and build scripts in cross-compile mode? +[rationale-host-deps-cross]: #why-use-the-pre-built-standard-library-for-procedural-macros-and-build-scripts-in-cross-compile-mode Procedural macros always run on the host and need to be built with a -configuration that are compatible with the host toolchain's rustc as they need -to be linked against it. Similarly, build scripts do not inherit `RUSTFLAGS` -from the environment (a deliberate deicsion made for `1.55`), so neither can the -standard library they link against. This means neither can use the standard -library that the user may have customised with target modifiers. - -This does introduce a perhaps surprising inconsistency for users where when -building without `--target` different hostmode dependencies use different -versions of the standard library. This is unavoidable while allowing users to -customise the standard library with target modifiers. - -There is little advantage to using a custom standard library with procedural -macros or build scripts as they are not part of the final output artifact and +configuration that are compatible with the host toolchain's Cargo and rustc, +limiting the potential customisations of the standard library that would be +valid. There is little advantage to using a custom standard library with +procedural macros, as they are not part of the final output artifact and anywhere they can run already have a toolchain with host tools and a pre-built -standard library. The fact that any configuration cannot change -`target-modifiers` further limits any potential uses. If desired this feature -can be added in the future by extending the features proposed in this RFC. +standard library. + +Build scripts similarly always run on the host and thus would require building +the standard library again for the host. There is little advantage to doing this +as build scripts are not part of the final output artifact. Build scripts do not +respect `RUSTFLAGS` which could result in target modifier mismatches if +rebuilding the standard library does respect `RUSTFLAGS`. + +↩ [*Proposal*][proposal] + +## Why use the pre-built standard library for procedural macros and build scripts in host mode? +[rationale-host-deps-host]: #why-use-the-pre-built-standard-library-for-procedural-macros-and-build-scripts-in-host-mode + +Unlike when in cross-compile mode, if Cargo is in host mode (i.e. `--target` is +not provided), the standard library built by build-std could hypothetically be +used for procedural macros and build scripts without additional recompilations +of the standard library. + +However, as with [cross-compile mode][rationale-host-deps-cross], there is +little advantage to using a customised standard library for procedural macros or +build scripts, and both would require limitations on the customisations possible +with build-std in order to guarantee compatibility with the compiler or build +script, respectively. ↩ [*Proposal*][proposal] diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index e35e8762b11..78c515fb558 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -100,7 +100,7 @@ Implicit and explicit standard library dependencies are added to `Cargo.lock` files ([?][rationale-cargo-lock]). > [!NOTE] -> +> > A new version of the `Cargo.lock` file will be introduced to add support for > packages with a `builtin` source: > @@ -110,7 +110,7 @@ files ([?][rationale-cargo-lock]). > version = "0.0.0" > source = "builtin" > ``` -> +> > The package version of `std`, `alloc` and `core` will be fixed at `0.0.0`. The > optional lockfile fields `dependencies` and `checksum` will not be present for > `builtin` dependencies. @@ -829,7 +829,7 @@ appropriate? Could the `source` field be reused with the string "builtin" or should it stay only as a URL+scheme? ↩ [*Proposal*][proposal] - + ## What syntax is used to patch dependencies on the standard library in `Cargo.toml`? [unresolved-patch-syntax]: #what-syntax-is-used-to-patch-dependencies-on-the-standard-library-in-cargotoml @@ -847,7 +847,7 @@ Allowing `builtin` dependencies to be regular and `dev` dependencies but not Cargo supports changing the profiles of these dependencies in a `[profile.dev.build-override]` section, and while this proposal does not allow changing the profile of the standard library and we expect that the use cases -for doing so for build dependenies are minimal (see +for doing so for build dependencies are minimal (see [stage1a][stage1a-host-deps]), users may expect to be able to do so. What they may not expect, however, is the increase in build times from needing to build the standard library an additional time for these dependencies. @@ -931,7 +931,7 @@ user can enable `compiler-builtins/c`, they will need to manually configure `CFLAGS` to ensure that the C components will link with Rust code. [stage1a]: ./4-stage-1a.md -[stage1a-host-deps]: ./4-stage-1a.md#why-use-the-pre-built-standard-library-for-procedural-macros-and-build-scripts +[stage1a-host-deps]: ./4-stage-1a.md#why-use-the-pre-built-standard-library-for-procedural-macros-and-build-scripts-in-cross-compile-mode [background-dependencies]: ./1-background.md#dependencies [cargo-docs-renaming]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml From 9c88d2d27d788d78ef59dd82e9c84ebf150749aa Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 11:02:30 +0000 Subject: [PATCH 61/96] 1a: clarify no-std section --- text/0000-build-std/4-stage-1a.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 3342e23a0f5..00aae986dff 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -680,21 +680,28 @@ script, respectively. [rationale-replace-no_std]: #why-not-replace-no_std-as-the-source-of-truth-for-whether-a-crate-depends-on-std Crates can currently use the crate attribute `#![no_std]` to indicate a lack of -dependency on `std`. With `build-std-crates` or explicit dependencies (as in -[Stage 1b][stage1b]) allowing the user to specify a dependency on the standard -library, it is unintuitive for there to be two sources-of-truth for this -information. +dependency on `std`. Introducing `build-std-crates` or explicit dependencies (as +in [Stage 1b][stage1b]) would add a second way for the user to indicate a lack +of dependency on the standard library. It could therefore be seen as desirable +to deprecate `#![no_std]` so that there remains only a single way to express a +dependency on the standard library. `#![no_std]` serves two purposes - it stops the compiler from loading `std` from the sysroot and adding `extern crate std`, and it prevents the user from depending on anything from `std` accidentally. `#![no_std]` could hypothetically be replaced by a lint to prevent use of the -standard library and a change to the compiler so that it loads the `std` +standard library and a change to the compiler so that it loads `std` speculatively unless it is used. However, while rustc does have some support for speculatively loading crates, it is not possible to do so and not declare them as a dependency in cross-crate metadata. +Alternatively, the `#![no_std]` attribute could be deprecated and instead become +a compiler flag that Cargo could pass when there is no dependency on std. While +this would be worthwhile, it is only practical once this proposal's changes to +Cargo have been widely adopted and Cargo is the source-of-truth for a dependency +on the `std`, and so it is not proposed in this RFC. + ↩ [*Interactions with `#![no_std]`*][interactions-with-no_std] ### Why remove `restricted_std`? From e93f9aa3971c7c7fb216ded9b8ff22279ba0147b Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 11:09:11 +0000 Subject: [PATCH 62/96] 1a: clarify status of Cargo caching issue --- text/0000-build-std/4-stage-1a.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 00aae986dff..aff278d1b2a 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -888,10 +888,10 @@ has precedence over shared libraries and the symbols of a dynamically-linked [rationale-caching]: #why-not-globally-cache-builds-of-the-standard-library The standard library is no different than regular dependencies in being able to -benefit from global caching of dependency builds. A generic proposal for global -dependency caching is being worked on as part of [cargo#5931] and could support -the standard library. It is out-of-scope of this proposal to propose a -special-cased mechanism for this that applies only to the standard library. +benefit from global caching of dependency builds. It is out-of-scope of this +proposal to propose a special-cased mechanism for this that applies only to the +standard library. [cargo#5931] tracks the feature request of intermediate +artifact caching in Cargo. ↩ [*Caching*][caching] From b279b5b5c77462d03c0aa2b93a2373d5ca8dccd2 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 11:09:11 +0000 Subject: [PATCH 63/96] 1a: elaborate on inheriting rustflags --- text/0000-build-std/4-stage-1a.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index aff278d1b2a..61d339de15d 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -33,8 +33,8 @@ When `build-std` is set to "always", then the standard library will be unconditionally recompiled ([?][rationale-unconditional]) in the release profile defined in its workspace as part of every clean build ([?][rationale-release-profile]). This is primarily useful for users of tier -three targets. Like with other dependencies the build will inherit variables -like `RUSTFLAGS` from the environment (see [unresolved-inherit-rustflags]). +three targets. As with other dependencies, the standard library's build will +respect the `RUSTFLAGS` environment variable. > [!NOTE] > @@ -937,8 +937,11 @@ What should this configuration option be named? ## Should the standard library inherit RUSTFLAGS? [unresolved-inherit-rustflags]: #should-the-standard-library-inherit-rustflags -The original opaque dependencies model gave them their own `RUSTFLAGS`. This RFC -currently diverges from that - can the two be unified in some way? +Existing designs for *[Opaque dependencies]* intended that `RUSTFLAGS` would not +apply to the opaque dependency. However, if a target modifier were set using +`RUSTFLAGS` and build-std ignored the variable, then rustc would fail to build +the user's project due to incompatible target modifiers. This would necessitate +that every stable target modifier be exposed via Cargo to be usable in practice. ↩ [*Proposal*][proposal] From 0f6a9ea23ac1e78fd180d162c976ff19cf18be4d Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 11:26:57 +0000 Subject: [PATCH 64/96] 1b: correct link syntax --- text/0000-build-std/5-stage-1b.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 78c515fb558..29049475796 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -660,7 +660,7 @@ differently when serialising the registry index schema by adding them to a separate field for dependencies, which older versions of Cargo would not be aware of. Requiring a new Cargo version to understand the manifest is common for new Cargo features, but we do maintain compatibility for index entries as -described in [registries]. +described in [*Registries*][registries]. ↩ [*Proposal*][proposal] From 2a330da09efc33164ff706d129a3bda4d1c43982 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 11:29:14 +0000 Subject: [PATCH 65/96] 1b: simplify unresolved q for build-dependencies --- text/0000-build-std/5-stage-1b.md | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 29049475796..c94dfaa655a 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -273,14 +273,13 @@ Implicit and explicit dependencies on the standard library are supported for dependencies specified are also available as `dev-dependencies` as usual. Build scripts and proc macros continue to use the prebuilt standard library as -in stage 1a, and so explicit dependencies on the standard library are not +in Stage 1a, and so explicit dependencies on the standard library are not supported in `build-dependencies`. *See the following sections for relevant unresolved questions:* - [*Should we support `build-dependencies`?*][unresolved-build-deps] - ## Registries [registries]: #registries @@ -841,18 +840,14 @@ be needlessly different to existing packages. ## Should we support `build-dependencies`? [unresolved-build-deps]: #should-we-support-build-dependencies -Allowing `builtin` dependencies to be regular and `dev` dependencies but not -`build` dependencies is inconsistent with other dependencies. +Allowing `builtin` dependencies to be used in `dependencies` and +`dev-dependencies` but not in `build-dependencies` is an inconsistency. -Cargo supports changing the profiles of these dependencies in a -`[profile.dev.build-override]` section, and while this proposal does not allow -changing the profile of the standard library and we expect that the use cases -for doing so for build dependencies are minimal (see -[stage1a][stage1a-host-deps]), users may expect to be able to do so. What they -may not expect, however, is the increase in build times from needing to build -the standard library an additional time for these dependencies. +However, supporting `builtin` dependencies in `build-dependencies` would permit +no-std build scripts. It is unclear whether supporting no-std build scripts +would be desirable. -↩ [*Dev-dependencies and build-dependencies*][dev-dependencies-and-build-dependencies] +↩ [*`dev-dependencies` and `build-dependencies`*][dev-dependencies-and-build-dependencies] # Future possibilities [future-possibilities]: #future-possibilities @@ -931,7 +926,6 @@ user can enable `compiler-builtins/c`, they will need to manually configure `CFLAGS` to ensure that the C components will link with Rust code. [stage1a]: ./4-stage-1a.md -[stage1a-host-deps]: ./4-stage-1a.md#why-use-the-pre-built-standard-library-for-procedural-macros-and-build-scripts-in-cross-compile-mode [background-dependencies]: ./1-background.md#dependencies [cargo-docs-renaming]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml From d5e3e6474df82ed766f912d8b662292f3dc83805 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 11:40:55 +0000 Subject: [PATCH 66/96] 1b: elaborate on dev-dependencies --- text/0000-build-std/5-stage-1b.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index c94dfaa655a..7c04a65408f 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -269,8 +269,11 @@ std = { builtin = true, public = true } [dev-dependencies-and-build-dependencies]: #dev-dependencies-and-build-dependencies Implicit and explicit dependencies on the standard library are supported for -`dev-dependencies` in the same way as regular `dependencies`. Any `builtin` -dependencies specified are also available as `dev-dependencies` as usual. +`dev-dependencies` in the same way as regular `dependencies`. `dev-dependencies` +continues to be a superset of `dependencies`, including with `builtin` +dependencies. It is possible for `dev-dependencies` to have additional `builtin` +dependencies that the `dependencies` section does not have (e.g. requiring `std` +when the regular dependencies only require `core`). Build scripts and proc macros continue to use the prebuilt standard library as in Stage 1a, and so explicit dependencies on the standard library are not From 725065eac08bd38c83bc2318880fa473f29b3c8c Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 11:44:24 +0000 Subject: [PATCH 67/96] 1b: elaborate on `cargo add`/`cargo remove` --- text/0000-build-std/5-stage-1b.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 7c04a65408f..79c58fd88b3 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -355,8 +355,10 @@ will only additionally recognise `core`, `alloc` and `std` and none of their dependencies. Many of Cargo's subcommands will need modification to support build-std: -[`cargo add`][cargo-add] will gain a `--builtin` flag to allow for adding crates -with a `builtin` source: +[`cargo add`][cargo-add]'s heuristics will include adding `std`, `alloc` or +`core` as builtin dependencies if these crate names are provided. `cargo add` +will additionally have a `--builtin` flag to allow for adding crates with a +`builtin` source explicitly: ```toml [package] @@ -444,7 +446,8 @@ any other dependency. the source, likewise with `alloc` and `std`. [`cargo remove`][cargo-remove] will remove `core`, `alloc` or `std` explicitly -from the manifest if invoked with those crate names: +from the manifest if invoked with those crate names (using the same heuristics +as those described above for `cargo add`): ```toml [package] From 97bb251817df33fe388f2545ca6b60d8cc464878 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 11:46:02 +0000 Subject: [PATCH 68/96] 1b: explicit dependencies for `cargo metadata` --- text/0000-build-std/5-stage-1b.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 79c58fd88b3..7ca162b11e5 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -409,9 +409,9 @@ documentation: https://doc.rust-lang.org/1.86.0/core/index.html [`cargo metadata`][cargo-metadata] will emit `std`, `alloc` and `core` dependencies to the metadata emitted by `cargo metadata` (when those crates are -dependencies). None of the standard library's dependencies will be included. -`source` would be set to `builtin` and the remaining fields would be set like -any other dependency. +explicit dependencies). None of the standard library's dependencies will be +included. `source` would be set to `builtin` and the remaining fields would be +set like any other dependency. > [!NOTE] > From 4d7a4d7b39d6449d15b0b8813a3747ba7d5cb616 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 11:48:13 +0000 Subject: [PATCH 69/96] 1b: published manifest not include inferred deps --- text/0000-build-std/5-stage-1b.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 7ca162b11e5..1b8ae4af985 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -339,7 +339,8 @@ and cannot otherwise be found in the registry. > > When producing a registry index entry for a package Cargo will not serialise > any `builtin` dependencies it inferred. This allows the set of inferred -> packages to change in the future if needed. +> packages to change in the future if needed. Similarly, the published +> `Cargo.toml` will not explicitly declare any inferred dependencies. *See the following sections for rationale/alternatives:* From 6a193bc3da0b0527ca0c72788fbdba22991d7460 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 11:49:15 +0000 Subject: [PATCH 70/96] 1b: clarify pkgid spec --- text/0000-build-std/5-stage-1b.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 1b8ae4af985..294d23d8522 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -443,8 +443,9 @@ set like any other dependency. > } > ``` -[`cargo pkgid`][cargo-pkgid] when passed `-p core` would print `builtin#core` as -the source, likewise with `alloc` and `std`. +[`cargo pkgid`][cargo-pkgid] when passed `-p core` would print +`builtin://.#core` as the source, likewise with `alloc` and `std`. This format +complies with [Cargo's spec for Package IDs][cargo-pkgid-spec]. [`cargo remove`][cargo-remove] will remove `core`, `alloc` or `std` explicitly from the manifest if invoked with those crate names (using the same heuristics @@ -937,6 +938,7 @@ user can enable `compiler-builtins/c`, they will need to manually configure [background-dependencies]: ./1-background.md#dependencies [cargo-docs-renaming]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml [cargo-json-schema]: https://doc.rust-lang.org/cargo/reference/registry-index.html#json-schema +[cargo-pkgid-spec]: https://doc.rust-lang.org/cargo/reference/pkgid-spec.html [embed-rs-source]: https://github.com/embed-rs/stm32f7-discovery/blob/e2bf713263791c028c2a897f2eb1830d7f09eceb/core/src/lib.rs#L7 [rust-extern-prelude]: https://doc.rust-lang.org/reference/names/preludes.html#extern-prelude From 9f8f4ff6d5e4abfe2dc4858e110b7e1d796f9562 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 11:51:51 +0000 Subject: [PATCH 71/96] 1b: mention publish web api endpoint --- text/0000-build-std/5-stage-1b.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 294d23d8522..ffa3995d0fb 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -291,7 +291,9 @@ Standard library dependencies will be present in the registry index [index's JSON schema][cargo-json-schema] ([?][rationale-cargo-builtindeps]). `builtin_deps` is similar to the existing `deps` key and contains a list of JSON objects, each representing a dependency that is "builtin" to the Rust toolchain -and cannot otherwise be found in the registry. +and cannot otherwise be found in the registry. The +["publish" endpoint][cargo-registry-web-publish] of the Registry Web API will +similarly be updated to support `builtin_deps`. > [!NOTE] > @@ -938,6 +940,7 @@ user can enable `compiler-builtins/c`, they will need to manually configure [background-dependencies]: ./1-background.md#dependencies [cargo-docs-renaming]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml [cargo-json-schema]: https://doc.rust-lang.org/cargo/reference/registry-index.html#json-schema +[cargo-registry-web-publish]: https://doc.rust-lang.org/cargo/reference/registry-web-api.html#publish [cargo-pkgid-spec]: https://doc.rust-lang.org/cargo/reference/pkgid-spec.html [embed-rs-source]: https://github.com/embed-rs/stm32f7-discovery/blob/e2bf713263791c028c2a897f2eb1830d7f09eceb/core/src/lib.rs#L7 [rust-extern-prelude]: https://doc.rust-lang.org/reference/names/preludes.html#extern-prelude From 673069c0458a794a1f45f730b5963f7aa8dcfa4d Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 11:55:37 +0000 Subject: [PATCH 72/96] 1b: add "transitive" for clarification --- text/0000-build-std/5-stage-1b.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index ffa3995d0fb..f8c524e40b9 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -864,8 +864,8 @@ would be desirable. There are many possible follow-ups to Stage 1b: -## Warn when `no_std` crates accidentally have a dependency on `std` -[future-no_std-warning]: #warn-when-no_std-crates-accidentally-have-a-dependency-on-std +## Warn when `no_std` crates accidentally have a transitive dependency on `std` +[future-no_std-warning]: #warn-when-no_std-crates-accidentally-have-a-transitive-dependency-on-std Cargo could emit a warning or lint when a root crate without an explicit dependency on `std` or `alloc` has a dependency on `std` or `alloc` via a From 8127c86e86f787bb70b2b87a88621ab3d4c2f24f Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 11:57:57 +0000 Subject: [PATCH 73/96] 1b: addl. context for registry schema versions --- text/0000-build-std/5-stage-1b.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index f8c524e40b9..8869cd62e70 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -773,8 +773,10 @@ packages which are defined using a schema it does not have knowledge of. Cargo ignores packages published under an unsupported schema version, so older versions of Cargo cannot use newer versions of packages relying on these -features. New schema versions are disruptive to users on older toolchains and -should be avoided where possible. +features (though this would be true because of an incompatible Cargo manifest +anyway). New schema versions are disruptive to users on older toolchains, as the +resolver will act as if a package does not exist. Recent Cargo versions have +improved error reporting for this circumstance. Some new fields, including `rust-version`, were added to all versions of the schema. Cargo ignores fields it does not have knowledge of, so older versions of From 8755a8e7df0f96c926d32089c7786b42703c5153 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 12:01:04 +0000 Subject: [PATCH 74/96] 3: mention profile field only working in one ctxt --- text/0000-build-std/7-stage-3.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/text/0000-build-std/7-stage-3.md b/text/0000-build-std/7-stage-3.md index a34ca097e9e..3949214c6a3 100644 --- a/text/0000-build-std/7-stage-3.md +++ b/text/0000-build-std/7-stage-3.md @@ -30,7 +30,7 @@ automatically when a pre-built standard library is not present. different profile than the default "release" profile of the pre-built standard library or a rebuild is necessary to maintain compatibility with the user's crate ([?][rationale-compatible-profile]). - + Cargo will build the standard library using the same profile as the user, as defined in the standard library workspace ([?][rationale-compatible-profile-std]). It will vary only in the target modifiers @@ -87,6 +87,7 @@ the standard library if [*Stage 1b*][stage1b] was implemented. *See the following sections for relevant unresolved questions:* - [*What should the "match-profile" and "compatible-profile" values of `build-std` be named?*][unresolved-naming] +- [*Should `build-std` be in `[profile]` if it only makes in the Cargo configuration `[profile]`?*][unresolved-profile] ## Stability guarantees [stability-guarantees]: #stability-guarantees @@ -136,6 +137,10 @@ binary. It is more likely that users would want to use "match-profile" with the release profile than by default (as in `[build]`) or for a specific target (as in `[target]`). +However, permitting `build-std` in `[profile]` when in Cargo configurations, but +not in Cargo manifests, is inconsistent with other options that exist in +profiles. + ↩ [*Proposal*][proposal] ## Why does `[profile]` have higher precedence than `[build]` and lower than `[target]`? @@ -176,7 +181,7 @@ builds would immediately trigger a rebuild of the standard library. ↩ [*Proposal*][proposal] ### Why add "compatible-profile"? -[rationale-compatible-profile]: #why-add-compatible-profile +[rationale-compatible-profile]: #why-add-compatible-profile "compatible-profile" is useful for when users want a more debuggable standard library while keeping rebuilds of the standard library to a minimum. @@ -184,7 +189,7 @@ library while keeping rebuilds of the standard library to a minimum. ↩ [*Proposal*][proposal] ### Why does "compatible-profile" use the standard library's profiles? -[rationale-compatible-profile-std]: #why-does-compatible-profile-use-the-standard-librarys-profiles +[rationale-compatible-profile-std]: #why-does-compatible-profile-use-the-standard-librarys-profiles By using the standard library's profile definitions, the library team will be able to define a "dev" profile that is most useful for the standard library. @@ -192,7 +197,7 @@ able to define a "dev" profile that is most useful for the standard library. ↩ [*Proposal*][proposal] ### Why add "match-profile"? -[rationale-match-profile]: #why-add-match-profile +[rationale-match-profile]: #why-add-match-profile "match-profile" is useful for rebuilding the standard library with the same codegen flags as the rest of the user's project, such as using `-Ctarget-cpu` to @@ -211,6 +216,11 @@ stabilisation and aren't pertinent to the overall design: It could be named something else. +## Should `build-std` be in `[profile]` if it only makes in the Cargo configuration `[profile]`? +[unresolved-profile]: #should-build-std-be-in-profile-if-it-only-makes-in-the-cargo-configuration-profile + +This could be unintuitive for users. + # Future possibilities [future-possibilities]: #future-possibilities From 4a278b81edbdcf7f33bfabb91ef577514712ced3 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 12:05:30 +0000 Subject: [PATCH 75/96] 3: no precedence for precedence --- text/0000-build-std/7-stage-3.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/text/0000-build-std/7-stage-3.md b/text/0000-build-std/7-stage-3.md index 3949214c6a3..ae3a4b60a1d 100644 --- a/text/0000-build-std/7-stage-3.md +++ b/text/0000-build-std/7-stage-3.md @@ -147,7 +147,9 @@ profiles. [rationale-profile-precedence]: #why-does-profile-have-higher-precedence-than-build-and-lower-than-target `[target]` configuration is more narrowly scoped than `[profile]` which is in -turn more narrowly scoped than the global default in `[build]`. +turn more narrowly scoped than the global default in `[build]`. There is no +existing precedent in Cargo for these sections having the precedence currently +proposed. ↩ [*Proposal*][proposal] From 905684d3037f68c33f5bde1f3cca417eff848270 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 14 Aug 2025 12:07:48 +0000 Subject: [PATCH 76/96] 1b: fix typo --- text/0000-build-std/5-stage-1b.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 8869cd62e70..b96cf4102fb 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -173,7 +173,7 @@ crates.io. ## Patches [patches]: #patches -Under a perma-unstable fetaure it is permitted to patch the standard library +Under a perma-unstable feature it is permitted to patch the standard library dependencies with `path` and `git` sources (or any other source) ([?][rationale-patching]): From cb098ff8d53edcdab8b0c0916be59d7a5e108675 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Fri, 15 Aug 2025 15:14:26 +0100 Subject: [PATCH 77/96] Fix nested list indentation --- text/0000-build-std/3-motivation.md | 92 +++++++++++++++-------------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/text/0000-build-std/3-motivation.md b/text/0000-build-std/3-motivation.md index e3a570adb55..58ca0886f12 100644 --- a/text/0000-build-std/3-motivation.md +++ b/text/0000-build-std/3-motivation.md @@ -20,31 +20,33 @@ This RFC aims to support the following use cases: 1. **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 + - 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 2. **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 + - 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 + - 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 + - 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 @@ -53,31 +55,31 @@ This RFC aims to support the following use cases: 3. **Building the standard library on a stable toolchain without Cargo** - - While tangential to the core of build-std as a feature, projects like Rust - for Linux want to be able to build an unmodified `core` from `rust-src` in - the sysroot on a stable toolchain without Cargo + - While tangential to the core of build-std as a feature, projects like Rust + for Linux want to be able to build an unmodified `core` from `rust-src` in + the sysroot on a stable toolchain without Cargo - It is relatively straightforward to support this, hence its inclusion - - Cargo may also want a mechanism to build the standard library for build-std - on a stable toolchain without relying on `RUSTC_BOOTSTRAP` + - Cargo may also want a mechanism to build the standard library for + build-std on a stable toolchain without relying on `RUSTC_BOOTSTRAP` 4. **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`) + - 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`) 5. **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 + - 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` + - 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]) + - These users are forced to use nightly and the unstable `-Zbuild-std` + feature or third-party tools like [cargo-xbuild] (formerly [xargo]) The following use cases are not supported by this RFC, but could be supported with follow-up RFCs (and this RFC will attempt to ensure they remain viable as @@ -85,25 +87,25 @@ 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) + - 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 + - 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. + - 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 a feature like `optimize_for_size` or - `panic_immediate_abort` to reduce binary size + - For example, embedded users may want to enable a feature like + `optimize_for_size` or `panic_immediate_abort` 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 + - 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 RFC may make decisions which make From dbf57b31af0c51f09f2931480d6fb05ddd630a87 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Fri, 15 Aug 2025 15:14:36 +0100 Subject: [PATCH 78/96] Justify excluded motivations --- text/0000-build-std/3-motivation.md | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/text/0000-build-std/3-motivation.md b/text/0000-build-std/3-motivation.md index 58ca0886f12..50353148abb 100644 --- a/text/0000-build-std/3-motivation.md +++ b/text/0000-build-std/3-motivation.md @@ -113,18 +113,30 @@ 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 + - 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 + - Similarly, some tier three targets may wish to patch standard library + dependencies to add or improve support for the target + + Supporting such users is very difficult to do so given that the standard + library's internals and its dependencies change often. Users wishing to do + this can instead fork the toolchain rather than modifying a toolchain + shipped by the rust project. 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 + Earlier proposals for build-std were motivated in-part by the desire to see + the concept of the sysroot retired. + + Doing this in a backwards-compatible way is difficult considering that many + users use build systems other than Cargo that assume rustc can find any + standard library dependencies. Many artifacts other than the standard + library also live in the sysroot meaning that the scope of any alternative + would be large. In addition, removing the sysroot does not significantly + help achieve previously stated motivations in this RFC. [cargo-xbuild]: https://github.com/rust-osdev/cargo-xbuild [xargo]: https://github.com/japaric/xargo From 418c560532ecea872e08d90063dc4859015ae7dd Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 18 Aug 2025 14:16:48 +0100 Subject: [PATCH 79/96] Remove special Cargo handling for c-b-mem --- text/0000-build-std/1-background.md | 7 ++++-- text/0000-build-std/4-stage-1a.md | 33 +++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/text/0000-build-std/1-background.md b/text/0000-build-std/1-background.md index 7e497ba4100..5247525cdef 100644 --- a/text/0000-build-std/1-background.md +++ b/text/0000-build-std/1-background.md @@ -105,8 +105,11 @@ dependencies: standard library - `compiler_builtins` has an optional `mem` feature that provides symbols for common memory routines (e.g. `memcpy`) - - It isn't used when `std` is built as `libc` provides these routines, - but is often used by `no_std` crates when there is not a system `libc` + - It is enabled automatically on `no_std` platforms as when `std` is built + `libc` provides these routines. + - Users often rely on weak linkage to override these symbols when required, + but in scenarios where weak linkage is not supported 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 diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 61d339de15d..55abbdae8ba 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -354,16 +354,21 @@ for discussion of the `compiler-builtins-c` feature. The `mem` feature of `compiler_builtins` (and the subsequent `compiler-builtins-mem` feature of `core`, `alloc`, `std` which forward to -`compiler_builtins/mem`) is required by `no_std` crates as a `std` dependency -will not be providing these symbols through its dependency on `libc`. +`compiler_builtins/mem`) will be inverted to a new feature named `external-mem` +([?][rationale-no-mem]). This will not be a default feature, so +`compiler_builtins` will provide mem symbols unless the `external-mem` is +provided. -It is necessary that the `compiler-builtins-mem` feature of `alloc` and/or -`core` be enabled when `libc` is not in the crate graph -([?][rationale-no-weak-linkage]). +`std`, which dynamically links to `libc`, will depend on the `external-mem` +feature. `no_std` users providing their own mem symbols can rely on weak linkage +to override the ones provided by `compiler_builtins` or provide the +`external-mem` feature with an unstable feature in scenarios where weak linkage +is not an option ([?][rationale-no-weak-linkage]). *See the following sections for rationale/alternatives:* -- [*Why not use weak linkage for `compiler-builtins/mem` symbols?*][rationale-no-weak-linkage] +- [*Why invert the `mem` feature?*][rationale-no-mem] +- [*Why not rely on weak linkage for `compiler-builtins/mem` symbols?*][rationale-no-weak-linkage] ## Caching [caching]: #caching @@ -870,6 +875,22 @@ special-case all of these crates. ↩ [*Building the standard library on a stable toolchain*][building-the-standard-library-on-a-stable-toolchain] +### Why invert the `mem` feature? +[rationale-no-mem]: #why-invert-the-mem-feature + +Currently the `mem` feature is enabled for `no_std` platforms in the +`compiler_builtins` `build.rs` file. Inverting a Cargo feature might seem like +an antipattern as "negative" features are discouraged because of how features +unify (e.g. `std` features are preferred to `no_std`). + +However, the `mem` feature is difficult to use as either `std` or the user may +want to turn the feature off. Because many different crates in the standard +library workspace depend on `compiler_builtins` this negative must be forwarded +to all of them to correctly disable the feature which is quite tricky to do. +This shows that the `mem` feature is actually the wrong way around. + +↩ [*`compiler-builtins-mem`*][compiler-builtins-mem] + ### Why not use weak linkage for `compiler-builtins/mem` symbols? [rationale-no-weak-linkage]: #why-not-use-weak-linkage-for-compiler-builtinsmem-symbols From 4a81e02ae5e6a4e8d06067d538866d575f689514 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 18 Aug 2025 15:09:29 +0100 Subject: [PATCH 80/96] Clarify shadowing path deps --- text/0000-build-std/1-background.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/text/0000-build-std/1-background.md b/text/0000-build-std/1-background.md index 5247525cdef..6b2e15ea084 100644 --- a/text/0000-build-std/1-background.md +++ b/text/0000-build-std/1-background.md @@ -64,11 +64,13 @@ 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 the standard library with -a `path` source (e.g. `core = { path = "../my_core" }`), but crates with these -dependencies are not accepted by crates.io. 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. +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 From 69df4d561c44f87f0f937e08914abb0c117b6b1f Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 21 Aug 2025 11:53:31 +0100 Subject: [PATCH 81/96] Fix heading levels --- text/0000-build-std/4-stage-1a.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 55abbdae8ba..feedcd66f75 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -620,7 +620,7 @@ See ↩ [*Proposal*][proposal] -### Why not build the standard library in incremental? +## Why not build the standard library in incremental? [rationale-incremental]: #why-not-build-the-standard-library-in-incremental The standard library sources are not intended to be modified locally, similarly @@ -630,7 +630,7 @@ change. ↩ [*Proposal*][proposal] -### Why not produce a `dylib` for the standard library? +## Why not produce a `dylib` for the standard library? [rationale-no-dylib]: #why-not-produce-a-dylib-for-the-standard-library The standard library supports being built as both a `rlib` and a `dylib` and @@ -709,7 +709,7 @@ on the `std`, and so it is not proposed in this RFC. ↩ [*Interactions with `#![no_std]`*][interactions-with-no_std] -### Why remove `restricted_std`? +## Why remove `restricted_std`? [rationale-remove-restricted-std]: #why-remove-restricted_std `restricted_std` was originally added as part of a mechanism to enable the @@ -729,7 +729,7 @@ layer, but this mechanism does not use `restricted_std`. ↩ [*`restricted_std`*][restricted_std] -### Why disallow custom targets? +## Why disallow custom targets? [rationale-disallow-custom-targets]: #why-disallow-custom-targets While custom targets can be used on stable today, in practice, they are only @@ -745,7 +745,7 @@ stable is covered in [rust#71009]. ↩ [*Custom targets*][custom-targets] -### Why prevent rustc from loading root dependencies from the sysroot? +## Why prevent rustc from loading root dependencies from the sysroot? [rationale-root-sysroot-deps]: #why-prevent-rustc-from-loading-root-dependencies-from-the-sysroot Loading root dependencies from the sysroot could be a source of bugs. @@ -777,7 +777,7 @@ providing an empty path. ↩ [*Preventing implicit sysroot dependencies*][preventing-implicit-sysroot-dependencies] -### Why use `noprelude` with `--extern`? +## Why use `noprelude` with `--extern`? [rationale-noprelude-with-extern]: #why-use-noprelude-with---extern rustc's existing behaviour of implicitly loading `std` and adding it to the @@ -794,7 +794,7 @@ the user. ↩ [*Preventing implicit sysroot dependencies*][preventing-implicit-sysroot-dependencies] -### Why not allow the source path for the standard library be customised? +## Why not allow the source path for the standard library be customised? [rationale-custom-src-path]: #why-not-allow-the-source-path-for-the-standard-library-be-customised It is not a goal of this proposal to enable or improve the usability of custom @@ -802,7 +802,7 @@ or modified standard libraries. ↩ [*Vendored `rust-src`*][vendored-rust-src] -### Why vendor the standard library's dependencies? +## Why vendor the standard library's dependencies? [rationale-vendoring]: #why-vendor-the-standard-librarys-dependencies Vendoring the standard library is possible since it currently has its own @@ -842,7 +842,7 @@ See ↩ [*Vendored `rust-src`*][vendored-rust-src] -### Why not check if `rust-src` has been modified? +## Why not check if `rust-src` has been modified? [rationale-src-modifications]: #why-not-check-if-rust-src-has-been-modified This is in line with other immutable dependency sources (like registry or git). @@ -855,7 +855,7 @@ included. ↩ [*Vendored `rust-src`*][vendored-rust-src] -### Why allow building from the sysroot with implied `RUSTC_BOOTSTRAP`? +## Why allow building from the sysroot with implied `RUSTC_BOOTSTRAP`? [rationale-implied-bootstrap]: #why-allow-building-from-the-sysroot-with-implied-rustc_bootstrap Cargo needs to be able to build the standard library crates, which inherently @@ -875,7 +875,7 @@ special-case all of these crates. ↩ [*Building the standard library on a stable toolchain*][building-the-standard-library-on-a-stable-toolchain] -### Why invert the `mem` feature? +## Why invert the `mem` feature? [rationale-no-mem]: #why-invert-the-mem-feature Currently the `mem` feature is enabled for `no_std` platforms in the @@ -891,7 +891,7 @@ This shows that the `mem` feature is actually the wrong way around. ↩ [*`compiler-builtins-mem`*][compiler-builtins-mem] -### Why not use weak linkage for `compiler-builtins/mem` symbols? +## Why not use weak linkage for `compiler-builtins/mem` symbols? [rationale-no-weak-linkage]: #why-not-use-weak-linkage-for-compiler-builtinsmem-symbols Since [compiler-builtins#411], the relevant symbols in `compiler_builtins` @@ -905,7 +905,7 @@ has precedence over shared libraries and the symbols of a dynamically-linked ↩ [*`compiler-builtins-mem`*][compiler-builtins-mem] -### Why not globally cache builds of the standard library? +## Why not globally cache builds of the standard library? [rationale-caching]: #why-not-globally-cache-builds-of-the-standard-library The standard library is no different than regular dependencies in being able to From c3896226f7983658b04096b7fa0f67f2f3030a57 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 21 Aug 2025 14:13:32 +0100 Subject: [PATCH 82/96] Add unresolved question for rust-src --- text/0000-build-std/4-stage-1a.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index feedcd66f75..0c4f96c1da2 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -231,6 +231,10 @@ of standard library dependencies will not need be fetched from crates.io. - [*Why vendor standard library dependencies?*][rationale-vendoring] - [*Why not check if `rust-src` has been modified?*][rationale-src-modifications] +*See the following sections for relevant unresolved questions:* + +- [*Should `rust-src` be a default component?*][unresolved-rust-src] + ## Panic strategies [panic-strategies]: #panic-strategies @@ -966,6 +970,19 @@ that every stable target modifier be exposed via Cargo to be usable in practice. ↩ [*Proposal*][proposal] +## Should `rust-src` be a default component? +[unresolved-rust-src]: #should-rust-src-be-a-default-component + +Ensuring `rust-src` is a default component reduces friction for users, and CI, +who have to otherwise need to install the component manually the first time they +use `build-std`. + +On the other hand this increases their storage and bandwidth costs, plus +bandwidth costs for the project. The impact on usability is limited for the user +to once per toolchain as the component persists through updates. + +↩ [*Vendored rust-src*][vendored-rust-src] + # Future possibilities [future-possibilities]: #future-possibilities From 316520d9ba73a1e1a89781122549f6d404bf769c Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 21 Aug 2025 14:38:59 +0100 Subject: [PATCH 83/96] Improve "standard library" terminology --- text/0000-build-std/0-introduction.md | 9 +++++---- text/0000-build-std/4-stage-1a.md | 6 +++--- text/0000-build-std/5-stage-1b.md | 11 +++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/text/0000-build-std/0-introduction.md b/text/0000-build-std/0-introduction.md index aa2499e923a..ffb5b4f6426 100644 --- a/text/0000-build-std/0-introduction.md +++ b/text/0000-build-std/0-introduction.md @@ -144,10 +144,11 @@ Thanks to [Jacob Bramley][jacobbramley] for their feedback on early drafts. The following terminology is used throughout the RFC: -- "the standard library" is used to refer to all of the crates that comprise the - standard library - `core`, `alloc` and `std` -- "std" is used to refer only to the `std` crate, not the entirety of the standard - library +- "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 RFC's "Proposal" sections, parentheses with "?" links will be present that which link the relevant section in the appropriate "Rationale and diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 0c4f96c1da2..6bc252a6957 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -46,7 +46,7 @@ respect the `RUSTFLAGS` environment variable. Alongside `build-std`, a `build-std-crate` key will be introduced ([?][rationale-build-std-crate]), which can be used to specify which crates from -the standard library is to be built. Only "core", "alloc" and "std" are valid +the standard library are to be built. Only "core", "alloc" and "std" are valid values for `build-std-crate`. ```toml @@ -147,8 +147,8 @@ extern prelude. ## `restricted_std` [restricted_std]: #restricted_std -The existing `restricted_std` mechanism will be removed from the standard -library's [`build.rs`][std-build.rs]. +The existing `restricted_std` mechanism will be removed from `std`'s +[`build.rs`][std-build.rs]. *See the following sections for rationale/alternatives:* diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index b96cf4102fb..1a45074afbc 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -173,7 +173,7 @@ crates.io. ## Patches [patches]: #patches -Under a perma-unstable feature it is permitted to patch the standard library +Under a perma-unstable feature it is permitted to patch standard library dependencies with `path` and `git` sources (or any other source) ([?][rationale-patching]): @@ -198,7 +198,7 @@ As with dependencies, crates with `path`/`git` patches for `core`, `alloc` or *See the following sections for rationale/alternatives:* -- [*Why unstably permit patching of the standard library dependencies?*][rationale-patching] +- [*Why unstably permit patching of standard library dependencies?*][rationale-patching] *See the following sections for relevant unresolved questions:* @@ -626,10 +626,9 @@ added manually by users, however: [rationale-unstable-builtin-crates]: #why-unstably-allow-all-names-for-builtin-crates For any crate shipped with the standard library in the sysroot, the user can -already write an `extern crate` declaration to use it. All crates other than -`std`, `alloc` or `core` are marked unstable either explicitly or implicitly -with the use of `-Zforce-unstable-if-unmarked` so this does not allow items from -these crates to be used on stable. +already write an `extern crate` declaration to use it. Most are marked unstable +either explicitly or implicitly with the use of `-Zforce-unstable-if-unmarked` +so this does not allow items from these crates to be used on stable. For example, some users write benchmarks using `libtest` and have written `extern crate test` without the `#[cfg(test)]` attribute to load the crate. From 4114fef43976ebe38aee75034417b72b35ede4a5 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 21 Aug 2025 14:53:18 +0100 Subject: [PATCH 84/96] Expand on rustup approach drawbacks --- text/0000-build-std/0-introduction.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/text/0000-build-std/0-introduction.md b/text/0000-build-std/0-introduction.md index ffb5b4f6426..99e2a4edd04 100644 --- a/text/0000-build-std/0-introduction.md +++ b/text/0000-build-std/0-introduction.md @@ -307,22 +307,25 @@ need. [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 lots of existing machinery -to create and maintain sysroots. rustup knows how to download `rust-src`, it -knows how to create a new toolchain from an existing sysroot (as in -`rustup toolchain link`), it would only need to learn how to invoke Cargo on the -`rust-src` sources. 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). +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 +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. +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. [davidtwco]: https://github.com/davidtwco [adamgemmell]: https://github.com/adamgemmell From d9a21cb39fe24f09a7e0e1227a4a736d57397e84 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 21 Aug 2025 15:23:22 +0100 Subject: [PATCH 85/96] Clarify standard library vs std --- text/0000-build-std/1-background.md | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/text/0000-build-std/1-background.md b/text/0000-build-std/1-background.md index 6b2e15ea084..267baf8f383 100644 --- a/text/0000-build-std/1-background.md +++ b/text/0000-build-std/1-background.md @@ -15,17 +15,17 @@ 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 support the standard library or have a pre-built standard -library distributed via rustup. This depends on the tier of support for the -target. According to rustc's [platform support][platform-support] documentation, -for tier three targets: +- 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 @@ -44,6 +44,11 @@ for tier three targets: > 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. From fa41db649b439c0bb4fc771ea616ee526fb02f29 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 21 Aug 2025 17:00:28 +0100 Subject: [PATCH 86/96] Add small introduction to each section listing motivations solved --- text/0000-build-std/0-introduction.md | 2 +- text/0000-build-std/4-stage-1a.md | 12 ++++++++++++ text/0000-build-std/5-stage-1b.md | 13 +++++++++++++ text/0000-build-std/6-stage-2.md | 13 +++++++++++-- text/0000-build-std/7-stage-3.md | 8 ++++++++ 5 files changed, 45 insertions(+), 3 deletions(-) diff --git a/text/0000-build-std/0-introduction.md b/text/0000-build-std/0-introduction.md index 99e2a4edd04..d12b3513395 100644 --- a/text/0000-build-std/0-introduction.md +++ b/text/0000-build-std/0-introduction.md @@ -213,7 +213,7 @@ context for the proposals of earlier stages. - Proposes adding a `build-std = "always|never"` option to the Cargo configuration which will unconditionally re-build the standard library - crates listed in the `build-std-crates` option + crates listed in a new `build-std-crates` option - [Proposal](./4-stage-1a.md#proposal) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 6bc252a6957..172b8955d0a 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -1,3 +1,15 @@ +# Stage 1a: `build-std=always` + +This stage proposes adding a `build-std = "always|never"` option to the Cargo +configuration which will unconditionally re-build the standard library crates +listed in a new `build-std-crates` option. + +This is aimed at supporting the following [motivations](./3-motivation.md): + +- Building the standard library on a stable toolchain without Cargo +- Building standard library crates that are not shipped for a target +- Using the standard library with tier three targets + # Proposal [proposal]: #proposal diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 1a45074afbc..ce339fe3b6b 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -1,3 +1,16 @@ +# Stage 1b: Explicit dependencies + +This stage proposes supporting explicit dependencies on the standard library +crates in `Cargo.toml`. This enables Cargo to determine which standard library +crates are required by the crate graph without `build-std-crates` being set and +for different crates to require different standard library crates. + +While not directly necessary for our core listed motivations, this stage allows +future extensions which support public/private standard library dependencies or +enabling features of the standard library. Allowing the standard library to +behave similarly to other dependencies reduces user friction and can improve +build times. + # Proposal [proposal]: #proposal diff --git a/text/0000-build-std/6-stage-2.md b/text/0000-build-std/6-stage-2.md index 9d72f19a47a..34ca873224c 100644 --- a/text/0000-build-std/6-stage-2.md +++ b/text/0000-build-std/6-stage-2.md @@ -1,3 +1,13 @@ +# Stage 2: `build-std=compatible` + +This stage proposes extending the `build-std` option with a new `compatible` +value, which will become the default and automatically rebuild the standard +library when it is necessary to maintain compatibility with the compiler flags +used by the rest of the crate graph. + +This is aimed at unblocking the stabilisation of ABI-modifying compiler flags +(as per [motivations](./3-motivation.md)). + # Proposal [proposal]: #proposal @@ -40,8 +50,7 @@ incompatible with the rest of the crate (due to use of target modifiers). The standard library will be rebuilt in its release profile and will only vary in the target modifier flags necessarily for it to be compatible -([?][rationale-release-profile]). This is primarily useful for prospective users -of target modifier flags. +([?][rationale-release-profile]). Pre-built available? | User's profile | Target modifiers changed? | Standard library re-built? -------------------- | -------------- | ------------------------- | -------------------------- diff --git a/text/0000-build-std/7-stage-3.md b/text/0000-build-std/7-stage-3.md index ae3a4b60a1d..0881ba28f18 100644 --- a/text/0000-build-std/7-stage-3.md +++ b/text/0000-build-std/7-stage-3.md @@ -1,3 +1,11 @@ +# Stage 3: `build-std=match-profile` + +This stage proposes extending the `build-std` option with new values which +automatically rebuild the standard library to match the user's current profile. + +This is aimed at allowing users to rebuild the standard library with different +codegen flags or profile (as per [motivations](./3-motivation.md)). + # Proposal [proposal]: #proposal From 1d4d8cd7aa1bd70fba2d0ab502b882f5acf8b006 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 21 Aug 2025 17:09:16 +0100 Subject: [PATCH 87/96] Mention -Zcrate-attrs wrt restricted_std --- text/0000-build-std/1-background.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/text/0000-build-std/1-background.md b/text/0000-build-std/1-background.md index 267baf8f383..4b0e105e404 100644 --- a/text/0000-build-std/1-background.md +++ b/text/0000-build-std/1-background.md @@ -148,14 +148,15 @@ conditional compilation [configuration options][conditional-compilation-config-o 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. +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. There is no mechanism for users to enable the `restricted_std` -feature on behalf of dependencies. There is also no such mechanism for `alloc` -or `core`, only `std`. +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 From 5077aa8ed8e8a1d483c001900cf52409f37d47b8 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 21 Aug 2025 17:21:01 +0100 Subject: [PATCH 88/96] Mention that features aren't additive --- text/0000-build-std/1-background.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/text/0000-build-std/1-background.md b/text/0000-build-std/1-background.md index 4b0e105e404..a9729e0f8e4 100644 --- a/text/0000-build-std/1-background.md +++ b/text/0000-build-std/1-background.md @@ -129,11 +129,12 @@ language features only when they are a dependency of the standard library. [background-features]: #features There are a handful of features defined in the standard library crates' -`Cargo.toml`s. 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. +`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 From 0341199e48b0d36b0e8600c546de488518467b74 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 28 Aug 2025 11:30:06 +0100 Subject: [PATCH 89/96] Various background/history refinements --- text/0000-build-std/1-background.md | 28 +++++++++++++++------------- text/0000-build-std/2-history.md | 6 ++++-- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/text/0000-build-std/1-background.md b/text/0000-build-std/1-background.md index a9729e0f8e4..9937778d22d 100644 --- a/text/0000-build-std/1-background.md +++ b/text/0000-build-std/1-background.md @@ -17,7 +17,7 @@ rationale: 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` + - 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 @@ -99,8 +99,8 @@ 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]) - there are still some C -dependencies: +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 @@ -214,15 +214,16 @@ a function annotated with `#[panic_handler]`. There can only be one (e.g. arithmetic overflow or out-of-bounds access) and the `core::panic!` macro immediately delegates to the panic handler crate. -`std` is also a panic handler. `std`'s panic handler and `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*. +`std` is also 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` and -`panic_abort` - each with a corresponding panic strategy. 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). +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 @@ -241,8 +242,9 @@ on the `panic_unwind` crate. `core` also has a `panic_immediate_abort` feature which modifies the `core::panic!` macro to immediately call the abort intrinsic without calling the -panic handler. `std` and `alloc` have the same feature which enable the feature -in `core`. `std`'s feature also adds an immediate abort to its `panic!` macro. +panic handler, which can dramatically reduce code size. `std` and `alloc` have +the same feature which enable the feature in `core`. `std`'s feature also adds +an immediate abort to its `panic!` macro. ## Cargo [background-cargo]: #cargo diff --git a/text/0000-build-std/2-history.md b/text/0000-build-std/2-history.md index 20c56aae3d9..d3224b56275 100644 --- a/text/0000-build-std/2-history.md +++ b/text/0000-build-std/2-history.md @@ -171,8 +171,10 @@ categories: 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. + 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 From 84827c34519529c9bf87bd7d4b949e21915ede30 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 28 Aug 2025 12:11:17 +0100 Subject: [PATCH 90/96] Cargo config is not just in the home directory --- text/0000-build-std/4-stage-1a.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 172b8955d0a..ab8658578cf 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -1,7 +1,7 @@ # Stage 1a: `build-std=always` This stage proposes adding a `build-std = "always|never"` option to the Cargo -configuration which will unconditionally re-build the standard library crates +configuration which will unconditionally rebuild the standard library crates listed in a new `build-std-crates` option. This is aimed at supporting the following [motivations](./3-motivation.md): @@ -37,9 +37,9 @@ The `build-std` configuration locations have the following precedence 2. `[target.]` 3. `[build]` -As the Cargo configuration is local to the current installation of Cargo -(typically in `~/.config/cargo`), the value of `build-std` is not influenced by -the dependencies of the current crate. +As the Cargo configuration is local to the current user (typically in +`.config/cargo.toml` in the project root and/or Cargo home directory), the value +of `build-std` is not influenced by the dependencies of the current crate. When `build-std` is set to "always", then the standard library will be unconditionally recompiled ([?][rationale-unconditional]) in the release profile From 7e38b8abb8b671e91bd8afaffd77b7d0517bc659 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Fri, 29 Aug 2025 15:29:00 +0100 Subject: [PATCH 91/96] Change build-std-crates' definition --- text/0000-build-std/4-stage-1a.md | 38 +++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index ab8658578cf..f94de1cc214 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -58,21 +58,24 @@ respect the `RUSTFLAGS` environment variable. Alongside `build-std`, a `build-std-crate` key will be introduced ([?][rationale-build-std-crate]), which can be used to specify which crates from -the standard library are to be built. Only "core", "alloc" and "std" are valid -values for `build-std-crate`. +the standard library are dependencies of the current project. Only "core", +"alloc" and "std" are valid values for `build-std-crate`. ```toml [build] build-std-crate = "std" ``` -If [*Stage 1b* of this proposal][stage1b] is implemented then `build-std-crate` -will not be used unless explicitly set and the crate graph's dependencies on the -standard library will determine which crates are built instead. Otherwise, -`build-std-crate` will default to "std". +A value of "std" means that every crate in the graph has a direct dependency on +`std`, `alloc` and `core`. Similarly, "alloc" means `alloc` and `core`, and +"core" means just `core`. + +If [*Stage 1b* of this proposal][stage1b] is implemented then `builtin` +dependencies will be used if `build-std-crates` is not explicitly set. +Otherwise, `build-std-crate` will default to "std". If `std` is to be built and Cargo is building a test using the default test -harness then Cargo will also build the `test` crate. +harness then Cargo will also add the `test` crate as a dependency. > [!NOTE] > @@ -88,14 +91,14 @@ harness then Cargo will also build the `test` crate. > the dependencies of the `core`, `alloc` or `std` standard library crates > individually (via profile overrides, for example). > -> - The profile defined by the standard library will be used. +> - The release profile defined by the standard library will be used. > > Cargo will resolves the dependencies of opaque dependencies, such as the > standard library, separately in their own workspaces. The root of such a -> resolve will be the crate specified in `build-std-crates`, or, if stage 1b is +> resolve will be the crates specified in `build-std-crates` or, if stage 1b is > implemented, the unified set of packages that any crate in the dependency has > a direct dependency on. A dependency on the relevant roots are added to all -> crates in the "parent" resolve. +> crates in the main resolve. > > Regardless of which standard library crates are being built, Cargo will build > the `sysroot` crate of the standard library workspace. `alloc` and `std` will @@ -144,6 +147,10 @@ target in the project. - [*What should `build-std-crate` be named?*][unresolved-build-std-crate-name] - [*Should the standard library inherit RUSTFLAGS?*][unresolved-inherit-rustflags] +*See the following sections for future possibilities:* + +- [*Allow reusing sysroot artifacts if available*][future-reuse-sysroot] + ## Interactions with `#![no_std]` [interactions-with-no_std]: #interactions-with-no_std @@ -1000,6 +1007,17 @@ to once per toolchain as the component persists through updates. There are many possible follow-ups to Stage 1a: +## Allow reusing sysroot artifacts if available +[future-reuse-sysroot]: #allow-reusing-sysroot-artifacts-if-available + +This stage proposes rebuilding all required crates unconditionally as this fits +Cargo's existing compilation model better. However, just building a crate +equivalent to one already in the sysroot is inefficient. Cargo could learn when +to reuse artifacts in the sysroot when equivalent to ones it intends to build, +but this is complex enough to warrant its own proposal if desired. + +↩ [*Proposal*][proposal] + ## Allow custom targets with build-std [future-custom-targets]: #allow-custom-targets-with-build-std From ebe0fb6193f799102609a9b4105398160e1f9603 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Fri, 29 Aug 2025 15:35:32 +0100 Subject: [PATCH 92/96] Fix typo --- text/0000-build-std/4-stage-1a.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index f94de1cc214..9a1d36c10ff 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -267,7 +267,7 @@ If Cargo is not building `std`, then neither of the panic runtimes will be built. In this circumstance rustc will continue to throw an error when a unwinding panic strategy is chosen. -If the Cargo would build `std` for a project then Cargo's behaviour depends on +If Cargo would build `std` for a project then Cargo's behaviour depends on whether or not `panic` is set in the profile: - If `panic` is not set in the profile then unwinding may still be the default From 9f7506176861350250e3894ca6199f501e19e9c1 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Fri, 29 Aug 2025 17:39:01 +0100 Subject: [PATCH 93/96] Correct extern prelude vs extern crate --- text/0000-build-std/1-background.md | 10 +++++----- text/0000-build-std/4-stage-1a.md | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/text/0000-build-std/1-background.md b/text/0000-build-std/1-background.md index 9937778d22d..3d9a484378e 100644 --- a/text/0000-build-std/1-background.md +++ b/text/0000-build-std/1-background.md @@ -173,11 +173,11 @@ configuration options. ## Prelude [background-prelude]: #prelude -rustc has the concept of the "extern prelude" which are the set of crates that -have been loaded by the compiler as direct dependencies. 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 -automatically loaded and added to the extern prelude. +rustc has the concept of the "extern prelude" which is effectively 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 automatically loaded and added to the extern prelude. `std` is automatically loaded and added to the extern prelude. For `#![no_std]` crates, `core` is loaded and added to the extern prelude instead. For `std` or diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 9a1d36c10ff..ca281053686 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -808,12 +808,12 @@ extern prelude will not be changed as part of this RFC. Adding The `noprelude` modifier for `--extern` is necessary for use of the `--extern` flag to be equivalent to loading from a sysroot. -Without `noprelude`, rustc implicitly inserts a `extern crate $name` when using +Without `noprelude`, rustc adds crates to the extern prelude when passed in with `--extern`. As a consequence, if a newly-built `alloc` were passed using `--extern alloc=alloc.rlib` then `extern crate alloc` would not be required to -use the locally-built `alloc`, but it would be to use the pre-built `alloc`. This -difference in how a crate is made available to rustc should not be observable to -the user. +use the locally-built `alloc`, but it would be to use the pre-built `alloc`. +This difference in how a crate is made available to rustc should not be +observable to the user. ↩ [*Preventing implicit sysroot dependencies*][preventing-implicit-sysroot-dependencies] From 115b0b3f0d0a26fefedccf05f8ef09e36bc922ee Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Tue, 23 Sep 2025 11:56:34 +0100 Subject: [PATCH 94/96] Pass explicit dependencies without noprelude --- text/0000-build-std/1-background.md | 10 +++--- text/0000-build-std/4-stage-1a.md | 27 ++++++++------- text/0000-build-std/5-stage-1b.md | 54 ++++++++++++++++------------- 3 files changed, 47 insertions(+), 44 deletions(-) diff --git a/text/0000-build-std/1-background.md b/text/0000-build-std/1-background.md index 3d9a484378e..2079c9649f8 100644 --- a/text/0000-build-std/1-background.md +++ b/text/0000-build-std/1-background.md @@ -177,13 +177,11 @@ rustc has the concept of the "extern prelude" which is effectively 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 automatically loaded and added to the extern prelude. +`--extern` added to the extern prelude. `core` is always added to the extern +prelude. For crates without `#![no_std]`, `std` is added to the extern prelude. -`std` is automatically loaded and added to the extern prelude. For `#![no_std]` -crates, `core` is loaded and added to the extern prelude instead. For `std` or -`core` as appropriate, an additional `use $crate::prelude::rust_20XX::*` is -injected for common items that Rust does not require users import (e.g. -`Option`). +The `core` or `std` prelude is added (depending on the presence of `#![no_std]`) +in the form of 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 diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index ca281053686..7626865234a 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -212,8 +212,8 @@ top-level dependencies from the sysroot ([?][rationale-root-sysroot-deps]). > rustc could add a `--no-implicit-sysroot-deps` flag with this behaviour. For > example, writing `extern crate foo` in a crate will not load `foo.rlib` from > the sysroot if it is present, but if an `--extern noprelude:bar.rlib` is -> provided which depends on a crate `foo`, rustc will look in `-L` paths and the -> sysroot for it. +> provided which depends on a crate `foo`, rustc will look in +> `-L dependency=...` paths and the sysroot for it. All Cargo dependencies are provided to the compiler using the `--extern noprelude:` flag ([?][rationale-noprelude-with-extern]), including @@ -803,17 +803,17 @@ providing an empty path. ## Why use `noprelude` with `--extern`? [rationale-noprelude-with-extern]: #why-use-noprelude-with---extern -rustc's existing behaviour of implicitly loading `std` and adding it to the -extern prelude will not be changed as part of this RFC. Adding The `noprelude` -modifier for `--extern` is necessary for use of the `--extern` flag to be -equivalent to loading from a sysroot. +Using `noprelude` allows `build-std` to closer match rustc's behaviour when it +loads crates from the sysroot. Without `noprelude`, rustc adds `--extern` crates +to the extern prelude. As a consequence, if a newly-built `alloc` were passed +using `--extern alloc=alloc.rlib` then `extern crate alloc` would not be +required to use the locally-built `alloc`, but it would be to use the pre-built +`alloc`. This difference in how a crate is made available to rustc should not be +observable to the user as they have not opted into the migration. -Without `noprelude`, rustc adds crates to the extern prelude when passed in with -`--extern`. As a consequence, if a newly-built `alloc` were passed using -`--extern alloc=alloc.rlib` then `extern crate alloc` would not be required to -use the locally-built `alloc`, but it would be to use the pre-built `alloc`. -This difference in how a crate is made available to rustc should not be -observable to the user. +Passing crates without `noprelude` with the existing prelude behaviour has also +been a source of [bugs][wg-cargo-std-aware-40] in previous `-Zbuild-std` +implementations. ↩ [*Preventing implicit sysroot dependencies*][preventing-implicit-sysroot-dependencies] @@ -1105,4 +1105,5 @@ build-std could build both the `dylib` and `rlib` of the standard library. [cargo-update]: https://doc.rust-lang.org/cargo/commands/cargo-update.html [cargo-vendor]: https://doc.rust-lang.org/cargo/commands/cargo-vendor.html [cargo-version]: https://doc.rust-lang.org/cargo/commands/cargo-version.html -[cargo-yank]: https://doc.rust-lang.org/cargo/commands/cargo-yank.html \ No newline at end of file +[cargo-yank]: https://doc.rust-lang.org/cargo/commands/cargo-yank.html +[wg-cargo-std-aware#40]: https://github.com/rust-lang/wg-cargo-std-aware/issues/40 \ No newline at end of file diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index ce339fe3b6b..fb629c2064f 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -36,36 +36,29 @@ named `core`, `alloc` or `std` ([?][rationale-no-builtin-other-crates]) on stable. Use with any crate name is gated on a perma-unstable `cargo-feature` ([?][rationale-unstable-builtin-crates]). +> [!NOTE] +> +> Explicit dependencies are passed to rustc with `--extern` and without the +> `noprelude` modifier and rustc will no longer insert `extern crate` +> declarations for `core` or `std` when it sees them passed in without the +> `noprelude` modifier ([?][rationale-explicit-noprelude]). This means users +> migrating to explicit builtin dependencies may need to migrate code by +> adjusting any root-relative references (like `::std`) that relied on +> previously-present `extern crate` statements. + Crates without an explicit dependency on the standard library now have a implicit dependency ([?][rationale-no-migration]) on `std`, `alloc` and `core`. -In the `hello_world` crate below, there are no explicit `builtin` dependencies.. - -```toml -[package] -name = "hello_world" -version = "0.1.0" -edition = "2024" - -[dependencies] -``` - -..which is equivalent to the following explicit dependencies: - -```toml -[package] -name = "hello_world" -version = "0.1.0" -edition = "2024" - -[dependencies] -std = { builtin = true } -alloc = { builtin = true } -core = { builtin = true } -``` - Any explicit `builtin` dependency present in the manifest will disable the implicit dependencies. +> [!NOTE] +> +> Implicit dependencies are passed to rustc with the `--extern` `noprelude` +> modifier to ensure backwards compatibility as in [stage1a][stage1a-noprelude]. +> This means that while implicit and explicit dependencies are equivalent during +> resolution Cargo must maintain a distinction between them that allows the +> `noprelude` modifier to be correctly passed. + When a `std` dependency is present an additional implicit dependency on the `test` crate is added for crates that are being tested with the default test harness. The `test` crate's name, but not its interface, will be stabilised so @@ -653,6 +646,16 @@ hardcode the names of many crates in the sysroot which are inherently unstable. ↩ [*Proposal*][proposal] +## Why not use `noprelude` for explicit `builtin` dependencies +[rationale-explicit-noprelude]: #why-not-use-noprelude-for-explicit-builtin-dependencies + +Moving away from `noprelude` for explicit dependencies means that they are more +consistent with other dependencies specified in the `Cargo.toml`. This does make +them less consistent with implicit dependencies, though the standard library is +today already inconsistent with explicit dependencies. + +↩ [*Proposal*][proposal] + ## Why not require builtin dependencies instead of supporting implicit ones? [rationale-no-migration]: #why-not-require-builtin-dependencies-instead-of-supporting-implicit-ones @@ -961,6 +964,7 @@ user can enable `compiler-builtins/c`, they will need to manually configure [panic-strategies]: ./4-stage-1a.md#panic-strategies [compiler-builtins-mem]: ./4-stage-1a.md#compiler-builtinsmem +[stage1a-noprelude]: ./4-stage-1a.md#why-use-noprelude-with---extern [cargo-add]: https://doc.rust-lang.org/cargo/commands/cargo-add.html [cargo-bench]: https://doc.rust-lang.org/cargo/commands/cargo-bench.html From 8cda9c64ff223c889329479bc91eb1178aca249b Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Tue, 23 Sep 2025 17:54:00 +0100 Subject: [PATCH 95/96] Plan for no_std removal --- text/0000-build-std/4-stage-1a.md | 3 ++- text/0000-build-std/5-stage-1b.md | 45 ++++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/text/0000-build-std/4-stage-1a.md b/text/0000-build-std/4-stage-1a.md index 7626865234a..1ca22386464 100644 --- a/text/0000-build-std/4-stage-1a.md +++ b/text/0000-build-std/4-stage-1a.md @@ -157,7 +157,8 @@ target in the project. Behaviour of crates using `#![no_std]` will not change whether or not `std` is rebuilt and passed via `--extern` to rustc, and `#![no_std]` will still be required in order for `rustc` to not attempt to load `std` and add it to the -extern prelude. +extern prelude. [Stage 1b][stage1b] proposes a mechanism that supercedes +`#![no_std]`. *See the following sections for rationale/alternatives:* diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index fb629c2064f..33ab15923eb 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -139,7 +139,7 @@ files ([?][rationale-cargo-lock]). *See the following sections for future possibilities:* -- [*Warn when `no_std` crates accidentally have a dependency on `std`*][future-no_std-warning] +- [*Deprecating `#![no_std]`*][future-deprecating-nostd] - [*Allow `builtin` source replacement*][future-source-replacement] - [*Remove `rustc_dep_of_std`*][future-rustc_dep_of_std] @@ -881,14 +881,41 @@ would be desirable. There are many possible follow-ups to Stage 1b: -## Warn when `no_std` crates accidentally have a transitive dependency on `std` -[future-no_std-warning]: #warn-when-no_std-crates-accidentally-have-a-transitive-dependency-on-std - -Cargo could emit a warning or lint when a root crate without an explicit -dependency on `std` or `alloc` has a dependency on `std` or `alloc` via a -dependency. When writing a `no_std` crate, then it is desirable to avoid any -unexpected dependency on standard library crates and this would cause the crate -to fail to compile on targets where those crates are not supported. +## Deprecating `#![no_std]` +[future-deprecating-nostd]: #deprecating-no_std + +The `#![no_std]` attribute does 4 things: + +1. Change the `extern crate std/core` declaration injected in the crate root +2. Decides whether `std` is added to the extern prelude +3. Chooses the standard library prelude to be used +4. Ensures rustc throws an error if a crate without `#![no_std]` is depended on. + +Points 1 and 2 are not an issue as explicit builtins will not have +`extern crate` declarations inserted and are added to the extern prelude when +passed with `--extern` without the `noprelude` modifier. + +For 3, a new rustc flag, say `--extern-stdlib`, could be added which changes +rustc to use the standard library crates present as `--extern` to decide which +prelude to import. The `#![no_std]` attribute would have to remain in order to +avoid raising the `rust-version` of the crate. It's behaviour if present would +be to prevent the use of the `std` prelude as this reduces the chance of a user +accidentally breaking older versions of the toolchain that do not use builtin +dependencies. + +For 4, Cargo could emit a warning or lint when a root crate without an explicit +dependency on `std` has a dependency on it via a dependency. When writing a +`no_std` crate, then it is desirable to avoid any unexpected dependency on +standard library crates and this would cause the crate to fail to compile on +targets where those crates are not supported. + +Once these points are in place Rust could then make `#![no_std]` deprecated on +a new edition. + +Cargo could also add a perma-unstable `no-implicit-builtins` feature to allow +users to have 0 builtin dependencies, which will allow `#![no_core]` users to +avoid unnecessary `core` dependencies. `#![no_core]` should still be required in +the user's crate in order to ensure that they are on an unstable toolchain. ↩ [*Proposal*][proposal] From 3b04dffb0a43251a04f1e79cea08b8548cf18803 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Tue, 23 Sep 2025 18:29:40 +0100 Subject: [PATCH 96/96] Explicitly disallow overriding dependencies except through patch --- text/0000-build-std/5-stage-1b.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/text/0000-build-std/5-stage-1b.md b/text/0000-build-std/5-stage-1b.md index 33ab15923eb..629741e7c5d 100644 --- a/text/0000-build-std/5-stage-1b.md +++ b/text/0000-build-std/5-stage-1b.md @@ -92,7 +92,9 @@ optional `alloc` and non-optional `core`). `core` cannot be optional. Dependencies with `builtin = true` cannot be renamed with the `package` key ([?][rationale-package-key]). It is not possible to perform source replacement on the `builtin` source using the `[source]` Cargo config table -([?][rationale-source-replacement]). +([?][rationale-source-replacement]), and nor is it possible to override +`builtin` dependencies with the `[replace]` sections or `paths` overrides +([?][rationale-overriding-builtins]), though [patching][patches] is permitted. Dependencies with `builtin = true` can be specified as platform-specific dependencies: @@ -715,6 +717,14 @@ See [*Allow `builtin` source replacement*][future-source-replacement]. ↩ [*Proposal*][proposal] +## Why not permit overriding dependencies with `replace` or `paths`? +[rationale-overriding-builtins]: #why-not-permit-overriding-dependencies-with-replace-or-paths + +For similar reasons to [source replacement][rationale-source-replacement] this +is considered out-of-scope for this proposal. + +↩ [*Proposal*][proposal] + ## Why add standard library dependencies to `Cargo.lock`? [rationale-cargo-lock]: #why-add-standard-library-dependencies-to-cargolock