Skip to content

Commit

Permalink
Include wrapper args. in stdout family heuristics to restore classi…
Browse files Browse the repository at this point in the history
…fying `clang --driver-mode=cl` as `Msvc { clang_cl: true }` (rust-lang#1378)
  • Loading branch information
ErichDonGubler committed Feb 9, 2025
1 parent dcd8ed3 commit 750671b
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 38 deletions.
16 changes: 5 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ use command_helpers::*;

mod tool;
pub use tool::Tool;
use tool::ToolFamily;
use tool::{CompilerFamilyLookupCache, ToolFamily};

mod target_info;
mod tempfile;
Expand Down Expand Up @@ -301,7 +301,7 @@ pub struct Build {
apple_sdk_root_cache: Arc<RwLock<HashMap<Box<str>, Arc<OsStr>>>>,
apple_versions_cache: Arc<RwLock<HashMap<Box<str>, Arc<str>>>>,
emit_rerun_if_env_changed: bool,
cached_compiler_family: Arc<RwLock<HashMap<Box<Path>, ToolFamily>>>,
cached_compiler_family: Arc<RwLock<CompilerFamilyLookupCache>>,
}

/// Represents the types of errors that may occur while using cc-rs.
Expand Down Expand Up @@ -2844,19 +2844,13 @@ impl Build {
let tool_opt: Option<Tool> = self
.env_tool(env)
.map(|(tool, wrapper, args)| {
// find the driver mode, if any
const DRIVER_MODE: &str = "--driver-mode=";
let driver_mode = args
.iter()
.find(|a| a.starts_with(DRIVER_MODE))
.map(|a| &a[DRIVER_MODE.len()..]);
// Chop off leading/trailing whitespace to work around
// semi-buggy build scripts which are shared in
// makefiles/configure scripts (where spaces are far more
// lenient)
let mut t = Tool::with_clang_driver(
let mut t = Tool::with_args(
tool,
driver_mode,
args.clone(),
&self.cached_compiler_family,
&self.cargo_output,
out_dir,
Expand Down Expand Up @@ -2968,7 +2962,7 @@ impl Build {
};
let mut nvcc_tool = Tool::with_features(
nvcc,
None,
vec![],
self.cuda,
&self.cached_compiler_family,
&self.cargo_output,
Expand Down
75 changes: 48 additions & 27 deletions src/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use crate::{
Error, ErrorKind, OutputKind,
};

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

/// Configuration used to represent an invocation of a C compiler.
///
/// This can be used to figure out what compiler is in use, what the arguments
Expand All @@ -40,30 +42,30 @@ pub struct Tool {
impl Tool {
pub(crate) fn new(
path: PathBuf,
cached_compiler_family: &RwLock<HashMap<Box<Path>, ToolFamily>>,
cached_compiler_family: &std::sync::Arc<RwLock<CompilerFamilyLookupCache>>,
cargo_output: &CargoOutput,
out_dir: Option<&Path>,
) -> Self {
Self::with_features(
path,
None,
vec![],
false,
cached_compiler_family,
cargo_output,
out_dir,
)
}

pub(crate) fn with_clang_driver(
pub(crate) fn with_args(
path: PathBuf,
clang_driver: Option<&str>,
cached_compiler_family: &RwLock<HashMap<Box<Path>, ToolFamily>>,
args: Vec<String>,
cached_compiler_family: &std::sync::Arc<RwLock<CompilerFamilyLookupCache>>,
cargo_output: &CargoOutput,
out_dir: Option<&Path>,
) -> Self {
Self::with_features(
path,
clang_driver,
args,
false,
cached_compiler_family,
cargo_output,
Expand All @@ -88,9 +90,9 @@ impl Tool {

pub(crate) fn with_features(
path: PathBuf,
clang_driver: Option<&str>,
args: Vec<String>,
cuda: bool,
cached_compiler_family: &RwLock<HashMap<Box<Path>, ToolFamily>>,
cached_compiler_family: &std::sync::Arc<RwLock<CompilerFamilyLookupCache>>,
cargo_output: &CargoOutput,
out_dir: Option<&Path>,
) -> Self {
Expand All @@ -107,6 +109,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 @@ -158,15 +161,21 @@ impl Tool {
cargo_output.print_debug(&stdout);

// https://gitlab.kitware.com/cmake/cmake/-/blob/69a2eeb9dff5b60f2f1e5b425002a0fd45b7cadb/Modules/CMakeDetermineCompilerId.cmake#L267-271
let accepts_cl_style_flags = run(Command::new(path).arg("-?"), 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
})
let accepts_cl_style_flags = run(
Command::new(path)
.args(args)
.arg("-?")
.stdin(std::process::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();

let clang = stdout.contains(r#""clang""#);
let gcc = stdout.contains(r#""gcc""#);

Expand All @@ -185,20 +194,26 @@ impl Tool {
}
}
}
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.as_os_str()]
.iter()
.cloned()
.chain(args.iter().map(OsStr::new))
.map(Into::into)
.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 All @@ -208,12 +223,18 @@ impl Tool {
Some(fname) if fname.ends_with("cl") || fname == "cl.exe" => {
ToolFamily::Msvc { clang_cl: false }
}
Some(fname) if fname.contains("clang") => match clang_driver {
Some("cl") => ToolFamily::Msvc { clang_cl: true },
_ => ToolFamily::Clang {
zig_cc: is_zig_cc(&path, cargo_output),
},
},
Some(fname) if fname.contains("clang") => {
let is_clang_cl = args
.iter()
.any(|a| a.strip_prefix("--driver-mode=") == Some("cl"));
if is_clang_cl {
ToolFamily::Msvc { clang_cl: true }
} else {
ToolFamily::Clang {
zig_cc: is_zig_cc(&path, cargo_output),
}
}
}
Some(fname) if fname.contains("zig") => ToolFamily::Clang { zig_cc: true },
_ => ToolFamily::Gnu,
}
Expand Down

0 comments on commit 750671b

Please sign in to comment.