Skip to content

Commit f36d6a7

Browse files
authored
Fix compile family detection: Use C macros instead of $compiler -v (#1000)
1 parent 77a54a9 commit f36d6a7

File tree

8 files changed

+256
-85
lines changed

8 files changed

+256
-85
lines changed

.github/workflows/main.yml

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on: [push, pull_request]
44
env:
55
CARGO_INCREMENTAL: 0
66
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
7+
CC_ENABLE_DEBUG_OUTPUT: true
78

89
jobs:
910
test:

dev-tools/cc-test/build.rs

+10
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,15 @@ fn run_action_if_forked() -> bool {
156156
true
157157
}
158158

159+
fn disable_debug_output() {
160+
// That env would break tests for warning/debug output,
161+
// and it is set in the CI, to make debugging CI failure easier.
162+
std::env::remove_var("CC_ENABLE_DEBUG_OUTPUT");
163+
}
164+
159165
fn build_cargo_warnings(warnings: bool) {
166+
disable_debug_output();
167+
160168
cc::Build::new()
161169
.cargo_metadata(false)
162170
.cargo_warnings(warnings)
@@ -166,6 +174,8 @@ fn build_cargo_warnings(warnings: bool) {
166174
}
167175

168176
fn build_cargo_metadata(metadata: bool) {
177+
disable_debug_output();
178+
169179
cc::Build::new()
170180
.cargo_metadata(metadata)
171181
.file("src/dummy.c")

dev-tools/gen-windows-sys-binding/windows_sys.list

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ Windows.Win32.System.Registry.REG_SZ
3737

3838
Windows.Win32.System.SystemInformation.IMAGE_FILE_MACHINE_AMD64
3939

40+
Windows.Win32.Storage.FileSystem.FILE_ATTRIBUTE_TEMPORARY
41+
4042
Windows.Win32.System.Threading.GetMachineTypeAttributes
4143
Windows.Win32.System.Threading.ReleaseSemaphore
4244
Windows.Win32.System.Threading.WaitForSingleObject

src/detect_compiler_family.c

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#ifdef __clang__
2+
#pragma message "clang"
3+
#endif
4+
5+
#ifdef __GNUC__
6+
#pragma message "gcc"
7+
#endif
8+
9+
#ifdef _MSC_VER
10+
#pragma message "msvc"
11+
#endif

src/lib.rs

+23-11
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ pub use tool::Tool;
248248
use tool::ToolFamily;
249249

250250
mod target_info;
251+
mod tempfile;
251252

252253
/// A builder for compilation of a native library.
253254
///
@@ -314,6 +315,8 @@ enum ErrorKind {
314315
ToolNotFound,
315316
/// One of the function arguments failed validation.
316317
InvalidArgument,
318+
/// No known macro is defined for the compiler when discovering tool family
319+
ToolFamilyMacroNotFound,
317320
/// Invalid target
318321
InvalidTarget,
319322
#[cfg(feature = "parallel")]
@@ -621,15 +624,15 @@ impl Build {
621624
if compiler.family.verbose_stderr() {
622625
compiler.remove_arg("-v".into());
623626
}
624-
if compiler.family == ToolFamily::Clang {
627+
if compiler.is_like_clang() {
625628
// Avoid reporting that the arg is unsupported just because the
626629
// compiler complains that it wasn't used.
627630
compiler.push_cc_arg("-Wno-unused-command-line-argument".into());
628631
}
629632

630633
let mut cmd = compiler.to_command();
631634
let is_arm = target.contains("aarch64") || target.contains("arm");
632-
let clang = compiler.family == ToolFamily::Clang;
635+
let clang = compiler.is_like_clang();
633636
let gnu = compiler.family == ToolFamily::Gnu;
634637
command_add_output_file(
635638
&mut cmd,
@@ -1576,7 +1579,7 @@ impl Build {
15761579
let target = self.get_target()?;
15771580
let msvc = target.contains("msvc");
15781581
let compiler = self.try_get_compiler()?;
1579-
let clang = compiler.family == ToolFamily::Clang;
1582+
let clang = compiler.is_like_clang();
15801583
let gnu = compiler.family == ToolFamily::Gnu;
15811584

15821585
let is_assembler_msvc = msvc && asm_ext == Some(AsmFileExt::DotAsm);
@@ -1732,7 +1735,7 @@ impl Build {
17321735
if let Some(ref std) = self.std {
17331736
let separator = match cmd.family {
17341737
ToolFamily::Msvc { .. } => ':',
1735-
ToolFamily::Gnu | ToolFamily::Clang => '=',
1738+
ToolFamily::Gnu | ToolFamily::Clang { .. } => '=',
17361739
};
17371740
cmd.push_cc_arg(format!("-std{}{}", separator, std).into());
17381741
}
@@ -1825,23 +1828,23 @@ impl Build {
18251828
_ => {}
18261829
}
18271830
}
1828-
ToolFamily::Gnu | ToolFamily::Clang => {
1831+
ToolFamily::Gnu | ToolFamily::Clang { .. } => {
18291832
// arm-linux-androideabi-gcc 4.8 shipped with Android NDK does
18301833
// not support '-Oz'
1831-
if opt_level == "z" && cmd.family != ToolFamily::Clang {
1834+
if opt_level == "z" && !cmd.is_like_clang() {
18321835
cmd.push_opt_unless_duplicate("-Os".into());
18331836
} else {
18341837
cmd.push_opt_unless_duplicate(format!("-O{}", opt_level).into());
18351838
}
18361839

1837-
if cmd.family == ToolFamily::Clang && target.contains("windows") {
1840+
if cmd.is_like_clang() && target.contains("windows") {
18381841
// Disambiguate mingw and msvc on Windows. Problem is that
18391842
// depending on the origin clang can default to a mismatchig
18401843
// run-time.
18411844
cmd.push_cc_arg(format!("--target={}", target).into());
18421845
}
18431846

1844-
if cmd.family == ToolFamily::Clang && target.contains("android") {
1847+
if cmd.is_like_clang() && target.contains("android") {
18451848
// For compatibility with code that doesn't use pre-defined `__ANDROID__` macro.
18461849
// If compiler used via ndk-build or cmake (officially supported build methods)
18471850
// this macros is defined.
@@ -1899,7 +1902,7 @@ impl Build {
18991902

19001903
// Target flags
19011904
match cmd.family {
1902-
ToolFamily::Clang => {
1905+
ToolFamily::Clang { .. } => {
19031906
if !cmd.has_internal_target_arg
19041907
&& !(target.contains("android")
19051908
&& android_clang_compiler_uses_target_arg_internally(&cmd.path))
@@ -2290,7 +2293,7 @@ impl Build {
22902293
if self.cpp {
22912294
match (self.cpp_set_stdlib.as_ref(), cmd.family) {
22922295
(None, _) => {}
2293-
(Some(stdlib), ToolFamily::Gnu) | (Some(stdlib), ToolFamily::Clang) => {
2296+
(Some(stdlib), ToolFamily::Gnu) | (Some(stdlib), ToolFamily::Clang { .. }) => {
22942297
cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into());
22952298
}
22962299
_ => {
@@ -2666,11 +2669,15 @@ impl Build {
26662669
}
26672670

26682671
fn get_base_compiler(&self) -> Result<Tool, Error> {
2672+
let out_dir = self.get_out_dir().ok();
2673+
let out_dir = out_dir.as_deref();
2674+
26692675
if let Some(c) = &self.compiler {
26702676
return Ok(Tool::new(
26712677
(**c).to_owned(),
26722678
&self.cached_compiler_family,
26732679
&self.cargo_output,
2680+
out_dir,
26742681
));
26752682
}
26762683
let host = self.get_host()?;
@@ -2712,6 +2719,7 @@ impl Build {
27122719
driver_mode,
27132720
&self.cached_compiler_family,
27142721
&self.cargo_output,
2722+
out_dir,
27152723
);
27162724
if let Some(cc_wrapper) = wrapper {
27172725
t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper));
@@ -2730,6 +2738,7 @@ impl Build {
27302738
PathBuf::from("cmd"),
27312739
&self.cached_compiler_family,
27322740
&self.cargo_output,
2741+
out_dir,
27332742
);
27342743
t.args.push("/c".into());
27352744
t.args.push(format!("{}.bat", tool).into());
@@ -2739,6 +2748,7 @@ impl Build {
27392748
PathBuf::from(tool),
27402749
&self.cached_compiler_family,
27412750
&self.cargo_output,
2751+
out_dir,
27422752
))
27432753
}
27442754
} else {
@@ -2798,6 +2808,7 @@ impl Build {
27982808
PathBuf::from(compiler),
27992809
&self.cached_compiler_family,
28002810
&self.cargo_output,
2811+
out_dir,
28012812
);
28022813
if let Some(cc_wrapper) = Self::rustc_wrapper_fallback() {
28032814
t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper));
@@ -2821,6 +2832,7 @@ impl Build {
28212832
self.cuda,
28222833
&self.cached_compiler_family,
28232834
&self.cargo_output,
2835+
out_dir,
28242836
);
28252837
nvcc_tool
28262838
.args
@@ -3144,7 +3156,7 @@ impl Build {
31443156
// And even extend it to gcc targets by searching for "ar" instead
31453157
// of "llvm-ar"...
31463158
let compiler = self.get_base_compiler().ok()?;
3147-
if compiler.family == ToolFamily::Clang {
3159+
if compiler.is_like_clang() {
31483160
name = format!("llvm-{}", tool);
31493161
search_programs(&mut self.cmd(&compiler.path), &name, &self.cargo_output)
31503162
.map(|name| self.cmd(name))

src/tempfile.rs

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use std::{
2+
collections::hash_map::RandomState,
3+
fs::{remove_file, File, OpenOptions},
4+
hash::{BuildHasher, Hasher},
5+
io, os,
6+
path::{Path, PathBuf},
7+
};
8+
9+
#[cfg(not(any(unix, target_os = "wasi", windows)))]
10+
compile_error!("Your system is not supported since cc cannot create named tempfile");
11+
12+
fn rand() -> u64 {
13+
RandomState::new().build_hasher().finish()
14+
}
15+
16+
fn tmpname(suffix: &str) -> String {
17+
format!("{}{}", rand(), suffix)
18+
}
19+
20+
fn create_named(path: &Path) -> io::Result<File> {
21+
let mut open_options = OpenOptions::new();
22+
23+
open_options.read(true).write(true).create_new(true);
24+
25+
#[cfg(all(unix, not(target_os = "wasi")))]
26+
<OpenOptions as os::unix::fs::OpenOptionsExt>::mode(&mut open_options, 0o600);
27+
28+
#[cfg(windows)]
29+
<OpenOptions as os::windows::fs::OpenOptionsExt>::custom_flags(
30+
&mut open_options,
31+
crate::windows::windows_sys::FILE_ATTRIBUTE_TEMPORARY,
32+
);
33+
34+
open_options.open(path)
35+
}
36+
37+
pub(super) struct NamedTempfile {
38+
path: PathBuf,
39+
file: Option<File>,
40+
}
41+
42+
impl NamedTempfile {
43+
pub(super) fn new(base: &Path, suffix: &str) -> io::Result<Self> {
44+
for _ in 0..10 {
45+
let path = base.join(tmpname(suffix));
46+
match create_named(&path) {
47+
Ok(file) => {
48+
return Ok(Self {
49+
file: Some(file),
50+
path,
51+
})
52+
}
53+
Err(e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
54+
Err(e) => return Err(e),
55+
};
56+
}
57+
58+
Err(io::Error::new(
59+
io::ErrorKind::AlreadyExists,
60+
format!(
61+
"too many temporary files exist in base `{}` with suffix `{}`",
62+
base.display(),
63+
suffix
64+
),
65+
))
66+
}
67+
68+
pub(super) fn path(&self) -> &Path {
69+
&self.path
70+
}
71+
72+
pub(super) fn file(&self) -> &File {
73+
self.file.as_ref().unwrap()
74+
}
75+
}
76+
77+
impl Drop for NamedTempfile {
78+
fn drop(&mut self) {
79+
// On Windows you have to close all handle to it before
80+
// removing the file.
81+
self.file.take();
82+
let _ = remove_file(&self.path);
83+
}
84+
}

0 commit comments

Comments
 (0)