Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down Expand Up @@ -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"
Expand Down
53 changes: 40 additions & 13 deletions src/cli/self_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<()> {
Expand Down
3 changes: 3 additions & 0 deletions src/test/clitools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion tests/suite/cli_inst_interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
...
"#]]);
Expand Down
Loading