-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: Minimum Supported Rust Version #2495
Changes from 15 commits
800825c
4ec9682
f9057da
a43e9e1
00a3022
1e37f4c
a6e42da
e4c638e
7580c20
1aa6476
84aecf1
a78e4b1
73bdc96
7657ef4
ad12112
1a186ea
0cacbb6
386fd8a
33ea5a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
- Feature Name: min_rust_version | ||
- Start Date: 2018-06-28 | ||
- RFC PR: (leave this empty) | ||
- Rust Issue: (leave this empty) | ||
|
||
# Summary | ||
[summary]: #summary | ||
|
||
Add `rust` field to the package section of `Cargo.toml` which will be used to | ||
specify crate's Minimum Supported Rust Version (MSRV): | ||
```toml | ||
[package] | ||
name = "foo" | ||
version = "0.1.0" | ||
rust = "1.30" | ||
``` | ||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
Currently crates have no way to formally specify MSRV. As a result users can't | ||
check if crate can be built on their toolchain without building it. It also | ||
leads to the debate on how to handle crate version change on bumping MSRV, | ||
conservative approach is to consider such changes as breaking ones, which can | ||
hinder adoption of new features across ecosystem or result in version number | ||
inflation, which makes it harder to keep downstream crates up-to-date. More | ||
relaxed approach on another hand can result in broken crates for user of older | ||
compiler versions. | ||
|
||
# Guide-level explanation | ||
[guide-level-explanation]: #guide-level-explanation | ||
|
||
If you target a specific MSRV add a `rust` field to the `[package]` section of | ||
your `Cargo.toml` with a value equal to the targeted Rust version. If you build | ||
a crate with a dependency which has MSRV higher than the current version of your | ||
toolchain, `cargo` will return a compilation error stating the dependency and | ||
its MSRV. This behavior can be disabled by using `--no-msrv-check` flag. | ||
|
||
# Reference-level explanation | ||
[reference-level-explanation]: #reference-level-explanation | ||
|
||
During build process (including `run`, `test`, `benchmark`, `verify` and `publish` | ||
sub-commands) `cargo` will check MSRV requirements of all crates in a dependency | ||
tree scheduled to be built or checked. Crates which are part of the dependency | ||
tree, but will not be built are excluded from this check (e.g. target-dependent | ||
or optional crates). | ||
|
||
`rust` field should respect the following minimal requirements: | ||
- Value should be a version in semver format **without** range operators. Note | ||
that "1.50" is a valid value and implies "1.50.0". | ||
- Version can not be bigger than a current stable toolchain (it will be checked | ||
by crates.io during crate upload). | ||
- Version can not be smaller than 1.27 (version in which `package.rust` field | ||
became a warning instead of an error). | ||
- Version can not be smaller than release version of a used edition, i.e. | ||
combination of `rust = "1.27"` and `edition = "2018"` is an invalid one. | ||
|
||
# Future work and extensions | ||
[future-work]: #future-work | ||
|
||
## Influencing version resolution | ||
|
||
The value of `rust` field (explicit or automatically selected by `cargo`) will | ||
be used to select appropriate dependency versions. | ||
|
||
For example, let's imagine that your crate depends on crate `foo` with 10 published | ||
versions from `0.1.0` to `0.1.9`, in versions from `0.1.0` to `0.1.5` `rust` | ||
field in the `Cargo.toml` sent to crates.io equals to "1.30" and for others to | ||
"1.40". Now if you'll build your project with e.g. Rust 1.33, `cargo` will select | ||
`foo v0.1.5`. `foo v0.1.9` will be selected only if you'll build your project with | ||
Rust 1.40 or higher. But if you'll try to build your project with Rust 1.29 cargo | ||
will issue an error. | ||
|
||
`rust` field value will be checked as well. During crate build `cargo` will check | ||
if all upstream dependencies can be built with the specified MSRV. (i.e. it will | ||
check if there is exists solution for given crates and Rust versions constraints) | ||
Yanked crates will be ignored in this process. | ||
|
||
Implementing this functionality hopefully will allow us to close the long-standing | ||
debate regarding whether MSRV bump is a breaking change or not and will allow | ||
crate authors to feel less restrictive about bumping their crate's MSRV. (though | ||
it may be a useful convention for post-1.0 crates to bump minor version on MSRV | ||
bump to allow publishing backports which fix serious issues using patch version) | ||
|
||
Note that described MSRV constraints and checks for dependency versions resolution | ||
can be disabled with the `--no-msrv-check` option. | ||
|
||
## Checking MSRV during publishing | ||
|
||
`cargo publish` will check that upload is done with a toolchain version specified | ||
in the `rust` field. If toolchain version is different, `cargo` will refuse to | ||
upload the crate. It will be a failsafe to prevent uses of incorrect `rust` values | ||
due to unintended MSRV bumps. This check can be disabled by using the existing | ||
`--no-verify` option. | ||
|
||
## Making `rust` field mandatory | ||
|
||
In future (probably in a next edition) we could make `rust` field mandatory for | ||
a newly uploaded crates. MSRV for older crates will be determined by the `edition` | ||
field. In other words `edition = "2018"` will imply `rust = "1.31"` and | ||
`edition = "2015"` will imply `rust = "1.0"`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implying Rust 1.0 seems mostly incompatible with this statement from earlier in the document:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The cited text is one of the requirements for the
|
||
|
||
`cargo init` will use version of a currently used toolchain. | ||
newpavlov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## `cfg`-based MSRVs | ||
|
||
Some crates can have different MSRVs depending on target architecture or enabled | ||
features. In such cases it can be useful to describe how MSRV depends on them, | ||
e.g. in the following way: | ||
```toml | ||
[package] | ||
rust = "1.30" | ||
|
||
[target.x86_64-pc-windows-gnu] | ||
newpavlov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
rust = "1.35" | ||
|
||
[target.'cfg(feature = "foo")'] | ||
newpavlov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
rust = "1.33" | ||
``` | ||
|
||
All `rust` values in the `target` sections should be equal or bigger to a `rust` value | ||
specified in the `package` section. | ||
|
||
If target condition is true, then `cargo ` will use `rust` value from this section. | ||
If several target section conditions are true, then maximum value will be used. | ||
|
||
## Nightly and stable versions | ||
|
||
Some crates may prefer to target only the most recent stable or nightly toolchain. | ||
In addition to the versions we could allow `stable` and `nightly` values to declare | ||
that maintainers do not track MSRV for the crate. | ||
|
||
For some bleeding-edge crates which experience frequent breaks on Nightly updates | ||
(e.g. `rocket`) it can be useful to specify exact Nightly version(s) on which | ||
crate can be built. One way to achieve this is by using the following syntax: | ||
- auto-select: "nightly" This variant will behave in the same way as "stable", i.e. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This entire list is poorly formatted for reading, with this line being particularly problematic. |
||
it will take a current nightly version and will use it in a "more or equal" constraint. | ||
- single version: "nightly: 2018-01-01" (the main variant) | ||
- enumeration: "nightly: 2018-01-01, 2018-01-15" | ||
- semver-like conditions: "nightly: >=2018-01-01", "nightly: >=2018-01-01, <=2018-01-15", | ||
"nightly: >=2018-01-01, <=2018-01-15, 2018-01-20". (the latter is interpreted as | ||
"(version >= 2018-01-01 && version <= 2018-01-20) || version == 2018-01-20") | ||
|
||
Such restrictions can be quite severe, but hopefully this functionality will be | ||
used only by handful of crates. | ||
|
||
# Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
- Declaration of MSRV, even with the checks, does not guarantee that crate | ||
will work correctly on the specified MSRV, only appropriate CI testing can do that. | ||
- More complex dependency versions resolution algorithm. | ||
- MSRV selected by `cargo publish` with `rust = "stable"` can be too | ||
conservative. | ||
|
||
# Alternatives | ||
[alternatives]: #alternatives | ||
|
||
- Automatically calculate MSRV. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems too vague to have much meaning; there are wildly different things it could mean, with completely different trade-offs. What is automatically calculating the MSRV? rustc, cargo, crates.io? How is it conveyed? Would it play well with the future work of MSRV influencing version resolution? I can think of two radically different approaches to this off the top of my head, one of which is completely different from this proposal and one of which boils down to just augmenting the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't want to cover all potential approaches, as you do say yourself there are a lot of options to choose from. The main idea here is that instead of asking people to manually select MSRV via the |
||
- Do nothing and rely on [LTS releases](https://github.com/rust-lang/rfcs/pull/2483) | ||
for bumping crate MSRVs. | ||
newpavlov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- Allow version and path based `cfg` attributes as proposed in [RFC 2523](https://github.com/rust-lang/rfcs/pull/2523). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. RFC 2523 isn’t an alternative to this functionality. It’s just related functionality, and the two go together quite nicely. (RFC 2523 has been accepted now, BTW, so if mention of it is kept, the link should probably change.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
# Prior art | ||
[prior-art]: #prior-art | ||
|
||
Previous proposals: | ||
- [RFC 1707](https://github.com/rust-lang/rfcs/pull/1707) | ||
- [RFC 1709](https://github.com/rust-lang/rfcs/pull/1709) | ||
- [RFC 1953](https://github.com/rust-lang/rfcs/pull/1953) | ||
- [RFC 2182](https://github.com/rust-lang/rfcs/pull/2182) (arguably this one got off-track) | ||
|
||
# Unresolved questions | ||
[unresolved]: #unresolved-questions | ||
|
||
- Name bike-shedding: `rust` vs `rustc` vs `min-rust-version` | ||
- Additional checks? | ||
- Better description of versions resolution algorithm. | ||
- How nightly versions will work with "cfg based MSRV"? |
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.
Some things in this section are written in the wrong tense, given that they are matters that this RFC does not decide upon. Because they’re hypothetical or tentative plans, “would” should be used instead of “will”, or else it’s easy to get confused about what’s in scope for implementation, when reading the RFC. For example, part way through reading it I was thinking that influencing version resolution was in scope due to the use of the word “will”, but it is in fact designated as possible future work.
(If you’re not sure what I’m talking about, https://english.stackexchange.com/questions/3657/when-should-i-use-would-would-have-will-and-will-have explains it decently. Also let it be known that I love the term subjunctive mood.)
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.
Ah, I forgot to change it after I moved this text to the "future work" section. I will try to fix it.