|
| 1 | +- Feature Name: `min_rust_version` |
| 2 | +- Start Date: 2018-06-28 |
| 3 | +- RFC PR: [rust-lang/rfcs#2495](https://github.com/rust-lang/rfcs/pull/2495) |
| 4 | +- Rust Issue: [rust-lang/rust#](https://github.com/rust-lang/rust/issues/) |
| 5 | + |
| 6 | +# Summary |
| 7 | +[summary]: #summary |
| 8 | + |
| 9 | +Add `rust` field to the package section of `Cargo.toml` which will be used to |
| 10 | +specify crate's Minimum Supported Rust Version (MSRV): |
| 11 | +```toml |
| 12 | +[package] |
| 13 | +name = "foo" |
| 14 | +version = "0.1.0" |
| 15 | +rust = "1.30" |
| 16 | +``` |
| 17 | + |
| 18 | +# Motivation |
| 19 | +[motivation]: #motivation |
| 20 | + |
| 21 | +Currently crates have no way to formally specify MSRV. As a result users can't |
| 22 | +check if crate can be built on their toolchain without building it. It also |
| 23 | +leads to the debate on how to handle crate version change on bumping MSRV, |
| 24 | +conservative approach is to consider such changes as breaking ones, which can |
| 25 | +hinder adoption of new features across ecosystem or result in version number |
| 26 | +inflation, which makes it harder to keep downstream crates up-to-date. More |
| 27 | +relaxed approach on another hand can result in broken crates for user of older |
| 28 | +compiler versions. |
| 29 | + |
| 30 | +# Guide-level explanation |
| 31 | +[guide-level-explanation]: #guide-level-explanation |
| 32 | + |
| 33 | +If you target a specific MSRV add a `rust` field to the `[package]` section of |
| 34 | +your `Cargo.toml` with a value equal to the targeted Rust version. If you build |
| 35 | +a crate with a dependency which has MSRV higher than the current version of your |
| 36 | +toolchain, `cargo` will return a compilation error stating the dependency and |
| 37 | +its MSRV. This behavior can be disabled by using `--no-msrv-check` flag. |
| 38 | + |
| 39 | +# Reference-level explanation |
| 40 | +[reference-level-explanation]: #reference-level-explanation |
| 41 | + |
| 42 | +During build process (including `run`, `test`, `benchmark`, `verify` and `publish` |
| 43 | +sub-commands) `cargo` will check MSRV requirements of all crates in a dependency |
| 44 | +tree scheduled to be built or checked. Crates which are part of the dependency |
| 45 | +tree, but will not be built are excluded from this check (e.g. target-dependent |
| 46 | +or optional crates). |
| 47 | + |
| 48 | +`rust` field should respect the following minimal requirements: |
| 49 | +- Value should be a version in semver format **without** range operators. Note |
| 50 | +that "1.50" is a valid value and implies "1.50.0". |
| 51 | +- Version can not be bigger than a current stable toolchain (it will be checked |
| 52 | +by crates.io during crate upload). |
| 53 | +- Version can not be smaller than 1.27 (version in which `package.rust` field |
| 54 | +became a warning instead of an error). |
| 55 | +- Version can not be smaller than release version of a used edition, i.e. |
| 56 | +combination of `rust = "1.27"` and `edition = "2018"` is an invalid one. |
| 57 | + |
| 58 | +# Future work and extensions |
| 59 | +[future-work]: #future-work |
| 60 | + |
| 61 | +## Influencing version resolution |
| 62 | + |
| 63 | +The value of `rust` field (explicit or automatically selected by `cargo`) will |
| 64 | +be used to select appropriate dependency versions. |
| 65 | + |
| 66 | +For example, let's imagine that your crate depends on crate `foo` with 10 published |
| 67 | +versions from `0.1.0` to `0.1.9`, in versions from `0.1.0` to `0.1.5` `rust` |
| 68 | +field in the `Cargo.toml` sent to crates.io equals to "1.30" and for others to |
| 69 | +"1.40". Now if you'll build your project with e.g. Rust 1.33, `cargo` will select |
| 70 | +`foo v0.1.5`. `foo v0.1.9` will be selected only if you'll build your project with |
| 71 | +Rust 1.40 or higher. But if you'll try to build your project with Rust 1.29 cargo |
| 72 | +will issue an error. |
| 73 | + |
| 74 | +`rust` field value will be checked as well. During crate build `cargo` will check |
| 75 | +if all upstream dependencies can be built with the specified MSRV. (i.e. it will |
| 76 | +check if there is exists solution for given crates and Rust versions constraints) |
| 77 | +Yanked crates will be ignored in this process. |
| 78 | + |
| 79 | +Implementing this functionality hopefully will allow us to close the long-standing |
| 80 | +debate regarding whether MSRV bump is a breaking change or not and will allow |
| 81 | +crate authors to feel less restrictive about bumping their crate's MSRV. (though |
| 82 | +it may be a useful convention for post-1.0 crates to bump minor version on MSRV |
| 83 | +bump to allow publishing backports which fix serious issues using patch version) |
| 84 | + |
| 85 | +Note that described MSRV constraints and checks for dependency versions resolution |
| 86 | +can be disabled with the `--no-msrv-check` option. |
| 87 | + |
| 88 | +## Checking MSRV during publishing |
| 89 | + |
| 90 | +`cargo publish` will check that upload is done with a toolchain version specified |
| 91 | +in the `rust` field. If toolchain version is different, `cargo` will refuse to |
| 92 | +upload the crate. It will be a failsafe to prevent uses of incorrect `rust` values |
| 93 | +due to unintended MSRV bumps. This check can be disabled by using the existing |
| 94 | +`--no-verify` option. |
| 95 | + |
| 96 | +## Making `rust` field mandatory |
| 97 | + |
| 98 | +In future (probably in a next edition) we could make `rust` field mandatory for |
| 99 | +a newly uploaded crates. MSRV for older crates will be determined by the `edition` |
| 100 | +field. In other words `edition = "2018"` will imply `rust = "1.31"` and |
| 101 | +`edition = "2015"` will imply `rust = "1.0"`. |
| 102 | + |
| 103 | +`cargo init` would use the version of the toolchain used. |
| 104 | + |
| 105 | +## `cfg`-based MSRVs |
| 106 | + |
| 107 | +Some crates can have different MSRVs depending on target architecture or enabled |
| 108 | +features. In such cases it can be useful to describe how MSRV depends on them, |
| 109 | +e.g. in the following way: |
| 110 | +```toml |
| 111 | +[package] |
| 112 | +rust = "1.30" |
| 113 | + |
| 114 | +[target.x86_64-pc-windows-gnu.package] |
| 115 | +rust = "1.35" |
| 116 | + |
| 117 | +[target.'cfg(feature = "foo")'.package] |
| 118 | +rust = "1.33" |
| 119 | +``` |
| 120 | + |
| 121 | +All `rust` values in the `target` sections should be equal or bigger to a `rust` value |
| 122 | +specified in the `package` section. |
| 123 | + |
| 124 | +If target condition is true, then `cargo ` will use `rust` value from this section. |
| 125 | +If several target section conditions are true, then maximum value will be used. |
| 126 | + |
| 127 | +## Nightly and stable versions |
| 128 | + |
| 129 | +Some crates may prefer to target only the most recent stable or nightly toolchain. |
| 130 | +In addition to the versions we could allow `stable` and `nightly` values to declare |
| 131 | +that maintainers do not track MSRV for the crate. |
| 132 | + |
| 133 | +For some bleeding-edge crates which experience frequent breaks on Nightly updates |
| 134 | +(e.g. `rocket`) it can be useful to specify exact Nightly version(s) on which |
| 135 | +crate can be built. One way to achieve this is by using the following syntax: |
| 136 | +- auto-select: "nightly" This variant will behave in the same way as "stable", i.e. |
| 137 | +it will take a current nightly version and will use it in a "more or equal" constraint. |
| 138 | +- single version: "nightly: 2018-01-01" (the main variant) |
| 139 | +- enumeration: "nightly: 2018-01-01, 2018-01-15" |
| 140 | +- semver-like conditions: "nightly: >=2018-01-01", "nightly: >=2018-01-01, <=2018-01-15", |
| 141 | +"nightly: >=2018-01-01, <=2018-01-15, 2018-01-20". (the latter is interpreted as |
| 142 | +"(version >= 2018-01-01 && version <= 2018-01-20) || version == 2018-01-20") |
| 143 | + |
| 144 | +Such restrictions can be quite severe, but hopefully this functionality will be |
| 145 | +used only by handful of crates. |
| 146 | + |
| 147 | +# Drawbacks |
| 148 | +[drawbacks]: #drawbacks |
| 149 | + |
| 150 | +- Declaration of MSRV, even with the checks, does not guarantee that crate |
| 151 | +will work correctly on the specified MSRV, only appropriate CI testing can do that. |
| 152 | +- More complex dependency versions resolution algorithm. |
| 153 | +- MSRV selected by `cargo publish` with `rust = "stable"` can be too |
| 154 | +conservative. |
| 155 | + |
| 156 | +# Alternatives |
| 157 | +[alternatives]: #alternatives |
| 158 | + |
| 159 | +- Automatically calculate MSRV. |
| 160 | +- Do nothing and rely on [LTS releases](https://github.com/rust-lang/rfcs/pull/2483) |
| 161 | +for bumping crate MSRVs. |
| 162 | +- Allow version and path based `cfg` attributes as proposed in [RFC 2523](https://github.com/rust-lang/rfcs/pull/2523). |
| 163 | + |
| 164 | +# Prior art |
| 165 | +[prior-art]: #prior-art |
| 166 | + |
| 167 | +Previous proposals: |
| 168 | +- [RFC 1707](https://github.com/rust-lang/rfcs/pull/1707) |
| 169 | +- [RFC 1709](https://github.com/rust-lang/rfcs/pull/1709) |
| 170 | +- [RFC 1953](https://github.com/rust-lang/rfcs/pull/1953) |
| 171 | +- [RFC 2182](https://github.com/rust-lang/rfcs/pull/2182) (arguably this one got off-track) |
| 172 | + |
| 173 | +# Unresolved questions |
| 174 | +[unresolved]: #unresolved-questions |
| 175 | + |
| 176 | +- Name bike-shedding: `rust` vs `rustc` vs `min-rust-version` |
| 177 | +- Additional checks? |
| 178 | +- Better description of versions resolution algorithm. |
| 179 | +- How nightly versions will work with "cfg based MSRV"? |
0 commit comments