Skip to content

Commit 3d43f82

Browse files
authored
Merge pull request #2782 from kinnison/improve-cross-check
install: improve heuristic for deprecation warning
2 parents c8be2a3 + 81df770 commit 3d43f82

File tree

2 files changed

+95
-1
lines changed

2 files changed

+95
-1
lines changed

src/cli/rustup_mode.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -962,7 +962,7 @@ fn update(cfg: &mut Cfg, m: &ArgMatches<'_>) -> Result<utils::ExitCode> {
962962
let host_arch = TargetTriple::from_host_or_build();
963963
if let Ok(toolchain_desc) = ToolchainDesc::from_str(name) {
964964
let target_triple = toolchain_desc.target;
965-
if !forced && host_arch.ne(&target_triple) {
965+
if !forced && !host_arch.can_run(&target_triple)? {
966966
err!("DEPRECATED: future versions of rustup will require --force-non-host to install a non-host toolchain as the default.");
967967
warn!(
968968
"toolchain '{}' may not be able to run on this system.",

src/dist/dist.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,33 @@ impl TargetTriple {
311311
pub fn from_host_or_build() -> Self {
312312
Self::from_host().unwrap_or_else(Self::from_build)
313313
}
314+
315+
pub fn can_run(&self, other: &TargetTriple) -> Result<bool> {
316+
// Most trivial shortcut of all
317+
if self == other {
318+
return Ok(true);
319+
}
320+
// Otherwise we need to parse things
321+
let partial_self = PartialTargetTriple::new(&self.0)
322+
.ok_or_else(|| anyhow!(format!("Unable to parse target triple: {}", self.0)))?;
323+
let partial_other = PartialTargetTriple::new(&other.0)
324+
.ok_or_else(|| anyhow!(format!("Unable to parse target triple: {}", other.0)))?;
325+
// First obvious check is OS, if that doesn't match there's no chance
326+
let ret = if partial_self.os != partial_other.os {
327+
false
328+
} else if partial_self.os.as_deref() == Some("pc-windows") {
329+
// Windows is a special case here, we know we can run 32bit on 64bit
330+
// and we know we can run gnu and msvc on the same system
331+
// We don't immediately assume we can cross between x86 and aarch64 though
332+
(partial_self.arch == partial_other.arch)
333+
|| (partial_self.arch.as_deref() == Some("x86_64")
334+
&& partial_other.arch.as_deref() == Some("i686"))
335+
} else {
336+
// For other OSes, for now, we assume other toolchains won't run
337+
false
338+
};
339+
Ok(ret)
340+
}
314341
}
315342

316343
impl std::convert::TryFrom<PartialTargetTriple> for TargetTriple {
@@ -1103,4 +1130,71 @@ mod tests {
11031130
assert_eq!(tcd.is_tracking(), case.1);
11041131
}
11051132
}
1133+
1134+
#[test]
1135+
fn compatible_host_triples() {
1136+
static CASES: &[(&str, &[&str], &[&str])] = &[
1137+
(
1138+
// 64bit linux
1139+
"x86_64-unknown-linux-gnu",
1140+
// Not compatible beyond itself
1141+
&[],
1142+
// Even 32bit linux is considered not compatible by default
1143+
&["i686-unknown-linux-gnu"],
1144+
),
1145+
(
1146+
// On the other hand, 64 bit Windows
1147+
"x86_64-pc-windows-msvc",
1148+
// is compatible with 32 bit windows, and even gnu
1149+
&[
1150+
"i686-pc-windows-msvc",
1151+
"x86_64-pc-windows-gnu",
1152+
"i686-pc-windows-gnu",
1153+
],
1154+
// But is not compatible with Linux
1155+
&["x86_64-unknown-linux-gnu"],
1156+
),
1157+
(
1158+
// Indeed, 64bit windows with the gnu toolchain
1159+
"x86_64-pc-windows-gnu",
1160+
// is compatible with the other windows platforms
1161+
&[
1162+
"i686-pc-windows-msvc",
1163+
"x86_64-pc-windows-gnu",
1164+
"i686-pc-windows-gnu",
1165+
],
1166+
// But is not compatible with Linux despite also being gnu
1167+
&["x86_64-unknown-linux-gnu"],
1168+
),
1169+
(
1170+
// However, 32bit Windows is not expected to be able to run
1171+
// 64bit windows
1172+
"i686-pc-windows-msvc",
1173+
&["i686-pc-windows-gnu"],
1174+
&["x86_64-pc-windows-msvc", "x86_64-pc-windows-gnu"],
1175+
),
1176+
];
1177+
1178+
for (host, compatible, incompatible) in CASES {
1179+
println!("host={}", host);
1180+
let host = TargetTriple::new(host);
1181+
assert!(host.can_run(&host).unwrap(), "host wasn't self-compatible");
1182+
for other in compatible.iter() {
1183+
println!("compatible with {}", other);
1184+
let other = TargetTriple::new(other);
1185+
assert!(
1186+
host.can_run(&other).unwrap(),
1187+
"host and other were unexpectedly incompatible"
1188+
);
1189+
}
1190+
for other in incompatible.iter() {
1191+
println!("incompatible with {}", other);
1192+
let other = TargetTriple::new(other);
1193+
assert!(
1194+
!host.can_run(&other).unwrap(),
1195+
"host and other were unexpectedly compatible"
1196+
);
1197+
}
1198+
}
1199+
}
11061200
}

0 commit comments

Comments
 (0)