Skip to content

Commit

Permalink
fix: include wrapper args. in stdout family heuristics
Browse files Browse the repository at this point in the history
This can be particularly significant for compilers that can dynamically
change what options they accept based on arguments, like `clang
--driver-mode=cl`.
  • Loading branch information
ErichDonGubler committed Jan 31, 2025
1 parent 50a3f70 commit 17c805a
Showing 1 changed file with 22 additions and 12 deletions.
34 changes: 22 additions & 12 deletions src/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
Error, ErrorKind, OutputKind,
};

pub(crate) type CompilerFamilyLookupCache = HashMap<Box<Path>, ToolFamily>;
pub(crate) type CompilerFamilyLookupCache = HashMap<Box<[OsString]>, ToolFamily>;

/// Configuration used to represent an invocation of a C compiler.
///
Expand Down Expand Up @@ -116,21 +116,25 @@ impl Tool {
fn guess_family_from_stdout(
stdout: &str,
path: &Path,
args: &[String],
cargo_output: &CargoOutput,
) -> Result<ToolFamily, Error> {
cargo_output.print_debug(&stdout);

// https://gitlab.kitware.com/cmake/cmake/-/blob/69a2eeb9dff5b60f2f1e5b425002a0fd45b7cadb/Modules/CMakeDetermineCompilerId.cmake#L267-271
// stdin is set to null to ensure that the help output is never paginated.
let accepts_cl_style_flags =
run(Command::new(path).arg("-?").stdin(Stdio::null()), path, &{
let accepts_cl_style_flags = run(
Command::new(path).args(args).arg("-?").stdin(Stdio::null()),
path,
&{
// the errors are not errors!
let mut cargo_output = cargo_output.clone();
cargo_output.warnings = cargo_output.debug;
cargo_output.output = OutputKind::Discard;
cargo_output
})
.is_ok();
},
)
.is_ok();

let clang = stdout.contains(r#""clang""#);
let gcc = stdout.contains(r#""gcc""#);
Expand All @@ -155,6 +159,7 @@ impl Tool {

fn detect_family_inner(
path: &Path,
args: &[String],
cargo_output: &CargoOutput,
out_dir: Option<&Path>,
) -> Result<ToolFamily, Error> {
Expand Down Expand Up @@ -209,25 +214,30 @@ impl Tool {
&compiler_detect_output,
)?;
let stdout = String::from_utf8_lossy(&stdout);
guess_family_from_stdout(&stdout, path, cargo_output)
guess_family_from_stdout(&stdout, path, args, cargo_output)
} else {
guess_family_from_stdout(&stdout, path, cargo_output)
guess_family_from_stdout(&stdout, path, args, cargo_output)
}
}
let detect_family = |path: &Path| -> Result<ToolFamily, Error> {
if let Some(family) = cached_compiler_family.read().unwrap().get(path) {
let detect_family = |path: &Path, args: &[String]| -> Result<ToolFamily, Error> {
let cache_key = [path]
.iter()
.map(|p| p.as_os_str().to_owned())
.chain(args.iter().map(|a| OsStr::new(a).to_owned()))
.collect();
if let Some(family) = cached_compiler_family.read().unwrap().get(&cache_key) {
return Ok(*family);
}

let family = detect_family_inner(path, cargo_output, out_dir)?;
let family = { detect_family_inner(path, args, cargo_output, out_dir)? };
cached_compiler_family
.write()
.unwrap()
.insert(path.into(), family);
.insert(cache_key, family);
Ok(family)
};

let family = detect_family(&path).unwrap_or_else(|e| {
let family = detect_family(&path, &args).unwrap_or_else(|e| {
cargo_output.print_warning(&format_args!(
"Compiler family detection failed due to error: {}",
e
Expand Down

0 comments on commit 17c805a

Please sign in to comment.