forked from rust-lang/rfcs
-
Notifications
You must be signed in to change notification settings - Fork 0
build-std: context #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 2 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
c7e099a
build-std: context
davidtwco a68f085
history: correct default crate built
davidtwco 3d9b399
background: clarify stability of custom targets
davidtwco 0c97a21
background: mention `path`/`git` sources
davidtwco 8765bc5
motivation: clarify these won't all be addressed
davidtwco 64bd0ab
history: clarify `libunwind` source
adamgemmell a3e92e6
background: clarify not all crates in registry
davidtwco a99cd20
history: s/virtual/in-memory
davidtwco 786c925
background: split into support/later/won't support
davidtwco c740a18
background: addl. cargo registry information
davidtwco 7163810
history: mention `no_std` usability issues
davidtwco 396138b
background: user crates use features for std
davidtwco File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
davidtwco marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| 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 | ||
davidtwco marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| are, etc. crates.io's registry index is a Git repository - | ||
| [rust-lang/crates.io-index] - which is updated automatically by crates.io when | ||
davidtwco marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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. | ||
davidtwco marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ### 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 | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.