Skip to content

Commit e1179b5

Browse files
committed
Auto merge of #14636 - epage:msrv-policy, r=weihanglo
docs(ref): Expand on MSRV ### What does this PR try to resolve? The need for this has been growing and becomes especially important with the upcoming MSRV aware resolver We will be making having an MSRV easier so we need to meet those maintainers where they are and help them. In particular, this covers - What setting an MSRV does - What "support" in MSRV means, according to the definition we developed during the review of [RFC 3537](https://rust-lang.github.io/rfcs/3537-msrv-resolver.html) - Background and guidance on setting an MSRV policy ### How should we test and review this PR? ### Additional information This intentionally leaves out anything related to the MSRV-aware resolver as that will be handled as the feature is stabilized.
2 parents 0473ee8 + b48e5f1 commit e1179b5

File tree

3 files changed

+164
-26
lines changed

3 files changed

+164
-26
lines changed

src/doc/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
* [Cargo Reference](reference/index.md)
2222
* [The Manifest Format](reference/manifest.md)
2323
* [Cargo Targets](reference/cargo-targets.md)
24+
* [Rust version](reference/rust-version.md)
2425
* [Workspaces](reference/workspaces.md)
2526
* [Specifying Dependencies](reference/specifying-dependencies.md)
2627
* [Overriding Dependencies](reference/overriding-dependencies.md)

