Skip to content

Commit 23cfc81

Browse files
committed
Auto detect c/cpp compiler by source file extension for Clang/Gnu toolset
Signed-off-by: Varphone Wong <[email protected]>
1 parent ecbdfab commit 23cfc81

File tree

3 files changed

+63
-8
lines changed

3 files changed

+63
-8
lines changed

src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,7 @@ impl Build {
687687
compiler.push_cc_arg("-Wno-unused-command-line-argument".into());
688688
}
689689

690-
let mut cmd = compiler.to_command();
690+
let mut cmd = compiler.to_command(None);
691691
let is_arm = target.contains("aarch64") || target.contains("arm");
692692
let clang = compiler.is_like_clang();
693693
let gnu = compiler.family == ToolFamily::Gnu;
@@ -1648,7 +1648,7 @@ impl Build {
16481648
let (cmd, name) = self.msvc_macro_assembler()?;
16491649
(cmd, Cow::Borrowed(Path::new(name)))
16501650
} else {
1651-
let mut cmd = compiler.to_command();
1651+
let mut cmd = compiler.to_command(Some(&obj.src));
16521652
for (a, b) in self.env.iter() {
16531653
cmd.env(a, b);
16541654
}
@@ -1704,7 +1704,7 @@ impl Build {
17041704
/// This will return a result instead of panicking; see expand() for the complete description.
17051705
pub fn try_expand(&self) -> Result<Vec<u8>, Error> {
17061706
let compiler = self.try_get_compiler()?;
1707-
let mut cmd = compiler.to_command();
1707+
let mut cmd = compiler.to_command(None);
17081708
for (a, b) in self.env.iter() {
17091709
cmd.env(a, b);
17101710
}
@@ -2508,7 +2508,7 @@ impl Build {
25082508

25092509
let out_dir = self.get_out_dir()?;
25102510
let dlink = out_dir.join(lib_name.to_owned() + "_dlink.o");
2511-
let mut nvcc = self.get_compiler().to_command();
2511+
let mut nvcc = self.get_compiler().to_command(None);
25122512
nvcc.arg("--device-link").arg("-o").arg(&dlink).arg(dst);
25132513
run(&mut nvcc, "nvcc", &self.cargo_output)?;
25142514
self.assemble_progressive(dst, &[dlink.as_path()])?;

src/tool.rs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,19 +290,72 @@ impl Tool {
290290
}
291291
}
292292

293+
/// Returns preferred compiler for source file.
294+
fn preferred_compiler_for_source(&self, src: Option<&PathBuf>) -> (PathBuf, &[OsString]) {
295+
let mut path = self.path.clone();
296+
let mut extra_args: &[OsString] = &[];
297+
if let Some(src) = src {
298+
let mut is_c = false;
299+
let mut is_cpp = false;
300+
if let Some(ext) = src.extension().and_then(|x| x.to_str()) {
301+
match ext {
302+
"c" => {
303+
is_c = true;
304+
}
305+
"cc" | "cpp" | "cxx" | "c++" => {
306+
is_cpp = true;
307+
}
308+
_ => {}
309+
}
310+
}
311+
match self.family {
312+
ToolFamily::Clang { zig_cc } if !zig_cc => {
313+
let s = path.to_string_lossy().to_string();
314+
if is_c {
315+
path = PathBuf::from(s.replace("clang++", "clang"));
316+
extra_args = &self.c_args;
317+
}
318+
if is_cpp {
319+
if s.ends_with("clang") {
320+
path = PathBuf::from(s.replace("clang", "clang++"));
321+
}
322+
extra_args = &self.cpp_args;
323+
}
324+
}
325+
ToolFamily::Gnu => {
326+
let s = path.to_string_lossy().to_string();
327+
if is_c {
328+
path = PathBuf::from(s.replace("g++", "gcc"));
329+
extra_args = &self.c_args;
330+
}
331+
if is_cpp {
332+
path = PathBuf::from(s.replace("gcc", "g++"));
333+
extra_args = &self.cpp_args;
334+
}
335+
}
336+
_ => {}
337+
}
338+
}
339+
(path, extra_args)
340+
}
341+
293342
/// Converts this compiler into a `Command` that's ready to be run.
294343
///
295344
/// This is useful for when the compiler needs to be executed and the
296345
/// command returned will already have the initial arguments and environment
297346
/// variables configured.
298-
pub fn to_command(&self) -> Command {
347+
///
348+
/// The `src` argument is used to determine the preferred compiler for the
349+
/// source file. If `None`, the default compiler is used.
350+
pub fn to_command(&self, src: Option<&PathBuf>) -> Command {
351+
let (path, extra_args) = self.preferred_compiler_for_source(src);
299352
let mut cmd = match self.cc_wrapper_path {
300353
Some(ref cc_wrapper_path) => {
301354
let mut cmd = Command::new(cc_wrapper_path);
302-
cmd.arg(&self.path);
355+
cmd.arg(&path);
303356
cmd
304357
}
305-
None => Command::new(&self.path),
358+
None => Command::new(&path),
306359
};
307360
cmd.args(&self.cc_wrapper_args);
308361

@@ -313,6 +366,8 @@ impl Tool {
313366
.collect::<Vec<_>>();
314367
cmd.args(&value);
315368

369+
cmd.args(extra_args);
370+
316371
for (k, v) in self.env.iter() {
317372
cmd.env(k, v);
318373
}

src/windows/find_tools.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ impl<'a> From<TargetArch<'a>> for &'a str {
4949
///
5050
/// Note that this function always returns `None` for non-MSVC targets.
5151
pub fn find(target: &str, tool: &str) -> Option<Command> {
52-
find_tool(target, tool).map(|c| c.to_command())
52+
find_tool(target, tool).map(|c| c.to_command(None))
5353
}
5454

5555
/// Similar to the `find` function above, this function will attempt the same

0 commit comments

Comments
 (0)