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 }` (#1378)
  • Loading branch information
ErichDonGubler authored Jan 31, 2025
1 parent 65b4d9a commit 3a4a86d
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 36 deletions.
16 changes: 5 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ use command_helpers::*;

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

mod tempfile;

Expand All @@ -277,7 +277,7 @@ struct BuildCache {
env_cache: RwLock<HashMap<Box<str>, Env>>,
apple_sdk_root_cache: RwLock<HashMap<Box<str>, Arc<OsStr>>>,
apple_versions_cache: RwLock<HashMap<Box<str>, Arc<str>>>,
cached_compiler_family: RwLock<HashMap<Box<Path>, ToolFamily>>,
cached_compiler_family: RwLock<CompilerFamilyLookupCache>,
known_flag_support_status_cache: RwLock<HashMap<CompilerFlag, bool>>,
target_info_parser: target::TargetInfoParser,
}
Expand Down Expand Up @@ -2739,19 +2739,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.build_cache.cached_compiler_family,
&self.cargo_output,
out_dir,
Expand Down Expand Up @@ -2871,7 +2865,7 @@ impl Build {
};
let mut nvcc_tool = Tool::with_features(
nvcc,
None,
vec![],
self.cuda,
&self.build_cache.cached_compiler_family,
&self.cargo_output,
Expand Down
69 changes: 44 additions & 25 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: &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: &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: &RwLock<CompilerFamilyLookupCache>,
cargo_output: &CargoOutput,
out_dir: Option<&Path>,
) -> Self {
Expand All @@ -114,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 @@ -153,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 @@ -207,25 +214,31 @@ 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.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 @@ -235,12 +248,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
1 change: 1 addition & 0 deletions tests/rustflags.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[cfg(not(windows))]
use crate::support::Test;
mod support;

Expand Down

0 comments on commit 3a4a86d

Please sign in to comment.