rustup
rustup copied to clipboard
`rustup component (add|remove)` should not rely on hardcoded target triples
Verification
- [X] I searched for recent similar issues at https://github.com/rust-lang/rustup/issues?q=is%3Aissue+is%3Aopen%2Cclosed and found no duplicates.
- [X] I am on the latest version of Rustup according to https://github.com/rust-lang/rustup/tags and am still able to reproduce my issue.
Problem
The direct cause of #3166 is that
wasm32-unknown-unknownhasn't been hardcoded into our codebase:https://github.com/rust-lang/rustup/blob/a6c9fae915f41d611ab88ddd2228e19ea978ecaa/src/dist/triple.rs#L7-L37
[...] we really should not hardcode target triples in our artifact, as the complete list changes quite regularly.
https://github.com/rust-lang/rustup/pull/3601#issue-2055114196
Rustup version
rustup 1.27.0+74 (a6c9fae91 2024-04-21) dirty 1 modification
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.77.2 (25ef9e3d8 2024-04-09)`
I think a good approach here would be to add an integration test that can download a recent manifest, parse it, and regenerate a source file that contains current definitions of these (and fails the test if they're outdated).
I think a good approach here would be to add an integration test that can download a recent manifest, parse it, and regenerate a source file that contains current definitions of these (and fails the test if they're outdated).
@djc The current model of target triples in Rustup requires some non-code knowledge to correctly generate the list:
{ arch: aarch64, os: linux, env: android }
{ arch: aarch64, os: unknown-freebsd}
Looking at the original file, I think a reasonable (but possibly breaking) solution would be parsing the triples as follows:
// for `x-y`
{ arch: x, os: y }
// special case for `x-y-w` where `y` is `none` or `linux`
// e.g. `thumbv4t-none-eabi`, `i686-linux-android`
// (should've been called `x-unknown-y-w`, but alas)
{ arch: x, os: y, env: w }
// for `x-y-z`
{ arch: x, os: y-z }
// for `x-y-z-w`
{ arch: x, os: y-z, env: w }
Then we can get a list of triples by using things like rustc --print target-list (I assume we cannot add/remove a component without even having rustc installed, right?), or by reading the manifest (either at comptime or at runtime) and deduplicating.
Yeah, splitting is definitely not completely straightforward, but having an automated test that checks our internal code matches any targets in current manifests still sounds good.
@djc After some investigation I think https://docs.rs/platforms could potentially be a better alternative, also I like its glob patterns which might greatly simplify our Implementation.
I'm not sure how this might interact with our triple shorthands though...
https://github.com/rust-lang/rustup/blob/2a5a69e0914ff419554d684ca71eb1d72c72bcb3/src/dist/triple.rs#L107-L119
Also we need to ensure the existence of an escape hatch for new/custom triples.
Ah yes, that looks great!
So here's my plan for the experiment: I'll try to generate a source file by CS 101-level string templating according to the rules in https://github.com/rust-lang/rustup/issues/3783#issuecomment-2084304503, and include!() it in src/dist/triple.rs. Or, better yet, I can add this into rustup-macros as a proc_macro.
The only concern I have is the following snippet in build.rs. We almost definitely need to decouple src/dist/triple.rs from this one since now it's build.rs' responsibility to generate the list of triple components.
https://github.com/rust-lang/rustup/blob/2a5a69e0914ff419554d684ca71eb1d72c72bcb3/build.rs#L3-L27
However I don't know too much about this undocumented environment variable and how it's supposed to be used. Maybe @kinnison can provide more context on this one?
I mean, by using platforms as a build dependency, we at least know whether RUSTUP_OVERRIDE_BUILD_TRIPLE has been set to a valid full triple (instead of a partial triple), and that regressing change, albeit breaking, should not cause too much damage.
Update: Grepping the whole repo showed that RUSTUP_OVERRIDE_BUILD_TRIPLE has been used only once in the actual business logic, and exactly as a full triple, so this partial triple thing in build.rs is probably not very useful after all?
https://github.com/rust-lang/rustup/blob/2a5a69e0914ff419554d684ca71eb1d72c72bcb3/src/dist/dist.rs#L261 https://github.com/rust-lang/rustup/blob/2a5a69e0914ff419554d684ca71eb1d72c72bcb3/src/dist/dist.rs#L266-L268
Instead of using include!() or a procedural macro, IMO it would be better to have an integration test that writes into a source file inside src and can be imported by the usual means. The integration test can then panic if the expected (newly generated) contents of the file are not the same as the "current" contents (on disk).
Instead of using
include!()or a procedural macro, IMO it would be better to have an integration test that writes into a source file insidesrcand can be imported by the usual means. The integration test can then panic if the expected (newly generated) contents of the file are not the same as the "current" contents (on disk).
@djc I see your point of keeping those lists clearly visible in the codebase, but will this cause PR authors to chase a moving target, similar to what we have now WRT clippy lints? My original point is that outsourcing the changes to an external dependency means updating the list is always a version bump away.
Potentially -- but (a) fixing it should be very straightforward and (b) don't know how much the target moves. If you think using platforms is easier, I'd go with that first, we can see which downsides we run into over time.