src/doc/src/reference/manifest.md

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Every manifest file consists of the following sections:
1212
* [`version`](#the-version-field) --- The version of the package.
1313
* [`authors`](#the-authors-field) --- The authors of the package.
1414
* [`edition`](#the-edition-field) --- The Rust edition.
15-
* [`rust-version`](#the-rust-version-field) --- The minimal supported Rust version.
15+
* [`rust-version`](rust-version.md) --- The minimal supported Rust version.
1616
* [`description`](#the-description-field) --- A description of the package.
1717
* [`documentation`](#the-documentation-field) --- URL of the package documentation.
1818
* [`readme`](#the-readme-field) --- Path to the package's README file.
@@ -163,31 +163,9 @@ will have `edition` explicitly specified to a newer value.
163163

164164
### The `rust-version` field
165165

166-
The `rust-version` field is an optional key that tells cargo what version of the
167-
Rust language and compiler your package can be compiled with.
168-
If the currently selected version of the Rust compiler is older than the stated
169-
version, cargo will exit with an error, telling the user what version is
170-
required.
171-
This affects all targets/crates in the package, including test suites,
172-
benchmarks, binaries, examples, etc.
173-
174-
The `rust-version` may be ignored using the `--ignore-rust-version` option.
175-
176-
```toml
177-
[package]
178-
# ...
179-
rust-version = "1.56"
180-
```
181-
182-
The Rust version must be a bare version number with at least one component; it
183-
cannot include semver operators or pre-release identifiers. Compiler pre-release
184-
identifiers such as -nightly will be ignored while checking the Rust version.
185-
186-
To find the minimum `rust-version` compatible with your project, you can use third-party tools like [`cargo-msrv`](https://crates.io/crates/cargo-msrv).
187-
188-
When used on packages that get published, we recommend [verifying the `rust-version`](../guide/continuous-integration.md#verifying-rust-version).
189-
190-
> **MSRV:** Respected as of 1.56
166+
The `rust-version` field tells cargo what version of the
167+
Rust toolchain you support for your package.
168+
See [the Rust version chapter](rust-version.md) for more detail.
191169

192170
### The `description` field
193171

@@ -685,6 +663,7 @@ more detail.
685663
"#the-exclude-and-include-fields-optional": "manifest.html#the-exclude-and-include-fields",
686664
"#the-publish--field-optional": "manifest.html#the-publish-field",
687665
"#the-metadata-table-optional": "manifest.html#the-metadata-table",
666+
"#rust-version": "rust-version.html",
688667
};
689668
var target = fragments[window.location.hash];
690669
if (target) {

src/doc/src/reference/rust-version.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# Rust Version
2+
3+
The `rust-version` field is an optional key that tells cargo what version of the
4+
Rust toolchain you support for your package.
5+
6+
```toml
7+
[package]
8+
# ...
9+
rust-version = "1.56"
10+
```
11+
12+
The Rust version must be a bare version number with at least one component; it
13+
cannot include semver operators or pre-release identifiers. Compiler pre-release
14+
identifiers such as -nightly will be ignored while checking the Rust version.
15+
16+
> **MSRV:** Respected as of 1.56
17+
18+
## Uses
19+
20+
**Diagnostics:**
21+
22+
When your package is compiled on an unsupported toolchain,
23+
Cargo will provide clearer diagnostics about the insufficient toolchain version rather than reporting invalid syntax or missing functionality in the standard library.
24+
This affects all [Cargo targets](cargo-targets.md) in the package, including binaries, examples, test suites,
25+
benchmarks, etc.
26+
27+
**Development aid:**
28+
29+
`cargo add` will auto-select the dependency's version requirement to be the latest version compatible with your `rust-version`.
30+
If that isn't the latest version, `cargo add` will inform users so they can make the choice on whether to keep it or update your `rust-version`.
31+
32+
Other tools may also take advantage of it, like `cargo clippy`'s
33+
[`incompatible_msrv` lint](https://rust-lang.github.io/rust-clippy/stable/index.html#/incompatible_msrv).
34+
35+
> **Note:** The `rust-version` may be ignored using the `--ignore-rust-version` option.
36+
37+
## Support Expectations
38+
39+
These are general expectations; some packages may document when they do not follow these.
40+
41+
**Complete:**
42+
43+
All functionality, including binaries and API, are available on the supported Rust versions under every [feature](features.md).
44+
45+
**Verified:**
46+
47+
A package's functionality is verified on its supported Rust versions, including automated testing.
48+
See also our
49+
[Rust version CI guide](../guide/continuous-integration.md#verifying-rust-version).
50+
51+
**Patchable:**
52+
53+
When licenses allow it,
54+
users can [override their local dependency](overriding-dependencies.md) with a fork of your package.
55+
In this situation, Cargo may load the entire workspace for the patched dependency which should work on the supported Rust versions, even if other packages in the workspace have different supported Rust versions.
56+
57+
**Dependency Support:**
58+
59+
In support of the above,
60+
it is expected that each dependency's version-requirement supports at least one version compatible with your `rust-version`.
61+
However,
62+
it is **not** expected that the dependency specification excludes versions incompatible with your `rust-version`.
63+
In fact, supporting both allows you to balance the needs of users that support older Rust versions with those that don't.
64+
65+
## Setting and Updating Rust Version
66+
67+
What Rust versions to support is a trade off between
68+
- Costs for the maintainer in not using newer features of the Rust toolchain or their dependencies
69+
- Costs to users who would benefit from a package using newer features of a toolchain, e.g. reducing build times by migrating to a feature in the standard library from a polyfill
70+
- Availability of a package to users supporting older Rust versions
71+
72+
> **Note:** [Changing `rust-version`](semver.md#env-new-rust) is assumed to be a minor incompatibility
73+
74+
> **Recommendation:** Choose a policy for what Rust versions to support and when that is changed so users can compare it with their own policy and,
75+
> if it isn't compatible,
76+
> decide whether the loss of general improvements or the risk of a blocking bug that won't be fixed is acceptable or not.
77+
>
78+
> The simplest policy to support is to always use the latest Rust version.
79+
>
80+
> Depending on your risk profile, the next simplest approach is to continue to support old major or minor versions of your package that support older Rust versions.
81+
82+
### Selecting supported Rust versions
83+
84+
Users of your package are most likely to track their supported Rust versions to:
85+
- Their Rust toolchain vendor's support policy, e.g. The Rust Project or a Linux distribution
86+
- Note: the Rust Project only offers bug fixes and security updates for the latest version.
87+
- A fixed schedule for users to re-verify their packages with the new toolchain, e.g. the first release of the year, every
88+
89+
In addition, users are unlikely to be using the new Rust version immediately but need time to notice and re-verify or might not be aligned on the exact same schedule..
90+
91+
Example version policies:
92+
- "N-2", meaning "latest version with a 2 release grace window for updating"
93+
- Every even release with a 2 release grace window for updating
94+
- Every version from this calendar year with a one year grace window for updating
95+
96+
> **Note:** To find the minimum `rust-version` compatible with your project as-is, you can use third-party tools like [`cargo-msrv`](https://crates.io/crates/cargo-msrv).
97+
98+
### Update timeline
99+
100+
When your policy specifies you no longer need to support a Rust version, you can update `rust-version` immediately or when needed.
101+
102+
By allowing `rust-version` to drift from your policy,
103+
you offer users more of a grace window for upgrading.
104+
However, this is too unpredictable to be relied on for aligning with the Rust version users track.
105+
106+
The further `rust-version` drifts from your specified policy,
107+
the more likely users are to infer a policy you did not intend,
108+
leading to frustration at the unmet expectations.
109+
110+
When drift is allowed,
111+
there is the question of what is "justifiable enough" to drop supported Versions.
112+
Each person can come to a reasonably different justification;
113+
working through that discussion can be frustrating for the involved parties.
114+
This will disempower those who would want to avoid that type of conflict,
115+
which is particularly the case for new or casual contributors who either
116+
feel that they are not in a position to raise the question or
117+
that the conflict may hurt the chance of their change being merged.
118+
119+
### Multiple Policies in a Workspace
120+
121+
Cargo allows supporting multiple policies within one workspace.
122+
123+
Verifying specific packages under specific Rust versions can get complicated.
124+
Tools like [`cargo-hack`](https://crates.io/crates/cargo-hack) can help.
125+
126+
For any dependency shared across policies,
127+
the lowest common versions must be used as Cargo
128+
[unifies SemVer-compatible versions](resolver.md#semver-compatibility),
129+
potentially limiting access to features of the shared dependency for the workspace member with the higher `rust-version`.
130+
131+
To allow users to patch a dependency on one of your workspace members,
132+
every package in the workspace would need to be loadable in the oldest Rust version supported by the workspace.
133+
134+
### One or More Policies
135+
136+
One way to mitigate the downsides of supporting older Rust versions is to apply your policy to older major or minor versions of your package that you continue to support.
137+
You likely still need a policy for what Rust versions the development branch support compared to the release branches for those major or minor versions.
138+
139+
Only updating the development branch when "needed"' can help reduce the number of supported release branches.
140+
141+
There is the question of what can be backported into these release branches.
142+
By backporting new functionality between minor versions,
143+
the next available version would be missing it which could be considered a breaking change, violating SemVer.
144+
Backporting changes also comes with the risk of introducing bugs.
145+
146+
Supporting older versions comes at a cost.
147+
This cost is dependent on the risk and impact of bugs within the package and what is acceptable for backporting.
148+
Creating the release branches on-demand and putting the backport burden on the community are ways to balance this cost.
149+
150+
There is not yet a way for dependency management tools to report that a non-latest version is still supported,
151+
shifting the responsibility to users to notice this in documentation.
152+
153+
For example, a Rust version support policy could look like:
154+
- The development branch tracks to the latest stable release from the Rust Project, updated when needed
155+
- The minor version will be raised when changing `rust-version`
156+
- The project supports every version for this calendar year, with another year grace window
157+
- The last minor version that supports a supported Rust version will receive community provided bug fixes
158+
- Fixes must be backported to all supported minor releases between the development branch and the needed supported Rust version

0 commit comments

Comments
 (0)