From 3f5e45882699b5819b53a92bd669dffd82729db9 Mon Sep 17 00:00:00 2001 From: Varphone Wong Date: Thu, 28 Mar 2024 09:36:40 +0800 Subject: [PATCH] Auto detect c/cpp compiler by source file extension for Clang/Gnu toolset Signed-off-by: Varphone Wong --- src/lib.rs | 8 ++--- src/tool.rs | 61 +++++++++++++++++++++++++++++++++++++-- src/windows/find_tools.rs | 2 +- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7a9794c2f..4713dd4ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -664,7 +664,7 @@ impl Build { compiler.push_cc_arg("-Wno-unused-command-line-argument".into()); } - let mut cmd = compiler.to_command(); + let mut cmd = compiler.to_command(None); let is_arm = target.contains("aarch64") || target.contains("arm"); let clang = compiler.is_like_clang(); let gnu = compiler.family == ToolFamily::Gnu; @@ -1621,7 +1621,7 @@ impl Build { let (cmd, name) = self.msvc_macro_assembler()?; (cmd, Cow::Borrowed(Path::new(name))) } else { - let mut cmd = compiler.to_command(); + let mut cmd = compiler.to_command(Some(&obj.src)); for (a, b) in self.env.iter() { cmd.env(a, b); } @@ -1667,7 +1667,7 @@ impl Build { /// This will return a result instead of panicking; see expand() for the complete description. pub fn try_expand(&self) -> Result, Error> { let compiler = self.try_get_compiler()?; - let mut cmd = compiler.to_command(); + let mut cmd = compiler.to_command(None); for (a, b) in self.env.iter() { cmd.env(a, b); } @@ -2433,7 +2433,7 @@ impl Build { let out_dir = self.get_out_dir()?; let dlink = out_dir.join(lib_name.to_owned() + "_dlink.o"); - let mut nvcc = self.get_compiler().to_command(); + let mut nvcc = self.get_compiler().to_command(None); nvcc.arg("--device-link").arg("-o").arg(&dlink).arg(dst); run(&mut nvcc, "nvcc", &self.cargo_output)?; self.assemble_progressive(dst, &[dlink.as_path()])?; diff --git a/src/tool.rs b/src/tool.rs index a37439262..071353dd5 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -264,19 +264,72 @@ impl Tool { } } + /// Returns preferred compiler for source file. + fn preferred_compiler_for_source(&self, src: Option<&PathBuf>) -> (PathBuf, &[OsString]) { + let mut path = self.path.clone(); + let mut extra_args: &[OsString] = &[]; + if let Some(src) = src { + let mut is_c = false; + let mut is_cpp = false; + if let Some(ext) = src.extension().and_then(|x| x.to_str()) { + match ext { + "c" => { + is_c = true; + } + "cc" | "cpp" | "cxx" | "c++" => { + is_cpp = true; + } + _ => {} + } + } + match self.family { + ToolFamily::Clang { zig_cc } if !zig_cc => { + let s = path.to_string_lossy().to_string(); + if is_c { + path = PathBuf::from(s.replace("clang++", "clang")); + extra_args = &self.c_args; + } + if is_cpp { + if s.ends_with("clang") { + path = PathBuf::from(s.replace("clang", "clang++")); + } + extra_args = &self.cpp_args; + } + } + ToolFamily::Gnu => { + let s = path.to_string_lossy().to_string(); + if is_c { + path = PathBuf::from(s.replace("g++", "gcc")); + extra_args = &self.c_args; + } + if is_cpp { + path = PathBuf::from(s.replace("gcc", "g++")); + extra_args = &self.cpp_args; + } + } + _ => {} + } + } + (path, extra_args) + } + /// Converts this compiler into a `Command` that's ready to be run. /// /// This is useful for when the compiler needs to be executed and the /// command returned will already have the initial arguments and environment /// variables configured. - pub fn to_command(&self) -> Command { + /// + /// The `src` argument is used to determine the preferred compiler for the + /// source file. If `None`, the default compiler is used. + pub fn to_command(&self, src: Option<&PathBuf>) -> Command { + let (path, extra_args) = self.preferred_compiler_for_source(src); let mut cmd = match self.cc_wrapper_path { Some(ref cc_wrapper_path) => { let mut cmd = Command::new(cc_wrapper_path); - cmd.arg(&self.path); + cmd.arg(&path); cmd } - None => Command::new(&self.path), + None => Command::new(&path), }; cmd.args(&self.cc_wrapper_args); @@ -287,6 +340,8 @@ impl Tool { .collect::>(); cmd.args(&value); + cmd.args(extra_args); + for (k, v) in self.env.iter() { cmd.env(k, v); } diff --git a/src/windows/find_tools.rs b/src/windows/find_tools.rs index 79ce3cb07..1ff8308d5 100644 --- a/src/windows/find_tools.rs +++ b/src/windows/find_tools.rs @@ -49,7 +49,7 @@ impl<'a> From> for &'a str { /// /// Note that this function always returns `None` for non-MSVC targets. pub fn find(target: &str, tool: &str) -> Option { - find_tool(target, tool).map(|c| c.to_command()) + find_tool(target, tool).map(|c| c.to_command(None)) } /// Similar to the `find` function above, this function will attempt the same