diff --git a/src/lib.rs b/src/lib.rs index f4ed815e..4c288d64 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -687,7 +687,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; @@ -1648,7 +1648,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); } @@ -1704,7 +1704,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); } @@ -2508,7 +2508,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 27840254..aed1f41f 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -290,19 +290,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); @@ -313,6 +366,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 c4a92bde..68fad002 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