Skip to content

Commit 3f5e458

Browse files
committed
Auto detect c/cpp compiler by source file extension for Clang/Gnu toolset
Signed-off-by: Varphone Wong <varphone@qq.com>
1 parent 6acdd67 commit 3f5e458

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
@@ -664,7 +664,7 @@ impl Build {
664664
compiler.push_cc_arg("-Wno-unused-command-line-argument".into());
665665
}
666666

667-
let mut cmd = compiler.to_command();
667+
let mut cmd = compiler.to_command(None);
668668
let is_arm = target.contains("aarch64") || target.contains("arm");
669669
let clang = compiler.is_like_clang();
670670
let gnu = compiler.family == ToolFamily::Gnu;
@@ -1621,7 +1621,7 @@ impl Build {
16211621
let (cmd, name) = self.msvc_macro_assembler()?;
16221622
(cmd, Cow::Borrowed(Path::new(name)))
16231623
} else {
1624-
let mut cmd = compiler.to_command();
1624+
let mut cmd = compiler.to_command(Some(&obj.src));
16251625
for (a, b) in self.env.iter() {
16261626
cmd.env(a, b);
16271627
}
@@ -1667,7 +1667,7 @@ impl Build {
16671667
/// This will return a result instead of panicking; see expand() for the complete description.
16681668
pub fn try_expand(&self) -> Result<Vec<u8>, Error> {
16691669
let compiler = self.try_get_compiler()?;
1670-
let mut cmd = compiler.to_command();
1670+
let mut cmd = compiler.to_command(None);
16711671
for (a, b) in self.env.iter() {
16721672
cmd.env(a, b);
16731673
}
@@ -2433,7 +2433,7 @@ impl Build {
24332433

24342434
let out_dir = self.get_out_dir()?;
24352435
let dlink = out_dir.join(lib_name.to_owned() + "_dlink.o");
2436-
let mut nvcc = self.get_compiler().to_command();
2436+
let mut nvcc = self.get_compiler().to_command(None);
24372437
nvcc.arg("--device-link").arg("-o").arg(&dlink).arg(dst);
24382438
run(&mut nvcc, "nvcc", &self.cargo_output)?;
24392439
self.assemble_progressive(dst, &[dlink.as_path()])?;

src/tool.rs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,19 +264,72 @@ impl Tool {
264264
}
265265
}
266266

267+
/// Returns preferred compiler for source file.
268+
fn preferred_compiler_for_source(&self, src: Option<&PathBuf>) -> (PathBuf, &[OsString]) {
269+
let mut path = self.path.clone();
270+
let mut extra_args: &[OsString] = &[];
271+
if let Some(src) = src {
272+
let mut is_c = false;
273+
let mut is_cpp = false;
274+
if let Some(ext) = src.extension().and_then(|x| x.to_str()) {
275+
match ext {
276+
"c" => {
277+
is_c = true;
278+
}
279+
"cc" | "cpp" | "cxx" | "c++" => {
280+
is_cpp = true;
281+
}
282+
_ => {}
283+
}
284+
}
285+
match self.family {
286+
ToolFamily::Clang { zig_cc } if !zig_cc => {
287+
let s = path.to_string_lossy().to_string();
288+
if is_c {
289+
path = PathBuf::from(s.replace("clang++", "clang"));
290+
extra_args = &self.c_args;
291+
}
292+
if is_cpp {
293+
if s.ends_with("clang") {
294+
path = PathBuf::from(s.replace("clang", "clang++"));
295+
}
296+
extra_args = &self.cpp_args;
297+
}
298+
}
299+
ToolFamily::Gnu => {
300+
let s = path.to_string_lossy().to_string();
301+
if is_c {
302+
path = PathBuf::from(s.replace("g++", "gcc"));
303+
extra_args = &self.c_args;
304+
}
305+
if is_cpp {
306+
path = PathBuf::from(s.replace("gcc", "g++"));
307+
extra_args = &self.cpp_args;
308+
}
309+
}
310+
_ => {}
311+
}
312+
}
313+
(path, extra_args)
314+
}
315+
267316
/// Converts this compiler into a `Command` that's ready to be run.
268317
///
269318
/// This is useful for when the compiler needs to be executed and the
270319
/// command returned will already have the initial arguments and environment
271320
/// variables configured.
272-
pub fn to_command(&self) -> Command {
321+
///
322+
/// The `src` argument is used to determine the preferred compiler for the
323+
/// source file. If `None`, the default compiler is used.
324+
pub fn to_command(&self, src: Option<&PathBuf>) -> Command {
325+
let (path, extra_args) = self.preferred_compiler_for_source(src);
273326
let mut cmd = match self.cc_wrapper_path {
274327
Some(ref cc_wrapper_path) => {
275328
let mut cmd = Command::new(cc_wrapper_path);
276-
cmd.arg(&self.path);
329+
cmd.arg(&path);
277330
cmd
278331
}
279-
None => Command::new(&self.path),
332+
None => Command::new(&path),
280333
};
281334
cmd.args(&self.cc_wrapper_args);
282335

@@ -287,6 +340,8 @@ impl Tool {
287340
.collect::<Vec<_>>();
288341
cmd.args(&value);
289342

343+
cmd.args(extra_args);
344+
290345
for (k, v) in self.env.iter() {
291346
cmd.env(k, v);
292347
}

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)