Skip to content

Commit b886474

Browse files
authored
Fix compiler family detection issue with clang-cl on macOS (#1328)
1 parent 41a0613 commit b886474

File tree

3 files changed

+75
-42
lines changed

3 files changed

+75
-42
lines changed

src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,10 @@ impl Build {
725725
},
726726
);
727727

728+
if compiler.supports_path_delimiter() {
729+
cmd.arg("--");
730+
}
731+
728732
cmd.arg(&src);
729733

730734
// On MSVC skip the CRT by setting the entry point to `main`.
@@ -1795,14 +1799,16 @@ impl Build {
17951799
if is_asm {
17961800
cmd.args(self.asm_flags.iter().map(std::ops::Deref::deref));
17971801
}
1798-
if compiler.family == (ToolFamily::Msvc { clang_cl: true }) && !is_assembler_msvc {
1802+
1803+
if compiler.supports_path_delimiter() && !is_assembler_msvc {
17991804
// #513: For `clang-cl`, separate flags/options from the input file.
18001805
// When cross-compiling macOS -> Windows, this avoids interpreting
18011806
// common `/Users/...` paths as the `/U` flag and triggering
18021807
// `-Wslash-u-filename` warning.
18031808
cmd.arg("--");
18041809
}
18051810
cmd.arg(&obj.src);
1811+
18061812
if cfg!(target_os = "macos") {
18071813
self.fix_env_for_apple_os(&mut cmd)?;
18081814
}

src/tool.rs

Lines changed: 66 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,46 @@ impl Tool {
105105
.unwrap_or_default()
106106
}
107107

108+
fn guess_family_from_stdout(
109+
stdout: &str,
110+
path: &Path,
111+
cargo_output: &CargoOutput,
112+
) -> Result<ToolFamily, Error> {
113+
cargo_output.print_debug(&stdout);
114+
115+
// https://gitlab.kitware.com/cmake/cmake/-/blob/69a2eeb9dff5b60f2f1e5b425002a0fd45b7cadb/Modules/CMakeDetermineCompilerId.cmake#L267-271
116+
// stdin is set to null to ensure that the help output is never paginated.
117+
let accepts_cl_style_flags =
118+
run(Command::new(path).arg("-?").stdin(Stdio::null()), path, &{
119+
// the errors are not errors!
120+
let mut cargo_output = cargo_output.clone();
121+
cargo_output.warnings = cargo_output.debug;
122+
cargo_output.output = OutputKind::Discard;
123+
cargo_output
124+
})
125+
.is_ok();
126+
127+
let clang = stdout.contains(r#""clang""#);
128+
let gcc = stdout.contains(r#""gcc""#);
129+
let emscripten = stdout.contains(r#""emscripten""#);
130+
let vxworks = stdout.contains(r#""VxWorks""#);
131+
132+
match (clang, accepts_cl_style_flags, gcc, emscripten, vxworks) {
133+
(clang_cl, true, _, false, false) => Ok(ToolFamily::Msvc { clang_cl }),
134+
(true, _, _, _, false) | (_, _, _, true, false) => Ok(ToolFamily::Clang {
135+
zig_cc: is_zig_cc(path, cargo_output),
136+
}),
137+
(false, false, true, _, false) | (_, _, _, _, true) => Ok(ToolFamily::Gnu),
138+
(false, false, false, false, false) => {
139+
cargo_output.print_warning(&"Compiler family detection failed since it does not define `__clang__`, `__GNUC__`, `__EMSCRIPTEN__` or `__VXWORKS__`, also does not accept cl style flag `-?`, fallback to treating it as GNU");
140+
Err(Error::new(
141+
ErrorKind::ToolFamilyMacroNotFound,
142+
"Expects macro `__clang__`, `__GNUC__` or `__EMSCRIPTEN__`, `__VXWORKS__` or accepts cl style flag `-?`, but found none",
143+
))
144+
}
145+
}
146+
}
147+
108148
fn detect_family_inner(
109149
path: &Path,
110150
cargo_output: &CargoOutput,
@@ -140,53 +180,30 @@ impl Tool {
140180
tmp_file.sync_data()?;
141181
drop(tmp_file);
142182

183+
// When expanding the file, the compiler prints a lot of information to stderr
184+
// that it is not an error, but related to expanding itself.
185+
//
186+
// cc would have to disable warning here to prevent generation of too many warnings.
187+
let mut compiler_detect_output = cargo_output.clone();
188+
compiler_detect_output.warnings = compiler_detect_output.debug;
189+
143190
let stdout = run_output(
144191
Command::new(path).arg("-E").arg(tmp.path()),
145192
path,
146-
// When expanding the file, the compiler prints a lot of information to stderr
147-
// that it is not an error, but related to expanding itself.
148-
//
149-
// cc would have to disable warning here to prevent generation of too many warnings.
150-
&{
151-
let mut cargo_output = cargo_output.clone();
152-
cargo_output.warnings = cargo_output.debug;
153-
cargo_output
154-
},
193+
&compiler_detect_output,
155194
)?;
156195
let stdout = String::from_utf8_lossy(&stdout);
157196

158-
cargo_output.print_debug(&stdout);
159-
160-
// https://gitlab.kitware.com/cmake/cmake/-/blob/69a2eeb9dff5b60f2f1e5b425002a0fd45b7cadb/Modules/CMakeDetermineCompilerId.cmake#L267-271
161-
// stdin is set to null to ensure that the help output is never paginated.
162-
let accepts_cl_style_flags =
163-
run(Command::new(path).arg("-?").stdin(Stdio::null()), path, &{
164-
// the errors are not errors!
165-
let mut cargo_output = cargo_output.clone();
166-
cargo_output.warnings = cargo_output.debug;
167-
cargo_output.output = OutputKind::Discard;
168-
cargo_output
169-
})
170-
.is_ok();
171-
172-
let clang = stdout.contains(r#""clang""#);
173-
let gcc = stdout.contains(r#""gcc""#);
174-
let emscripten = stdout.contains(r#""emscripten""#);
175-
let vxworks = stdout.contains(r#""VxWorks""#);
176-
177-
match (clang, accepts_cl_style_flags, gcc, emscripten, vxworks) {
178-
(clang_cl, true, _, false, false) => Ok(ToolFamily::Msvc { clang_cl }),
179-
(true, _, _, _, false) | (_, _, _, true, false) => Ok(ToolFamily::Clang {
180-
zig_cc: is_zig_cc(path, cargo_output),
181-
}),
182-
(false, false, true, _, false) | (_, _, _, _, true) => Ok(ToolFamily::Gnu),
183-
(false, false, false, false, false) => {
184-
cargo_output.print_warning(&"Compiler family detection failed since it does not define `__clang__`, `__GNUC__`, `__EMSCRIPTEN__` or `__VXWORKS__`, also does not accept cl style flag `-?`, fallback to treating it as GNU");
185-
Err(Error::new(
186-
ErrorKind::ToolFamilyMacroNotFound,
187-
"Expects macro `__clang__`, `__GNUC__` or `__EMSCRIPTEN__`, `__VXWORKS__` or accepts cl style flag `-?`, but found none",
188-
))
189-
}
197+
if stdout.contains("-Wslash-u-filename") {
198+
let stdout = run_output(
199+
Command::new(path).arg("-E").arg("--").arg(tmp.path()),
200+
path,
201+
&compiler_detect_output,
202+
)?;
203+
let stdout = String::from_utf8_lossy(&stdout);
204+
guess_family_from_stdout(&stdout, path, cargo_output)
205+
} else {
206+
guess_family_from_stdout(&stdout, path, cargo_output)
190207
}
191208
}
192209
let detect_family = |path: &Path| -> Result<ToolFamily, Error> {
@@ -403,6 +420,14 @@ impl Tool {
403420
pub fn is_like_msvc(&self) -> bool {
404421
matches!(self.family, ToolFamily::Msvc { .. })
405422
}
423+
424+
/// Supports using `--` delimiter to separate arguments and path to source files.
425+
pub(crate) fn supports_path_delimiter(&self) -> bool {
426+
matches!(
427+
self.family,
428+
ToolFamily::Clang { .. } | ToolFamily::Msvc { clang_cl: true }
429+
) && !self.cuda
430+
}
406431
}
407432

408433
/// Represents the family of tools this tool belongs to.

tests/test.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,8 @@ fn gnu_static() {
405405
}
406406

407407
#[test]
408+
// on macOS, cc/gcc is link to apple clang
409+
#[cfg_attr(target_os = "macos", ignore)]
408410
fn gnu_no_dash_dash() {
409411
let test = Test::gnu();
410412
test.gcc().file("foo.c").compile("foo");

0 commit comments

Comments
 (0)