- Feature Name:
min_rust_version
- Start Date: 2018-06-28
- RFC PR: rust-lang/rfcs#2495
- Rust Issue: rust-lang/rust#65262
Summary
Add rust
field to the package section of Cargo.toml
which will be used to
specify crate’s Minimum Supported Rust Version (MSRV):
[package]
name = "foo"
version = "0.1.0"
rust = "1.30"
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
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
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"
andedition = "2018"
is an invalid one.
Future work and extensions
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"
.
cargo init
would use the version of the toolchain used.
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:
[package]
rust = "1.30"
[target.x86_64-pc-windows-gnu.package]
rust = "1.35"
[target.'cfg(feature = "foo")'.package]
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. 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
- 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
withrust = "stable"
can be too conservative.
Alternatives
- Automatically calculate MSRV.
- Do nothing and rely on LTS releases for bumping crate MSRVs.
- Allow version and path based
cfg
attributes as proposed in RFC 2523.
Prior art
Previous proposals:
Unresolved questions
- Name bike-shedding:
rust
vsrustc
vsmin-rust-version
- Additional checks?
- Better description of versions resolution algorithm.
- How nightly versions will work with “cfg based MSRV”?