-
Notifications
You must be signed in to change notification settings - Fork 1.6k
build-std: explicit dependencies #3875
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
base: master
Are you sure you want to change the base?
build-std: explicit dependencies #3875
Conversation
| ..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 } | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I think this is a sensible default, I think there should be a warn-by-default lint if this ever occurs for a crate annotated with #![no_std], since we should be pushing people toward adding an alloc or core dependency instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify, a lint in the compiler if we end up passing --extern std=... to rustc but with a #![no_std] crate? That makes sense to me but the part of the document you've commented on is about public/private dependencies which seems unrelated, so wanted to double check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically, if:
Cargo.tomldoesn't have any std/alloc/core dependencies- The crate is
no_std
It may require explicit support from Cargo to do this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added this to the future possibility related to #![no_std] in 3935863, depending on whether migrating away from #![no_std] entirely is feasible, this could be an alternative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's reasonable; I'll resolve this for now. I definitely think it's okay to punt this off until later.
| 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. For | ||
| example, the following example will error as it could result in a build without | ||
| `core` (if the `std` feature were disabled): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While it is an unstable feature, I think it's worth commenting on how this interacts with the no_core feature: will crates using this still have to specify the core dependency, or will it be allowed to be omitted in those cases? Additionally, would this require an additional cargo feature or would just the feature on the crate be enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't considered no_core because it's perma-unstable. I don't see us ever stabilising it unless we're comfortable with alternative core crates having no stability guarantees (otherwise we can't add new required language items, which is very useful). Given that there is no path to or interest in stabilising this feature, I don't think it is worth mentioning in the RFC - a proposal to stabilise no_core can mention interactions with build-std rather than this RFC anticipating it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would strongly consider how annoying opt-out traits have been on the language design level, and "default-features" and feature migrations too, so we don't repeat the same mistakes here.
If we require core-only users to explicitly depend on core, yes they have type a few more characters, but we side step all those problems from the get-go.
(For what is is worth, the outcome I think is most likely is that in the coming decade, as we find ways to move more standard library functionality onto crates.io "full userland", core eventually becomes something that also depends on other crates. This is exactly analogous to the "oops, Sized is now longer the first trait in the hierarchy" problem, and close to the "oops, I want to add a new default feature, how do people opt out?" problem.)
Writing the core dependency one per crate is a lot cheaper than writing T: Sized in every bound, so let's just do it! Problem avoided!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non-cargo users are important to consider here - they may need to add features to their own build systems if passing in stdlib crates via --extern becomes mandatory in any sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we require core-only users to explicitly depend on core, yes they have type a few more characters, but we side step all those problems from the get-go.
This is exactly what we already propose, if you depend only on core then you need to explicitly write your dependency on core to remove the implicit dependencies on alloc and std.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK that sounds fine for external creates. Sorry for my misunderstanding.
New related question, that I think needs a call-out in the RFC:
How is core itself to be packaged? (Or really all standard library crates?) It would be nice for them to explicitly have no stdlib deps, rather than rely on today's hacks.
I see two approaches, which I'll Alan-Kay-style call eager and late binding:
-
late binding: Standard library crates use
builtin = trueon other standard library crates, and rely on the perma-unstable patching mechanism to make those refer to the right crates (that are presumably in the repo). -
eager binding: standard library creates just refer to each other with
pathdependencies, like today.
I think late binding is better. But the problem exist either way:
-
In the case of late binding,
coreneeds a way to have no (implicit or explicit) standard library deps, so it doesn't get a dependency on itself in thebuild-std = "always"case. -
In the case of early binding, all standard library crates need to have no (implicit or explicit) standard library deps for the same reason, because their
pathdeps on their fellow standard library crates serve that purpose instead.
|
|
||
| [dependencies] | ||
| std = { builtin = true, optional = true } | ||
| # error: must have a non-optional dependency on core |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that it might be worth mentioning the concept of lints here to make this less annoying of a requirement.
Right now, we have the concept of cargo lints, but we don't have any lints that let you autofix Cargo.toml, which I think would be a much-appreciated addition here. I feel like it makes a substantial difference toward this being a reasonable requirement if, instead of a hard error, this were a warn-by-default lint (implicitly adding the core dependency anyway) and that crates like this simply could not be published to crates.io.
In particular, it would be quite annoying if this issue completely prevented rust-analyzer from operating on code until it were fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced this is that annoying a requirement. Users will only hit this after adding an explicit optional dependency on the alloc or std and immediately notice the error and need to fix it. I don't see the value in having a lint that would allow you to delay fixing this but would force you to fix it eventually when you want to publish the crate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess that my main opinion here is that it's something that requires immediate attention to be fixed when it doesn't really affect the ability to build the code. If someone runs cargo add std --optional, this suddenly prevents rust-analyzer from working at all until it's fixed, and while the error should definitely be fixed before publishing the package, I fail to see how this should completely deadlock cargo's ability to build the crate at all until it's fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cargo add could just automatically add core if you're adding std or alloc.
eafc6b2 to
4b870f6
Compare
| > ├── rand v0.7.3 | ||
| > │ ├── getrandom v0.1.14 | ||
| > │ │ ├── cfg-if v0.1.10 | ||
| > │ │ │ └── core v0.0.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get why these don't have a usable version number, but IMHO, this should either display as core (built-in) or use the current Rust toolchain version instead. I can see the latter being considered very useful for the theoretical long-term case where crates could potentially be compiled with different libstd versions and then linked together, e.g. via dynamic linking.
Allow users to add explicit dependencies on standard library crates in the
Cargo.toml. This enables Cargo to determine which standard library crates are required by the crate graph withoutbuild-std-cratesbeing set and for different crates to require different standard library crates.This RFC is is part of the build-std project goal and a series of build-std RFCs:
build-std="always"(build-std: always #3874)build-std="compatible"(RFC not opened yet)build-std="match-profile"(RFC not opened yet)There is also a Zulip channel where you can ask questions about any of the build-std RFCs. This series of RFCs was drafted over many months with the help of stakeholders from many Rust project teams, we thank them for their help!
There are some details that have been noted as being worth mentioning in any eventual tracking issues:
Rendered