Skip to content

Commit 2defc68

Browse files
authored
Merge pull request #3772 from epage/build-target-edition
RFC: Deprecate the per-build-target `edition` field in `Cargo.toml`
2 parents e4d4b5d + d969dda commit 2defc68

File tree

1 file changed

+199
-0
lines changed

1 file changed

+199
-0
lines changed

text/3772-build-target-edition.md

+199
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
- Feature Name: `build-target-edition`
2+
- Start Date: 2025-02-13
3+
- RFC PR: [rust-lang/rfcs#3772](https://github.com/rust-lang/rfcs/pull/3772)
4+
- Rust Issue: [rust-lang/cargo#15283](https://github.com/rust-lang/cargo/issues/15283)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
Deprecate `lib.edition`, etc in favor of only setting `package.edition`, removing the fields in the next Edition.
10+
11+
# Motivation
12+
[motivation]: #motivation
13+
14+
Cargo supports setting the edition per-build-target:
15+
```toml
16+
[package]
17+
name = "foo"
18+
edition = "2021"
19+
20+
[lib]
21+
edition = "2015"
22+
23+
[[bin]]
24+
name = "foo"
25+
path = "src/main.rs"
26+
edition = "2015"
27+
28+
[[example]]
29+
name = "foo"
30+
path = "examples/foo.rs"
31+
edition = "2015"
32+
33+
[[test]]
34+
name = "foo"
35+
path = "tests/foo.rs"
36+
edition = "2015"
37+
38+
[[bench]]
39+
name = "foo"
40+
path = "benches/foo.rs"
41+
edition = "2015"
42+
```
43+
44+
This was intended for ([cargo#5661](https://github.com/rust-lang/cargo/issues/5661)):
45+
- Migrating to a new edition per build-target
46+
- Per edition tests
47+
48+
In practice, this feature does not seem to be in common use.
49+
Searching the latest `Cargo.toml` files of every package on crates.io,
50+
we found 13 packages using this feature
51+
([zulip](https://rust-lang.zulipchat.com/#narrow/channel/246057-t-cargo/topic/Deprecate.20build-target.20.60edition.60.20field.3F/near/499047806)):
52+
- 4 set `edition` on the sole build-target, rather than on the `package`
53+
- 3 set `edition` because they enumerated every build-target field but then forgot to update them when updating `package.edition`
54+
- 3 (+2 forks) have per-edition tests
55+
- 1 has every version yanked
56+
57+
While this does not account for transient use of this feature during an Edition migration,
58+
from our experience and observing others, we think this practice is not very common.
59+
In fact, it seems more likely that migrating a lint at a time may be more beneficial
60+
([cargo#11125](https://github.com/rust-lang/cargo/issues/11125#issuecomment-2641119791)).
61+
There is also an open question on the Cargo team on how much to focus on multiple build-targets per package
62+
vs individual packages
63+
(see [This Development-cycle in Cargo: 1.77](https://blog.rust-lang.org/inside-rust/2024/02/13/this-development-cycle-in-cargo-1-77.html#when-to-use-packages-or-workspaces)).
64+
65+
Drawbacks of this feature include:
66+
- Using this has a lot of friction as users have to explicitly
67+
enumerate each build target they want to set `edition` on which usually requires
68+
also setting the `name` and `path`.
69+
- This has led to bugs where people thought they migrated editions but did not
70+
- This is an easily overlooked feature to take into account when extending Cargo
71+
- Cargo cannot tell a `build.rs` what Edition to generate code for as it may generate code for one of several
72+
([cargo#6408](https://github.com/rust-lang/cargo/issues/6408)).
73+
This will become more important once we have [metabuild](https://github.com/rust-lang/cargo/issues/14903) for delegating build scripts to dependencies.
74+
- Making it more difficult for tools like `cargo fmt`
75+
([rustfmt#5071](https://github.com/rust-lang/rustfmt/pull/5071)) which need to map
76+
a file back to its edition which requires heuristics to associate a `.rs`
77+
file with a `Cargo.toml` and then to associate it with a specific build-target.
78+
79+
# Guide-level explanation
80+
[guide-level-explanation]: #guide-level-explanation
81+
82+
Documentation updates:
83+
84+
## Configuring a target
85+
86+
*From the [Cargo book](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target)*
87+
88+
...
89+
90+
```toml
91+
[lib]
92+
name = "foo" # The name of the target.
93+
path = "src/lib.rs" # The source file of the target.
94+
test = true # Is tested by default.
95+
doctest = true # Documentation examples are tested by default.
96+
bench = true # Is benchmarked by default.
97+
doc = true # Is documented by default.
98+
proc-macro = false # Set to `true` for a proc-macro library.
99+
harness = true # Use libtest harness.
100+
crate-type = ["lib"] # The crate types to generate.
101+
required-features = [] # Features required to build this target (N/A for lib).
102+
103+
edition = "2015" # Deprecated, N/A for Edition 20XX+
104+
```
105+
106+
...
107+
108+
### The `edition` field
109+
110+
The `edition` field defines the [Rust edition] the target will use. If not
111+
specified, it defaults to the [`edition` field][package-edition] for the
112+
`[package]`.
113+
114+
This field is deprecated and unsupported for Edition 20XX+
115+
116+
## Migration guide
117+
118+
*From [Rust Edition Guide: Advanced migration strategies](https://doc.rust-lang.org/nightly/edition-guide/editions/advanced-migrations.html#migrating-a-large-project-or-workspace)*
119+
120+
### Migrating a large project or workspace
121+
122+
You can migrate a large project incrementally to make the process easier if you run into problems.
123+
124+
In a [Cargo workspace], each package defines its own edition, so the process naturally involves migrating one package at a time.
125+
126+
Within a [Cargo package], you can either migrate the entire package at once, or migrate individual [Cargo targets] one at a time.
127+
For example, if you have multiple binaries, tests, and examples, you can use specific target selection flags with `cargo fix --edition` to migrate just that one target.
128+
By default, `cargo fix` uses `--all-targets`.
129+
130+
*(removed talk of the build-target `edition` field)*
131+
132+
### Migrating macros
133+
134+
...
135+
136+
If you have macros, you are encouraged to make sure you have tests that fully
137+
cover the macro's syntax. You may also want to test the macros by importing and
138+
using them in crates from multiple editions, just to ensure it works correctly
139+
everywhere.
140+
You can do this in doctests by setting the [edition attribute](https://doc.rust-lang.org/stable/rustdoc/write-documentation/documentation-tests.html#attributes)
141+
or by creating a package for your tests in your workspace for each edition.
142+
143+
If you run into issues, you'll need to read through the chapters of
144+
this guide to understand how the code can be changed to work across all
145+
editions.
146+
147+
*(added a testing strategy which was previously left unspoken)*
148+
149+
# Reference-level explanation
150+
[reference-level-explanation]: #reference-level-explanation
151+
152+
A non-`None` edition will be considered deprecated
153+
- A deprecation message will eventually be shown by Cargo
154+
- Timing depends on if this will be blocked on having `[lints]` control over this or not
155+
- When `package.edition` is set to Edition 20XX+, an error will be reported when a `<build-target>.edition` field is set.
156+
157+
# Drawbacks
158+
[drawbacks]: #drawbacks
159+
160+
- This makes testing macros more difficult as they are limited to either
161+
- doctests
162+
- creating packages just for the sake of defining tests
163+
164+
# Rationale and alternatives
165+
[rationale-and-alternatives]: #rationale-and-alternatives
166+
167+
## One Edition field controlling another
168+
169+
The exact semantics of `package.edition` vs `<build-target>.edition` have not been well defined when it comes to the manifest format itself.
170+
171+
`package.edition`'s [documentation](https://doc.rust-lang.org/cargo/reference/manifest.html#the-edition-field) says:
172+
173+
> [it] affects which Rust Edition your package is compiled with
174+
175+
while `<build-target>.edition` [documentation](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-edition-field) says:
176+
177+
> [it] defines the Rust edition the target will use
178+
179+
For Edition 2024, support for `<build-target>.proc_macro` and `<build-target>.crate_type`
180+
was removed based on `package.edition` and not `<build-target>.edition`.
181+
182+
By having `package.edition` affect `<build-target>.edition`,
183+
we are effectively saying that `package.edition` affects the manifest format
184+
while `<build-target>.edition` affects only affects the source code of the build-target.
185+
186+
# Prior art
187+
[prior-art]: #prior-art
188+
189+
# Unresolved questions
190+
[unresolved-questions]: #unresolved-questions
191+
192+
- When will Cargo start to report the deprecation message?
193+
- Cargo currently lacks lint control for itself ([cargo#12235](https://github.com/rust-lang/cargo/issues/12235)) which we could wait for
194+
- We could unconditionally report the warning but the Cargo team avoids adding warnings without a way of suppressing them without changing behavior
195+
196+
# Future possibilities
197+
[future-possibilities]: #future-possibilities
198+
199+
- Reporting the Edition to `build.rs`

0 commit comments

Comments
 (0)