From 7599df820a4e25a3fd23793f897a48a92d71cdcc Mon Sep 17 00:00:00 2001 From: James Munns Date: Fri, 10 Apr 2026 15:57:04 +0200 Subject: [PATCH] Use `cc-rs` to detect the default linker, instead of assuming `cc` --- Cargo.toml | 2 +- src/cli/self_update.rs | 53 ++++++++++++++++++++++------- src/test/clitools.rs | 3 ++ tests/suite/cli_inst_interactive.rs | 2 +- 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0bf848de9d..c1a8d1556c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ test = ["dep:snapbox", "dep:walkdir", "clap-cargo/testing_colors"] anstream = "1" anstyle = "1.0.11" anyhow = "1.0.69" +cc = "1" cfg-if = "1.0" chrono = { version = "0.4", default-features = false, features = ["std"] } clap = { version = "4", features = ["derive", "wrap_help", "string"] } @@ -112,7 +113,6 @@ snapbox = { version = "1", features = ["term-svg"], optional = true } walkdir = { version = "2", optional = true } [target."cfg(windows)".dependencies] -cc = "1" scopeguard = "1" windows-registry = "0.6" windows-result = "0.4" diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 762a1f1b07..2e7d810ac4 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -828,20 +828,47 @@ fn current_install_opts(opts: &InstallOpts<'_>, process: &Process) -> String { #[cfg(unix)] fn warn_if_default_linker_missing(process: &Process) { - // Search for `cc` in PATH - if let Some(path) = process.var_os("PATH") { - let cc_binary = format!("cc{}", EXE_SUFFIX); - - for mut p in env::split_paths(&path) { - p.push(&cc_binary); - if p.is_file() { - return; - } - } - } + // Search for linker in PATH + let Some(path) = process.var_os("PATH") else { + warn!("unable to search PATH for a default linker"); + warn!("many Rust crates require a system C toolchain to build"); + return; + }; + + // If we have the host triple, attempt to determine the CC/linker path that + // `cc-rs` would use, as this is *usually* why we need a linker to invoke. + // + // Doing it this way allows us to correctly diagnose quirky systems like + // solaris and illumos that use `gcc` rather than `cc` for historical reasons. + let cc_tool = TargetTriple::from_host(process).and_then(|triple| { + // Fill in some dummy settings for `Build`/`Tool` to be able to properly + // give us the metadata we want + cc::Build::new() + .opt_level(0) + .target(&triple) + .host(&triple) + .try_get_compiler() + .ok() + }); + + let cc_binary = if let Some(cc_tool) = &cc_tool { + Cow::Borrowed(cc_tool.path()) + } else { + // If we don't get info from cc-rs, fall back to just looking for the literal `cc`. + Cow::Owned(format!("cc{EXE_SUFFIX}").into()) + }; - warn!("no default linker (`cc`) was found in your PATH"); - warn!("many Rust crates require a system C toolchain to build"); + // Search the path for the selected binary + let found = env::split_paths(&path).any(|mut p| { + p.push(&cc_binary); + p.is_file() + }); + + if !found { + let bin_disp = cc_binary.display(); + warn!("no default linker (`{bin_disp}`) was found in your PATH"); + warn!("many Rust crates require a system C toolchain to build"); + } } fn install_bins(process: &Process) -> Result<()> { diff --git a/src/test/clitools.rs b/src/test/clitools.rs index 8fa17c09cf..e1ff39c6f7 100644 --- a/src/test/clitools.rs +++ b/src/test/clitools.rs @@ -133,6 +133,9 @@ impl Assert { ("[CROSS_ARCH_I]", Cow::Borrowed(CROSS_ARCH1)), ("[CROSS_ARCH_II]", Cow::Borrowed(CROSS_ARCH2)), ("[MULTI_ARCH_I]", Cow::Borrowed(MULTI_ARCH1)), + ("[CC_TOOL]", Cow::Borrowed("`cc`")), + ("[CC_TOOL]", Cow::Borrowed("`gcc`")), + ("[CC_TOOL]", Cow::Borrowed("`clang`")), ]) .expect("invalid redactions detected"); Self { diff --git a/tests/suite/cli_inst_interactive.rs b/tests/suite/cli_inst_interactive.rs index 5a34bc8fa3..659cfc486c 100644 --- a/tests/suite/cli_inst_interactive.rs +++ b/tests/suite/cli_inst_interactive.rs @@ -684,7 +684,7 @@ async fn install_warns_if_default_linker_missing() { .is_ok() .with_stderr(snapbox::str![[r#" ... -warn: no default linker (`cc`) was found in your PATH +warn: no default linker ([CC_TOOL]) was found in your PATH warn: many Rust crates require a system C toolchain to build ... "#]]);