From a7e0c6a293b2bafcfacfa14cd6934ece251cabcd Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 8 Mar 2024 01:02:42 +1100 Subject: [PATCH 01/14] Impl `NamedTempfile` Signed-off-by: Jiahao XU --- .../gen-windows-sys-binding/windows_sys.list | 2 + src/lib.rs | 2 + src/tempfile.rs | 84 +++++++++++++++++++ src/windows/windows_sys.rs | 38 +++++---- 4 files changed, 108 insertions(+), 18 deletions(-) create mode 100644 src/tempfile.rs diff --git a/dev-tools/gen-windows-sys-binding/windows_sys.list b/dev-tools/gen-windows-sys-binding/windows_sys.list index 327bed83..bc188957 100644 --- a/dev-tools/gen-windows-sys-binding/windows_sys.list +++ b/dev-tools/gen-windows-sys-binding/windows_sys.list @@ -37,6 +37,8 @@ Windows.Win32.System.Registry.REG_SZ Windows.Win32.System.SystemInformation.IMAGE_FILE_MACHINE_AMD64 +Windows.Win32.Storage.FileSystem.FILE_ATTRIBUTE_TEMPORARY + Windows.Win32.System.Threading.GetMachineTypeAttributes Windows.Win32.System.Threading.ReleaseSemaphore Windows.Win32.System.Threading.WaitForSingleObject diff --git a/src/lib.rs b/src/lib.rs index 8ef48305..84591eca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -247,6 +247,8 @@ mod tool; pub use tool::Tool; use tool::ToolFamily; +mod tempfile; + /// A builder for compilation of a native library. /// /// A `Build` is the main type of the `cc` crate and is used to control all the diff --git a/src/tempfile.rs b/src/tempfile.rs new file mode 100644 index 00000000..ab0ac877 --- /dev/null +++ b/src/tempfile.rs @@ -0,0 +1,84 @@ +use std::{ + collections::hash_map::RandomState, + fs::{remove_file, File, OpenOptions}, + hash::{BuildHasher, Hasher}, + io, os, + path::{Path, PathBuf}, +}; + +#[cfg(not(any(unix, target_os = "wasi", windows)))] +compile_error!("Your system is not supported since cc cannot create named tempfile"); + +fn rand() -> u64 { + RandomState::new().build_hasher().finish() +} + +fn tmpname(suffix: &str) -> String { + format!("{}{}", rand(), suffix) +} + +fn create_named(path: &Path) -> io::Result { + let mut open_options = OpenOptions::new(); + + open_options.read(true).write(true).create_new(true); + + #[cfg(all(unix, not(target_os = "wasi")))] + ::mode(&mut open_options, 0o600); + + #[cfg(windows)] + ::custom_flags( + &mut open_options, + crate::windows::windows_sys::FILE_ATTRIBUTE_TEMPORARY, + ); + + open_options.open(path) +} + +pub(super) struct NamedTempfile { + path: PathBuf, + file: Option, +} + +impl NamedTempfile { + pub(super) fn new(base: &Path, suffix: &str) -> io::Result { + for _ in 0..10 { + let path = base.join(tmpname(suffix)); + match create_named(&path) { + Ok(file) => { + return Ok(Self { + file: Some(file), + path, + }) + } + Err(e) if e.kind() == io::ErrorKind::AlreadyExists => continue, + Err(e) => return Err(e), + }; + } + + Err(io::Error::new( + io::ErrorKind::AlreadyExists, + format!( + "too many temporary files exist in base `{}` with suffix `{}`", + base.display(), + suffix + ), + )) + } + + pub(super) fn path(&self) -> &Path { + &self.path + } + + pub(super) fn file(&self) -> &File { + self.file.as_ref().unwrap() + } +} + +impl Drop for NamedTempfile { + fn drop(&mut self) { + // On Windows you have to close all handle to it before + // removing the file. + self.file.take(); + let _ = remove_file(&self.path); + } +} diff --git a/src/windows/windows_sys.rs b/src/windows/windows_sys.rs index 8b98ce97..56b54424 100644 --- a/src/windows/windows_sys.rs +++ b/src/windows/windows_sys.rs @@ -6,7 +6,7 @@ // cd generate-windows-sys/ // cargo run // ``` -// Bindings generated by `windows-bindgen` 0.53.0 +// Bindings generated by `windows-bindgen` 0.55.0 #![allow( non_snake_case, @@ -80,7 +80,7 @@ extern "system" { extern "system" { pub fn PeekNamedPipe( hnamedpipe: HANDLE, - lpbuffer: *mut ::core::ffi::c_void, + lpbuffer: *mut core::ffi::c_void, nbuffersize: u32, lpbytesread: *mut u32, lptotalbytesavail: *mut u32, @@ -103,15 +103,15 @@ extern "system" { extern "system" { pub fn CoCreateInstance( rclsid: *const GUID, - punkouter: *mut ::core::ffi::c_void, + punkouter: *mut core::ffi::c_void, dwclscontext: CLSCTX, riid: *const GUID, - ppv: *mut *mut ::core::ffi::c_void, + ppv: *mut *mut core::ffi::c_void, ) -> HRESULT; } #[link(name = "ole32")] extern "system" { - pub fn CoInitializeEx(pvreserved: *const ::core::ffi::c_void, dwcoinit: u32) -> HRESULT; + pub fn CoInitializeEx(pvreserved: *const core::ffi::c_void, dwcoinit: u32) -> HRESULT; } #[link(name = "oleaut32")] extern "system" { @@ -131,18 +131,20 @@ pub const COINIT_MULTITHREADED: COINIT = 0i32; pub const ERROR_NO_MORE_ITEMS: WIN32_ERROR = 259u32; pub const ERROR_SUCCESS: WIN32_ERROR = 0u32; pub const FALSE: BOOL = 0i32; -pub type FARPROC = ::core::option::Option isize>; +pub type FARPROC = Option isize>; #[repr(C)] pub struct FILETIME { pub dwLowDateTime: u32, pub dwHighDateTime: u32, } -impl ::core::marker::Copy for FILETIME {} -impl ::core::clone::Clone for FILETIME { +impl Copy for FILETIME {} +impl Clone for FILETIME { fn clone(&self) -> Self { *self } } +pub const FILE_ATTRIBUTE_TEMPORARY: FILE_FLAGS_AND_ATTRIBUTES = 256u32; +pub type FILE_FLAGS_AND_ATTRIBUTES = u32; #[repr(C)] pub struct GUID { pub data1: u32, @@ -150,8 +152,8 @@ pub struct GUID { pub data3: u16, pub data4: [u8; 8], } -impl ::core::marker::Copy for GUID {} -impl ::core::clone::Clone for GUID { +impl Copy for GUID {} +impl Clone for GUID { fn clone(&self) -> Self { *self } @@ -166,10 +168,10 @@ impl GUID { } } } -pub type HANDLE = *mut ::core::ffi::c_void; -pub type HKEY = *mut ::core::ffi::c_void; +pub type HANDLE = *mut core::ffi::c_void; +pub type HKEY = *mut core::ffi::c_void; pub const HKEY_LOCAL_MACHINE: HKEY = -2147483646i32 as _; -pub type HMODULE = *mut ::core::ffi::c_void; +pub type HMODULE = *mut core::ffi::c_void; pub type HRESULT = i32; pub type IMAGE_FILE_MACHINE = u16; pub const IMAGE_FILE_MACHINE_AMD64: IMAGE_FILE_MACHINE = 34404u16; @@ -188,11 +190,11 @@ pub struct SAFEARRAY { pub fFeatures: ADVANCED_FEATURE_FLAGS, pub cbElements: u32, pub cLocks: u32, - pub pvData: *mut ::core::ffi::c_void, + pub pvData: *mut core::ffi::c_void, pub rgsabound: [SAFEARRAYBOUND; 1], } -impl ::core::marker::Copy for SAFEARRAY {} -impl ::core::clone::Clone for SAFEARRAY { +impl Copy for SAFEARRAY {} +impl Clone for SAFEARRAY { fn clone(&self) -> Self { *self } @@ -202,8 +204,8 @@ pub struct SAFEARRAYBOUND { pub cElements: u32, pub lLbound: i32, } -impl ::core::marker::Copy for SAFEARRAYBOUND {} -impl ::core::clone::Clone for SAFEARRAYBOUND { +impl Copy for SAFEARRAYBOUND {} +impl Clone for SAFEARRAYBOUND { fn clone(&self) -> Self { *self } From 8a2efd710fb70ecbdf5f1afb72288cb21977e99a Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 8 Mar 2024 01:02:59 +1100 Subject: [PATCH 02/14] Detect compiler family by using C macros which is more robust than checking output of `$compiler -v` Signed-off-by: Jiahao XU --- src/lib.rs | 32 +++++++---- src/tool.rs | 150 ++++++++++++++++++++++++++++++++-------------------- 2 files changed, 114 insertions(+), 68 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 84591eca..2e38e6bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -314,6 +314,8 @@ enum ErrorKind { ToolNotFound, /// One of the function arguments failed validation. InvalidArgument, + /// No known macro is defined for the compiler when discovering tool family + ToolFamilyMacroNotFound, #[cfg(feature = "parallel")] /// jobserver helpthread failure JobserverHelpThreadError, @@ -619,7 +621,7 @@ impl Build { if compiler.family.verbose_stderr() { compiler.remove_arg("-v".into()); } - if compiler.family == ToolFamily::Clang { + if compiler.is_like_clang() { // Avoid reporting that the arg is unsupported just because the // compiler complains that it wasn't used. compiler.push_cc_arg("-Wno-unused-command-line-argument".into()); @@ -627,7 +629,7 @@ impl Build { let mut cmd = compiler.to_command(); let is_arm = target.contains("aarch64") || target.contains("arm"); - let clang = compiler.family == ToolFamily::Clang; + let clang = compiler.is_like_clang(); let gnu = compiler.family == ToolFamily::Gnu; command_add_output_file( &mut cmd, @@ -1574,7 +1576,7 @@ impl Build { let target = self.get_target()?; let msvc = target.contains("msvc"); let compiler = self.try_get_compiler()?; - let clang = compiler.family == ToolFamily::Clang; + let clang = compiler.is_like_clang(); let gnu = compiler.family == ToolFamily::Gnu; let is_assembler_msvc = msvc && asm_ext == Some(AsmFileExt::DotAsm); @@ -1730,7 +1732,7 @@ impl Build { if let Some(ref std) = self.std { let separator = match cmd.family { ToolFamily::Msvc { .. } => ':', - ToolFamily::Gnu | ToolFamily::Clang => '=', + ToolFamily::Gnu | ToolFamily::Clang { .. } => '=', }; cmd.push_cc_arg(format!("-std{}{}", separator, std).into()); } @@ -1823,23 +1825,23 @@ impl Build { _ => {} } } - ToolFamily::Gnu | ToolFamily::Clang => { + ToolFamily::Gnu | ToolFamily::Clang { .. } => { // arm-linux-androideabi-gcc 4.8 shipped with Android NDK does // not support '-Oz' - if opt_level == "z" && cmd.family != ToolFamily::Clang { + if opt_level == "z" && !cmd.is_like_clang() { cmd.push_opt_unless_duplicate("-Os".into()); } else { cmd.push_opt_unless_duplicate(format!("-O{}", opt_level).into()); } - if cmd.family == ToolFamily::Clang && target.contains("windows") { + if cmd.is_like_clang() && target.contains("windows") { // Disambiguate mingw and msvc on Windows. Problem is that // depending on the origin clang can default to a mismatchig // run-time. cmd.push_cc_arg(format!("--target={}", target).into()); } - if cmd.family == ToolFamily::Clang && target.contains("android") { + if cmd.is_like_clang() && target.contains("android") { // For compatibility with code that doesn't use pre-defined `__ANDROID__` macro. // If compiler used via ndk-build or cmake (officially supported build methods) // this macros is defined. @@ -1897,7 +1899,7 @@ impl Build { // Target flags match cmd.family { - ToolFamily::Clang => { + ToolFamily::Clang { .. } => { if !cmd.has_internal_target_arg && !(target.contains("android") && android_clang_compiler_uses_target_arg_internally(&cmd.path)) @@ -2303,7 +2305,7 @@ impl Build { if self.cpp { match (self.cpp_set_stdlib.as_ref(), cmd.family) { (None, _) => {} - (Some(stdlib), ToolFamily::Gnu) | (Some(stdlib), ToolFamily::Clang) => { + (Some(stdlib), ToolFamily::Gnu) | (Some(stdlib), ToolFamily::Clang { .. }) => { cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into()); } _ => { @@ -2679,11 +2681,14 @@ impl Build { } fn get_base_compiler(&self) -> Result { + let out_dir = self.get_out_dir()?; + if let Some(c) = &self.compiler { return Ok(Tool::new( (**c).to_owned(), &self.cached_compiler_family, &self.cargo_output, + &out_dir, )); } let host = self.get_host()?; @@ -2725,6 +2730,7 @@ impl Build { driver_mode, &self.cached_compiler_family, &self.cargo_output, + &out_dir, ); if let Some(cc_wrapper) = wrapper { t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); @@ -2743,6 +2749,7 @@ impl Build { PathBuf::from("cmd"), &self.cached_compiler_family, &self.cargo_output, + &out_dir, ); t.args.push("/c".into()); t.args.push(format!("{}.bat", tool).into()); @@ -2752,6 +2759,7 @@ impl Build { PathBuf::from(tool), &self.cached_compiler_family, &self.cargo_output, + &out_dir, )) } } else { @@ -2811,6 +2819,7 @@ impl Build { PathBuf::from(compiler), &self.cached_compiler_family, &self.cargo_output, + &out_dir, ); if let Some(cc_wrapper) = Self::rustc_wrapper_fallback() { t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); @@ -2834,6 +2843,7 @@ impl Build { self.cuda, &self.cached_compiler_family, &self.cargo_output, + &out_dir, ); nvcc_tool .args @@ -3157,7 +3167,7 @@ impl Build { // And even extend it to gcc targets by searching for "ar" instead // of "llvm-ar"... let compiler = self.get_base_compiler().ok()?; - if compiler.family == ToolFamily::Clang { + if compiler.is_like_clang() { name = format!("llvm-{}", tool); search_programs(&mut self.cmd(&compiler.path), &name, &self.cargo_output) .map(|name| self.cmd(name)) diff --git a/src/tool.rs b/src/tool.rs index bb7de512..33ec3439 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -1,12 +1,17 @@ use std::{ collections::HashMap, - ffi::OsString, + ffi::{OsStr, OsString}, + io::Write, path::{Path, PathBuf}, - process::Command, + process::{Command, Stdio}, sync::Mutex, }; -use crate::command_helpers::{run_output, CargoOutput}; +use crate::{ + command_helpers::{run_output, CargoOutput}, + tempfile::NamedTempfile, + Error, ErrorKind, +}; /// Configuration used to represent an invocation of a C compiler. /// @@ -34,8 +39,16 @@ impl Tool { path: PathBuf, cached_compiler_family: &Mutex, ToolFamily>>, cargo_output: &CargoOutput, + out_dir: &Path, ) -> Self { - Self::with_features(path, None, false, cached_compiler_family, cargo_output) + Self::with_features( + path, + None, + false, + cached_compiler_family, + cargo_output, + out_dir, + ) } pub(crate) fn with_clang_driver( @@ -43,6 +56,7 @@ impl Tool { clang_driver: Option<&str>, cached_compiler_family: &Mutex, ToolFamily>>, cargo_output: &CargoOutput, + out_dir: &Path, ) -> Self { Self::with_features( path, @@ -50,6 +64,7 @@ impl Tool { false, cached_compiler_family, cargo_output, + out_dir, ) } @@ -74,70 +89,91 @@ impl Tool { cuda: bool, cached_compiler_family: &Mutex, ToolFamily>>, cargo_output: &CargoOutput, + out_dir: &Path, ) -> Self { - fn detect_family_inner(path: &Path, cargo_output: &CargoOutput) -> ToolFamily { - let mut cmd = Command::new(path); - cmd.arg("--version"); - - let stdout = match run_output( - &mut cmd, + fn is_zig_cc(path: &Path, cargo_output: &CargoOutput) -> bool { + run_output( + Command::new(&path).arg("--version"), path, // tool detection issues should always be shown as warnings cargo_output, ) - .ok() - .and_then(|o| String::from_utf8(o).ok()) - { - Some(s) => s, - None => { - // --version failed. fallback to gnu - cargo_output.print_warning(&format_args!("Failed to run: {:?}", cmd)); - return ToolFamily::Gnu; + .map(|o| String::from_utf8_lossy(&o).contains("ziglang")) + .unwrap_or_default() + } + + fn detect_family_inner( + path: &Path, + cargo_output: &CargoOutput, + out_dir: &Path, + ) -> Result { + let tmp = NamedTempfile::new(out_dir, "detect_compiler_family.c")?; + tmp.file() + .write_all(include_bytes!("detect_compiler_family.c"))?; + + let stdout = run_output( + Command::new(path) + .arg("-E") + .arg(tmp.path()) + .stderr(Stdio::null()), + path, + // tool detection issues should always be shown as warnings + cargo_output, + )?; + let stdout = String::from_utf8_lossy(&stdout); + + let clang = stdout.contains("clang"); + let msvc = stdout.contains("msvc"); + let gcc = stdout.contains("gcc"); + + match (clang, msvc, gcc) { + (clang_cl, true, _) => Ok(ToolFamily::Msvc { clang_cl }), + (true, false, _) => Ok(ToolFamily::Clang { + zig_cc: is_zig_cc(path, cargo_output), + }), + (false, false, true) => Ok(ToolFamily::Gnu), + (false, false, false) => { + cargo_output.print_warning(&"Compiler family detection failed since it does not define `__clang__`, `__GNUC__` or `_MSC_VER`, fallback to treating it as GNU"); + Err(Error::new( + ErrorKind::ToolFamilyMacroNotFound, + "Expects macro `__clang__`, `__GNUC__` or `_MSC_VER`, but found none", + )) } - }; - if stdout.contains("clang") { - ToolFamily::Clang - } else if stdout.contains("GCC") { - ToolFamily::Gnu - } else { - // --version doesn't include clang for GCC - cargo_output.print_warning(&format_args!( - "Compiler version doesn't include clang or GCC: {:?}", - cmd - )); - ToolFamily::Gnu } } - let detect_family = |path: &Path| -> ToolFamily { + let detect_family = |path: &Path| -> Result { if let Some(family) = cached_compiler_family.lock().unwrap().get(path) { - return *family; + return Ok(*family); } - let family = detect_family_inner(path, cargo_output); + let family = detect_family_inner(path, cargo_output, out_dir)?; cached_compiler_family .lock() .unwrap() .insert(path.into(), family); - family + Ok(family) }; - // Try to detect family of the tool from its name, falling back to Gnu. - let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) { - if fname.contains("clang-cl") { - ToolFamily::Msvc { clang_cl: true } - } else if fname.ends_with("cl") || fname == "cl.exe" { - ToolFamily::Msvc { clang_cl: false } - } else if fname.contains("clang") { - match clang_driver { - Some("cl") => ToolFamily::Msvc { clang_cl: true }, - _ => ToolFamily::Clang, + let family = detect_family(&path).unwrap_or_else(|e| { + cargo_output.print_warning(&format_args!( + "Compiler family detection failed due to error: {}", + e + )); + match path.file_name().map(OsStr::to_string_lossy) { + Some(fname) if fname.contains("clang-cl") => ToolFamily::Msvc { clang_cl: true }, + Some(fname) if fname.ends_with("cl") || fname == "cl.exe" => { + ToolFamily::Msvc { clang_cl: false } } - } else { - detect_family(&path) + Some(fname) if fname.contains("clang") => match clang_driver { + Some("cl") => ToolFamily::Msvc { clang_cl: true }, + _ => ToolFamily::Clang { + zig_cc: is_zig_cc(&path, cargo_output), + }, + }, + Some(fname) if fname.contains("zig") => ToolFamily::Clang { zig_cc: true }, + _ => ToolFamily::Gnu, } - } else { - detect_family(&path) - }; + }); Tool { path, @@ -303,7 +339,7 @@ impl Tool { /// Whether the tool is Clang-like. pub fn is_like_clang(&self) -> bool { - self.family == ToolFamily::Clang + matches!(self.family, ToolFamily::Clang { .. }) } /// Whether the tool is AppleClang under .xctoolchain @@ -337,7 +373,7 @@ pub enum ToolFamily { Gnu, /// Tool is Clang-like. It differs from the GCC in a sense that it accepts superset of flags /// and its cross-compilation approach is different. - Clang, + Clang { zig_cc: bool }, /// Tool is the MSVC cl.exe. Msvc { clang_cl: bool }, } @@ -349,7 +385,7 @@ impl ToolFamily { ToolFamily::Msvc { .. } => { cmd.push_cc_arg("-Z7".into()); } - ToolFamily::Gnu | ToolFamily::Clang => { + ToolFamily::Gnu | ToolFamily::Clang { .. } => { cmd.push_cc_arg( dwarf_version .map_or_else(|| "-g".into(), |v| format!("-gdwarf-{}", v)) @@ -362,7 +398,7 @@ impl ToolFamily { /// What the flag to force frame pointers. pub(crate) fn add_force_frame_pointer(&self, cmd: &mut Tool) { match *self { - ToolFamily::Gnu | ToolFamily::Clang => { + ToolFamily::Gnu | ToolFamily::Clang { .. } => { cmd.push_cc_arg("-fno-omit-frame-pointer".into()); } _ => (), @@ -373,7 +409,7 @@ impl ToolFamily { pub(crate) fn warnings_flags(&self) -> &'static str { match *self { ToolFamily::Msvc { .. } => "-W4", - ToolFamily::Gnu | ToolFamily::Clang => "-Wall", + ToolFamily::Gnu | ToolFamily::Clang { .. } => "-Wall", } } @@ -381,7 +417,7 @@ impl ToolFamily { pub(crate) fn extra_warnings_flags(&self) -> Option<&'static str> { match *self { ToolFamily::Msvc { .. } => None, - ToolFamily::Gnu | ToolFamily::Clang => Some("-Wextra"), + ToolFamily::Gnu | ToolFamily::Clang { .. } => Some("-Wextra"), } } @@ -389,11 +425,11 @@ impl ToolFamily { pub(crate) fn warnings_to_errors_flag(&self) -> &'static str { match *self { ToolFamily::Msvc { .. } => "-WX", - ToolFamily::Gnu | ToolFamily::Clang => "-Werror", + ToolFamily::Gnu | ToolFamily::Clang { .. } => "-Werror", } } pub(crate) fn verbose_stderr(&self) -> bool { - *self == ToolFamily::Clang + matches!(*self, ToolFamily::Clang { .. }) } } From d214af4c7e97abb16e693bfce1f0bb5d3019c119 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 8 Mar 2024 01:05:15 +1100 Subject: [PATCH 03/14] Add `detect_compiler_family.c` Signed-off-by: Jiahao XU --- src/detect_compiler_family.c | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/detect_compiler_family.c diff --git a/src/detect_compiler_family.c b/src/detect_compiler_family.c new file mode 100644 index 00000000..290d2fc7 --- /dev/null +++ b/src/detect_compiler_family.c @@ -0,0 +1,11 @@ +#ifdef __clang__ +#pragma message "clang" +#endif + +#ifdef __GNUC__ +#pragma message "gcc" +#endif + +#ifdef _MSC_VER +#pragma message "msvc" +#endif From 779bed4b88ef2663a9bf082a1921a8525fc7356b Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 8 Mar 2024 15:10:17 +1100 Subject: [PATCH 04/14] Fix `gnu_flag_if_supported` and `gnu_flag_if_supported_cpp` Signed-off-by: Jiahao XU --- src/bin/gcc-shim.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/bin/gcc-shim.rs b/src/bin/gcc-shim.rs index f0d219f4..73c11d93 100644 --- a/src/bin/gcc-shim.rs +++ b/src/bin/gcc-shim.rs @@ -3,10 +3,10 @@ #![cfg_attr(test, allow(dead_code))] -use std::env; use std::fs::File; use std::io::{self, prelude::*}; use std::path::PathBuf; +use std::{env, fs}; fn main() { let mut args = env::args(); @@ -70,4 +70,21 @@ fn main() { e ) }); + + // Handle the compiler detection logic + let args = env::args().collect::>(); + if args.len() == 3 + && args[1] == "-E" + && fs::read_to_string(&args[2]) + .map(|s| s == include_str!("../detect_compiler_family.c")) + .unwrap_or_default() + { + match &*program { + "cc" | "c++" => println!("gcc"), + "cl" | "lib.exe" | "cl.exe" => println!("msvc"), + "clang-cl" | "clang-cl.exe" => println!("msvc\nclang"), + "clang" | "clang++" => println!("clang"), + _ => (), + } + } } From 681a1f98e2cb564388b3ca12b8a4020749945853 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 8 Mar 2024 15:16:47 +1100 Subject: [PATCH 05/14] Disable warning for compiler family detection When expanding the file, the compiler prints a lot of information to stderr that it is not an error, but related to expanding itself. cc would have to disable warning here to prevent generation of too many warnings. Signed-off-by: Jiahao XU --- src/tool.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/tool.rs b/src/tool.rs index 33ec3439..ee9d5623 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -117,8 +117,15 @@ impl Tool { .arg(tmp.path()) .stderr(Stdio::null()), path, - // tool detection issues should always be shown as warnings - cargo_output, + // When expanding the file, the compiler prints a lot of information to stderr + // that it is not an error, but related to expanding itself. + // + // cc would have to disable warning here to prevent generation of too many warnings. + &{ + let mut cargo_output = cargo_output.clone(); + cargo_output.warnings = false; + cargo_output + }, )?; let stdout = String::from_utf8_lossy(&stdout); From 093848cb5f24fe61309f967e2dc105639136c582 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 8 Mar 2024 15:18:53 +1100 Subject: [PATCH 06/14] Enable stderr forwarding for compiler family detection if debugging output is enabled It's good to have the output for debugging. Signed-off-by: Jiahao XU --- src/tool.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tool.rs b/src/tool.rs index ee9d5623..b0177581 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -123,7 +123,7 @@ impl Tool { // cc would have to disable warning here to prevent generation of too many warnings. &{ let mut cargo_output = cargo_output.clone(); - cargo_output.warnings = false; + cargo_output.warnings = cargo_output.debug; cargo_output }, )?; From aa2b4b6864763c6bda0d90fa9998f24e441621ef Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 8 Mar 2024 15:19:55 +1100 Subject: [PATCH 07/14] Print stdout from compiler family detection if debugging output is enabled Can help find issues related to compiler family detection. Signed-off-by: Jiahao XU --- src/tool.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tool.rs b/src/tool.rs index b0177581..7ef65781 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -129,6 +129,8 @@ impl Tool { )?; let stdout = String::from_utf8_lossy(&stdout); + cargo_output.print_debug(&stdout); + let clang = stdout.contains("clang"); let msvc = stdout.contains("msvc"); let gcc = stdout.contains("gcc"); From 1d8cf4167c01b726806caae8b560aa801f487a49 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 8 Mar 2024 17:39:32 +1100 Subject: [PATCH 08/14] Enable debugging output for CI Signed-off-by: Jiahao XU --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 653c6d12..fef9cb8c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,6 +4,7 @@ on: [push, pull_request] env: CARGO_INCREMENTAL: 0 CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse + CC_ENABLE_DEBUG_OUTPUT: true jobs: test: From ea7221655c992ced1c455698232f079c0628e49e Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 8 Mar 2024 18:42:14 +1100 Subject: [PATCH 09/14] Fix `flag_if_supported` failure due to `OUT_DIR` not set Fallback to create `NamedTempfile` in `std::env::temp_dir()` Signed-off-by: Jiahao XU --- src/lib.rs | 15 ++++++++------- src/tool.rs | 17 ++++++++++++----- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2e38e6bd..8fdcbc4a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2681,14 +2681,15 @@ impl Build { } fn get_base_compiler(&self) -> Result { - let out_dir = self.get_out_dir()?; + let out_dir = self.get_out_dir().ok(); + let out_dir = out_dir.as_deref(); if let Some(c) = &self.compiler { return Ok(Tool::new( (**c).to_owned(), &self.cached_compiler_family, &self.cargo_output, - &out_dir, + out_dir, )); } let host = self.get_host()?; @@ -2730,7 +2731,7 @@ impl Build { driver_mode, &self.cached_compiler_family, &self.cargo_output, - &out_dir, + out_dir, ); if let Some(cc_wrapper) = wrapper { t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); @@ -2749,7 +2750,7 @@ impl Build { PathBuf::from("cmd"), &self.cached_compiler_family, &self.cargo_output, - &out_dir, + out_dir, ); t.args.push("/c".into()); t.args.push(format!("{}.bat", tool).into()); @@ -2759,7 +2760,7 @@ impl Build { PathBuf::from(tool), &self.cached_compiler_family, &self.cargo_output, - &out_dir, + out_dir, )) } } else { @@ -2819,7 +2820,7 @@ impl Build { PathBuf::from(compiler), &self.cached_compiler_family, &self.cargo_output, - &out_dir, + out_dir, ); if let Some(cc_wrapper) = Self::rustc_wrapper_fallback() { t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); @@ -2843,7 +2844,7 @@ impl Build { self.cuda, &self.cached_compiler_family, &self.cargo_output, - &out_dir, + out_dir, ); nvcc_tool .args diff --git a/src/tool.rs b/src/tool.rs index 7ef65781..c0064ce6 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -1,5 +1,7 @@ use std::{ + borrow::Cow, collections::HashMap, + env, ffi::{OsStr, OsString}, io::Write, path::{Path, PathBuf}, @@ -39,7 +41,7 @@ impl Tool { path: PathBuf, cached_compiler_family: &Mutex, ToolFamily>>, cargo_output: &CargoOutput, - out_dir: &Path, + out_dir: Option<&Path>, ) -> Self { Self::with_features( path, @@ -56,7 +58,7 @@ impl Tool { clang_driver: Option<&str>, cached_compiler_family: &Mutex, ToolFamily>>, cargo_output: &CargoOutput, - out_dir: &Path, + out_dir: Option<&Path>, ) -> Self { Self::with_features( path, @@ -89,7 +91,7 @@ impl Tool { cuda: bool, cached_compiler_family: &Mutex, ToolFamily>>, cargo_output: &CargoOutput, - out_dir: &Path, + out_dir: Option<&Path>, ) -> Self { fn is_zig_cc(path: &Path, cargo_output: &CargoOutput) -> bool { run_output( @@ -105,9 +107,14 @@ impl Tool { fn detect_family_inner( path: &Path, cargo_output: &CargoOutput, - out_dir: &Path, + out_dir: Option<&Path>, ) -> Result { - let tmp = NamedTempfile::new(out_dir, "detect_compiler_family.c")?; + let tmp = NamedTempfile::new( + &out_dir + .map(Cow::Borrowed) + .unwrap_or_else(|| Cow::Owned(env::temp_dir())), + "detect_compiler_family.c", + )?; tmp.file() .write_all(include_bytes!("detect_compiler_family.c"))?; From f70eafa47bf842b7f6aae04040b07a0c2b12dc01 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 8 Mar 2024 18:49:27 +1100 Subject: [PATCH 10/14] Fix test on cargo warnings Signed-off-by: Jiahao XU --- dev-tools/cc-test/build.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dev-tools/cc-test/build.rs b/dev-tools/cc-test/build.rs index 8968eb53..0fae1d7a 100644 --- a/dev-tools/cc-test/build.rs +++ b/dev-tools/cc-test/build.rs @@ -156,7 +156,13 @@ fn run_action_if_forked() -> bool { true } +fn disable_debug_output() { + std::env::remove_var("CC_ENABLE_DEBUG_OUTPUT"); +} + fn build_cargo_warnings(warnings: bool) { + disable_debug_output(); + cc::Build::new() .cargo_metadata(false) .cargo_warnings(warnings) @@ -166,6 +172,8 @@ fn build_cargo_warnings(warnings: bool) { } fn build_cargo_metadata(metadata: bool) { + disable_debug_output(); + cc::Build::new() .cargo_metadata(metadata) .file("src/dummy.c") From ada78b91deddc2d948717e7af0320a4eb3b54208 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 8 Mar 2024 18:53:52 +1100 Subject: [PATCH 11/14] Revert changes to `src/bin/gcc-shim.rs` It's not necessary. Signed-off-by: Jiahao XU --- src/bin/gcc-shim.rs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/bin/gcc-shim.rs b/src/bin/gcc-shim.rs index 73c11d93..f0d219f4 100644 --- a/src/bin/gcc-shim.rs +++ b/src/bin/gcc-shim.rs @@ -3,10 +3,10 @@ #![cfg_attr(test, allow(dead_code))] +use std::env; use std::fs::File; use std::io::{self, prelude::*}; use std::path::PathBuf; -use std::{env, fs}; fn main() { let mut args = env::args(); @@ -70,21 +70,4 @@ fn main() { e ) }); - - // Handle the compiler detection logic - let args = env::args().collect::>(); - if args.len() == 3 - && args[1] == "-E" - && fs::read_to_string(&args[2]) - .map(|s| s == include_str!("../detect_compiler_family.c")) - .unwrap_or_default() - { - match &*program { - "cc" | "c++" => println!("gcc"), - "cl" | "lib.exe" | "cl.exe" => println!("msvc"), - "clang-cl" | "clang-cl.exe" => println!("msvc\nclang"), - "clang" | "clang++" => println!("clang"), - _ => (), - } - } } From f3b594642f14cb6aab1e37cd2c3b2c5fbd636901 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 8 Mar 2024 19:00:56 +1100 Subject: [PATCH 12/14] Remove unnecessary `.stderr(Stdio::null())` in `tool.rs` Signed-off-by: Jiahao XU --- src/tool.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/tool.rs b/src/tool.rs index c0064ce6..d8623ccc 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -5,7 +5,7 @@ use std::{ ffi::{OsStr, OsString}, io::Write, path::{Path, PathBuf}, - process::{Command, Stdio}, + process::Command, sync::Mutex, }; @@ -119,10 +119,7 @@ impl Tool { .write_all(include_bytes!("detect_compiler_family.c"))?; let stdout = run_output( - Command::new(path) - .arg("-E") - .arg(tmp.path()) - .stderr(Stdio::null()), + Command::new(path).arg("-E").arg(tmp.path()), path, // When expanding the file, the compiler prints a lot of information to stderr // that it is not an error, but related to expanding itself. From 1ab8a9de716868e8b6f01a5b1de4734d87cd8bd5 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Fri, 15 Mar 2024 23:00:03 +1100 Subject: [PATCH 13/14] Run `cargo fmt` Signed-off-by: Jiahao XU --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 028ca75d..b539abd0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -247,8 +247,8 @@ mod tool; pub use tool::Tool; use tool::ToolFamily; -mod tempfile; mod target_info; +mod tempfile; /// A builder for compilation of a native library. /// From 467bd8c3221fd5123d1cf9a38d6f7245aba87072 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Sun, 17 Mar 2024 11:41:16 +1100 Subject: [PATCH 14/14] Add comment to `disable_debug_output` in `cc-test/build.rs` Signed-off-by: Jiahao XU --- dev-tools/cc-test/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev-tools/cc-test/build.rs b/dev-tools/cc-test/build.rs index 0fae1d7a..7ebeeab2 100644 --- a/dev-tools/cc-test/build.rs +++ b/dev-tools/cc-test/build.rs @@ -157,6 +157,8 @@ fn run_action_if_forked() -> bool { } fn disable_debug_output() { + // That env would break tests for warning/debug output, + // and it is set in the CI, to make debugging CI failure easier. std::env::remove_var("CC_ENABLE_DEBUG_OUTPUT"); }