From 01e6e98d5002d389b26b96a61630676e42624612 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Sun, 14 Jan 2024 20:32:18 +0100 Subject: [PATCH 01/23] fix some instances of broken cargo:warning instruction --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0a5b2ae35..cd00310fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3475,7 +3475,7 @@ impl Build { // If below 10.9, we round up. if major == 10 && minor < 9 { println!( - "cargo-warning: macOS deployment target ({}) too low, it will be increased", + "cargo:warning=macOS deployment target ({}) too low, it will be increased", deployment_target_ver ); return String::from("10.9"); @@ -3486,7 +3486,7 @@ impl Build { if major < 7 { println!( - "cargo-warning: iOS deployment target ({}) too low, it will be increased", + "cargo:warning=iOS deployment target ({}) too low, it will be increased", deployment_target_ver ); return String::from(OLD_IOS_MINIMUM_VERSION); @@ -3586,7 +3586,7 @@ impl Tool { Some(s) => s, None => { // --version failed. fallback to gnu - println!("cargo-warning:Failed to run: {:?}", cmd); + println!("cargo:warning=Failed to run: {:?}", cmd); return ToolFamily::Gnu; } }; @@ -3597,7 +3597,7 @@ impl Tool { } else { // --version doesn't include clang for GCC println!( - "cargo-warning:Compiler version doesn't include clang or GCC: {:?}", + "cargo:warning=Compiler version doesn't include clang or GCC: {:?}", cmd ); ToolFamily::Gnu From e7af292d6f7dafc97fa970e07477761f8ba70757 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Sun, 14 Jan 2024 20:33:42 +0100 Subject: [PATCH 02/23] allow disabling cargo warnings for compilation --- src/lib.rs | 70 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cd00310fd..48cfa9a6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,6 +123,7 @@ pub struct Build { archiver: Option>, ranlib: Option>, cargo_metadata: bool, + cargo_warnings: bool, link_lib_modifiers: Vec>, pic: Option, use_plt: Option, @@ -331,6 +332,7 @@ impl Build { archiver: None, ranlib: None, cargo_metadata: true, + cargo_warnings: true, link_lib_modifiers: Vec::new(), pic: None, use_plt: None, @@ -1042,6 +1044,16 @@ impl Build { self } + /// Define whether compile warnings should be emitted for cargo. Defaults to + /// `true`. + /// + /// If disabled, compiler messages are printed without the 'cargo:warning' prefix. + /// Issues unrelated to the compilation will always produce cargo warnings regardless of this setting. + pub fn cargo_warnings(&mut self, cargo_warnings: bool) -> &mut Build { + self.cargo_warnings = cargo_warnings; + self + } + /// Adds a native library modifier that will be added to the /// `rustc-link-lib=static:MODIFIERS=LIBRARY_NAME` metadata line /// emitted for cargo if `cargo_metadata` is enabled. @@ -1173,7 +1185,7 @@ impl Build { objects.push(Object::new(file.to_path_buf(), obj)); } - let print = PrintThread::new()?; + let print = PrintThread::new(self.cargo_warnings)?; self.compile_objects(&objects, &print)?; self.assemble(lib_name, &dst.join(gnu_lib_name), &objects, &print)?; @@ -1393,7 +1405,10 @@ impl Build { // sure users always see all the compilation failures. has_made_progress.set(true); - let _ = writeln!(stdout, "cargo:warning={}", err); + if self.cargo_warnings { + let _ = write!(stdout, "cargo:warning="); + } + let _ = writeln!(stdout, "{}", err); error = Some(err); false @@ -1566,7 +1581,7 @@ impl Build { .to_string_lossy() .into_owned(); - Ok(run_output(&mut cmd, &name)?) + Ok(run_output(&mut cmd, &name, self.cargo_warnings)?) } /// Run the compiler, returning the macro-expanded version of the input files. @@ -2167,10 +2182,15 @@ impl Build { cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into()); } _ => { - println!( - "cargo:warning=cpp_set_stdlib is specified, but the {:?} compiler \ + let mut stdout = io::stdout().lock(); + if self.cargo_warnings { + let _ = write!(stdout, "cargo:warning="); + } + let _ = writeln!( + stdout, + "cpp_set_stdlib is specified, but the {:?} compiler \ does not support this option, ignored", - cmd.family + cmd.family, ); } } @@ -2726,7 +2746,11 @@ impl Build { } if target.contains("msvc") && tool.family == ToolFamily::Gnu { - println!("cargo:warning=GNU compiler is not supported for this target"); + let mut stdout = io::stdout().lock(); + if self.cargo_warnings { + let _ = write!(stdout, "cargo:warning="); + } + let _ = writeln!(stdout, "GNU compiler is not supported for this target"); } Ok(tool) @@ -3400,6 +3424,7 @@ impl Build { .arg("--sdk") .arg(sdk), "xcrun", + self.cargo_warnings, )?; let sdk_path = match String::from_utf8(sdk_path) { @@ -3579,9 +3604,14 @@ impl Tool { let mut cmd = Command::new(path); cmd.arg("--version"); - let stdout = match run_output(&mut cmd, &path.to_string_lossy()) - .ok() - .and_then(|o| String::from_utf8(o).ok()) + let stdout = match run_output( + &mut cmd, + &path.to_string_lossy(), + // tool detection issues should always be shown as warnings + true, + ) + .ok() + .and_then(|o| String::from_utf8(o).ok()) { Some(s) => s, None => { @@ -3882,10 +3912,10 @@ fn run(cmd: &mut Command, program: &str, print: &PrintThread) -> Result<(), Erro Ok(()) } -fn run_output(cmd: &mut Command, program: &str) -> Result, Error> { +fn run_output(cmd: &mut Command, program: &str, cargo_warnings: bool) -> Result, Error> { cmd.stdout(Stdio::piped()); - let mut print = PrintThread::new()?; + let mut print = PrintThread::new(cargo_warnings)?; let mut child = spawn(cmd, program, print.pipe_writer().take().unwrap())?; let mut stdout = vec![]; @@ -4126,7 +4156,13 @@ fn which(tool: &Path, path_entries: Option) -> Option { // search for |prog| on 'programs' path in '|cc| -print-search-dirs' output fn search_programs(cc: &mut Command, prog: &str) -> Option { - let search_dirs = run_output(cc.arg("-print-search-dirs"), "cc").ok()?; + let search_dirs = run_output( + cc.arg("-print-search-dirs"), + "cc", + // this doesn't concern the compilation so we always want to show warnings. + true, + ) + .ok()?; // clang driver appears to be forcing UTF-8 output even on Windows, // hence from_utf8 is assumed to be usable in all cases. let search_dirs = std::str::from_utf8(&search_dirs).ok()?; @@ -4169,11 +4205,11 @@ struct PrintThread { } impl PrintThread { - fn new() -> Result { + fn new(cargo_warnings: bool) -> Result { let (pipe_reader, pipe_writer) = os_pipe::pipe()?; // Capture the standard error coming from compilation, and write it out - // with cargo:warning= prefixes. Note that this is a bit wonky to avoid + // with cargo:warning= prefixes if requested. Note that this is a bit wonky to avoid // requiring the output to be UTF-8, we instead just ship bytes from one // location to another. let print = thread::spawn(move || { @@ -4186,7 +4222,9 @@ impl PrintThread { { let mut stdout = stdout.lock(); - stdout.write_all(b"cargo:warning=").unwrap(); + if cargo_warnings { + stdout.write_all(b"cargo:warning=").unwrap(); + } stdout.write_all(&line).unwrap(); stdout.write_all(b"\n").unwrap(); } From 4a90bd864dee110297c72706380029f8523536c4 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Sun, 14 Jan 2024 23:18:48 +0100 Subject: [PATCH 03/23] comply with MSRV --- src/lib.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 48cfa9a6b..6acb8acf9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2182,16 +2182,19 @@ impl Build { cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into()); } _ => { - let mut stdout = io::stdout().lock(); - if self.cargo_warnings { - let _ = write!(stdout, "cargo:warning="); - } - let _ = writeln!( - stdout, - "cpp_set_stdlib is specified, but the {:?} compiler \ + let stdout = io::stdout(); + { + let mut stdout = stdout.lock(); + if self.cargo_warnings { + let _ = write!(stdout, "cargo:warning="); + } + let _ = writeln!( + stdout, + "cpp_set_stdlib is specified, but the {:?} compiler \ does not support this option, ignored", - cmd.family, - ); + cmd.family, + ); + } } } } @@ -2746,11 +2749,14 @@ impl Build { } if target.contains("msvc") && tool.family == ToolFamily::Gnu { - let mut stdout = io::stdout().lock(); - if self.cargo_warnings { - let _ = write!(stdout, "cargo:warning="); + let stdout = io::stdout(); + { + let mut stdout = stdout.lock(); + if self.cargo_warnings { + let _ = write!(stdout, "cargo:warning="); + } + let _ = writeln!(stdout, "GNU compiler is not supported for this target"); } - let _ = writeln!(stdout, "GNU compiler is not supported for this target"); } Ok(tool) From 40bb482d3a270565735fa0ebe92c9c9425ad78bb Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Sun, 14 Jan 2024 23:20:16 +0100 Subject: [PATCH 04/23] allow dead_code to make ci pass --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 6acb8acf9..3d2b75aa2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2405,7 +2405,7 @@ impl Build { enum ArchSpec { Device(&'static str), Simulator(&'static str), - Catalyst(&'static str), + Catalyst(#[allow(dead_code)] &'static str), } let target = self.get_target()?; From 7d51284679abc566c7b54c26f3a359a057e0b4b3 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Mon, 15 Jan 2024 12:58:18 +0100 Subject: [PATCH 05/23] make print thread optional --- src/lib.rs | 66 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3d2b75aa2..048b6f05a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1185,10 +1185,13 @@ impl Build { objects.push(Object::new(file.to_path_buf(), obj)); } - let print = PrintThread::new(self.cargo_warnings)?; + let print = self + .cargo_warnings + .then(|| PrintThread::new()) + .transpose()?; - self.compile_objects(&objects, &print)?; - self.assemble(lib_name, &dst.join(gnu_lib_name), &objects, &print)?; + self.compile_objects(&objects, print.as_ref())?; + self.assemble(lib_name, &dst.join(gnu_lib_name), &objects, print.as_ref())?; if self.get_target()?.contains("msvc") { let compiler = self.get_base_compiler()?; @@ -1329,7 +1332,7 @@ impl Build { } #[cfg(feature = "parallel")] - fn compile_objects(&self, objs: &[Object], print: &PrintThread) -> Result<(), Error> { + fn compile_objects(&self, objs: &[Object], print: Option<&PrintThread>) -> Result<(), Error> { use std::cell::Cell; use async_executor::{block_on, YieldOnce}; @@ -1440,7 +1443,8 @@ impl Build { YieldOnce::default().await } }; - let child = spawn(&mut cmd, &program, print.pipe_writer_cloned()?.unwrap())?; + let pipe_writer = print.map(|print| print.clone_pipe_writer()).transpose()?; + let child = spawn(&mut cmd, &program, pipe_writer)?; cell_update(&pendings, |mut pendings| { pendings.push((cmd, program, KillOnDrop(child), token)); @@ -1478,7 +1482,7 @@ impl Build { } #[cfg(not(feature = "parallel"))] - fn compile_objects(&self, objs: &[Object], print: &PrintThread) -> Result<(), Error> { + fn compile_objects(&self, objs: &[Object], print: Option<&PrintThread>) -> Result<(), Error> { for obj in objs { let (mut cmd, name) = self.create_compile_object_cmd(obj)?; run(&mut cmd, &name, print)?; @@ -2273,7 +2277,7 @@ impl Build { lib_name: &str, dst: &Path, objs: &[Object], - print: &PrintThread, + print: Option<&PrintThread>, ) -> Result<(), Error> { // Delete the destination if it exists as we want to // create on the first iteration instead of appending. @@ -2342,7 +2346,7 @@ impl Build { &self, dst: &Path, objs: &[&Path], - print: &PrintThread, + print: Option<&PrintThread>, ) -> Result<(), Error> { let target = self.get_target()?; @@ -3907,13 +3911,14 @@ fn try_wait_on_child( } } -fn run_inner(cmd: &mut Command, program: &str, pipe_writer: File) -> Result<(), Error> { +fn run_inner(cmd: &mut Command, program: &str, pipe_writer: Option) -> Result<(), Error> { let mut child = spawn(cmd, program, pipe_writer)?; wait_on_child(cmd, program, &mut child) } -fn run(cmd: &mut Command, program: &str, print: &PrintThread) -> Result<(), Error> { - run_inner(cmd, program, print.pipe_writer_cloned()?.unwrap())?; +fn run(cmd: &mut Command, program: &str, print: Option<&PrintThread>) -> Result<(), Error> { + let pipe_writer = print.map(|print| print.clone_pipe_writer()).transpose()?; + run_inner(cmd, program, pipe_writer)?; Ok(()) } @@ -3921,8 +3926,12 @@ fn run(cmd: &mut Command, program: &str, print: &PrintThread) -> Result<(), Erro fn run_output(cmd: &mut Command, program: &str, cargo_warnings: bool) -> Result, Error> { cmd.stdout(Stdio::piped()); - let mut print = PrintThread::new(cargo_warnings)?; - let mut child = spawn(cmd, program, print.pipe_writer().take().unwrap())?; + let mut print = cargo_warnings.then(|| PrintThread::new()).transpose()?; + let mut child = spawn( + cmd, + program, + print.as_mut().map(|print| print.take_pipe_writer()), + )?; let mut stdout = vec![]; child @@ -3937,7 +3946,7 @@ fn run_output(cmd: &mut Command, program: &str, cargo_warnings: bool) -> Result< Ok(stdout) } -fn spawn(cmd: &mut Command, program: &str, pipe_writer: File) -> Result { +fn spawn(cmd: &mut Command, program: &str, pipe_writer: Option) -> Result { struct ResetStderr<'cmd>(&'cmd mut Command); impl Drop for ResetStderr<'_> { @@ -3951,8 +3960,11 @@ fn spawn(cmd: &mut Command, program: &str, pipe_writer: File) -> Result Ok(child), Err(ref e) if e.kind() == io::ErrorKind::NotFound => { let extra = if cfg!(windows) { @@ -4211,7 +4223,7 @@ struct PrintThread { } impl PrintThread { - fn new(cargo_warnings: bool) -> Result { + fn new() -> Result { let (pipe_reader, pipe_writer) = os_pipe::pipe()?; // Capture the standard error coming from compilation, and write it out @@ -4228,9 +4240,7 @@ impl PrintThread { { let mut stdout = stdout.lock(); - if cargo_warnings { - stdout.write_all(b"cargo:warning=").unwrap(); - } + stdout.write_all(b"cargo:warning=").unwrap(); stdout.write_all(&line).unwrap(); stdout.write_all(b"\n").unwrap(); } @@ -4246,11 +4256,21 @@ impl PrintThread { }) } - fn pipe_writer(&mut self) -> &mut Option { - &mut self.pipe_writer + /// # Panics + /// + /// Will panic if the pipe writer has already been taken. + fn take_pipe_writer(&mut self) -> File { + self.pipe_writer.take().unwrap() + } + + /// # Panics + /// + /// Will panic if the pipe writer has already been taken. + fn clone_pipe_writer(&self) -> Result { + self.try_clone_pipe_writer().map(|writer| writer.unwrap()) } - fn pipe_writer_cloned(&self) -> Result, Error> { + fn try_clone_pipe_writer(&self) -> Result, Error> { self.pipe_writer .as_ref() .map(File::try_clone) From cf795f2f7604ef685dfa4e26af93ed9ef76d1db0 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Mon, 15 Jan 2024 14:12:51 +0100 Subject: [PATCH 06/23] simplify warnings using macros --- src/lib.rs | 62 +++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 048b6f05a..c0ee5ef5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -295,6 +295,25 @@ impl Object { } } +#[cfg(feature = "parallel")] +macro_rules! writeln_warning { + ($dst:expr $(,)?) => { + $crate::writeln_warning!($dst, "") + }; + ($dst:expr, $($arg:tt)*) => { + ::std::writeln!($dst, "cargo:warning={}", ::std::format_args!($($arg)*)) + }; +} + +macro_rules! println_warning { + () => { + $crate::println_warning!("") + }; + ($($arg:tt)*) => { + ::std::println!("cargo:warning={}", ::std::format_args!($($arg)*)) + }; +} + impl Build { /// Construct a new instance of a blank set of configuration. /// @@ -1409,9 +1428,8 @@ impl Build { has_made_progress.set(true); if self.cargo_warnings { - let _ = write!(stdout, "cargo:warning="); + let _ = writeln_warning!(stdout, "{}", err); } - let _ = writeln!(stdout, "{}", err); error = Some(err); false @@ -2186,18 +2204,8 @@ impl Build { cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into()); } _ => { - let stdout = io::stdout(); - { - let mut stdout = stdout.lock(); - if self.cargo_warnings { - let _ = write!(stdout, "cargo:warning="); - } - let _ = writeln!( - stdout, - "cpp_set_stdlib is specified, but the {:?} compiler \ - does not support this option, ignored", - cmd.family, - ); + if self.cargo_warnings { + println_warning!("cpp_set_stdlib is specified, but the {:?} compiler does not support this option, ignored", cmd.family); } } } @@ -2753,13 +2761,8 @@ impl Build { } if target.contains("msvc") && tool.family == ToolFamily::Gnu { - let stdout = io::stdout(); - { - let mut stdout = stdout.lock(); - if self.cargo_warnings { - let _ = write!(stdout, "cargo:warning="); - } - let _ = writeln!(stdout, "GNU compiler is not supported for this target"); + if self.cargo_warnings { + println_warning!("GNU compiler is not supported for this target"); } } @@ -3509,8 +3512,8 @@ impl Build { // If below 10.9, we round up. if major == 10 && minor < 9 { - println!( - "cargo:warning=macOS deployment target ({}) too low, it will be increased", + println_warning!( + "macOS deployment target ({}) too low, it will be increased", deployment_target_ver ); return String::from("10.9"); @@ -3520,8 +3523,8 @@ impl Build { let major = deployment_target.next().unwrap_or(0); if major < 7 { - println!( - "cargo:warning=iOS deployment target ({}) too low, it will be increased", + println_warning!( + "iOS deployment target ({}) too low, it will be increased", deployment_target_ver ); return String::from(OLD_IOS_MINIMUM_VERSION); @@ -3626,7 +3629,7 @@ impl Tool { Some(s) => s, None => { // --version failed. fallback to gnu - println!("cargo:warning=Failed to run: {:?}", cmd); + println_warning!("Failed to run: {:?}", cmd); return ToolFamily::Gnu; } }; @@ -3636,10 +3639,7 @@ impl Tool { ToolFamily::Gnu } else { // --version doesn't include clang for GCC - println!( - "cargo:warning=Compiler version doesn't include clang or GCC: {:?}", - cmd - ); + println_warning!("Compiler version doesn't include clang or GCC: {:?}", cmd); ToolFamily::Gnu } } @@ -4227,7 +4227,7 @@ impl PrintThread { let (pipe_reader, pipe_writer) = os_pipe::pipe()?; // Capture the standard error coming from compilation, and write it out - // with cargo:warning= prefixes if requested. Note that this is a bit wonky to avoid + // with cargo:warning= prefixes. Note that this is a bit wonky to avoid // requiring the output to be UTF-8, we instead just ship bytes from one // location to another. let print = thread::spawn(move || { From 17535c3b8cb3417436d2696e0b3796d4c36c864b Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Mon, 15 Jan 2024 14:54:58 +0100 Subject: [PATCH 07/23] add a test case --- cc-test/build.rs | 8 ++++++++ cc-test/src/suppress_warnings.c | 1 + 2 files changed, 9 insertions(+) create mode 100644 cc-test/src/suppress_warnings.c diff --git a/cc-test/build.rs b/cc-test/build.rs index 4097fbbd0..eeccb2af2 100644 --- a/cc-test/build.rs +++ b/cc-test/build.rs @@ -103,4 +103,12 @@ fn main() { let out = cc::Build::new().file("src/expand.c").expand(); let out = String::from_utf8(out).unwrap(); assert!(out.contains("hello world")); + + // Compilations _should_ fail, but we don't want it to show up as a warning. + cc::Build::new() + .cargo_metadata(false) + .cargo_warnings(false) + .file("src/suppress_warnings.c") + .try_compile("suppress_warnings") + .unwrap_err(); } diff --git a/cc-test/src/suppress_warnings.c b/cc-test/src/suppress_warnings.c new file mode 100644 index 000000000..535ae3419 --- /dev/null +++ b/cc-test/src/suppress_warnings.c @@ -0,0 +1 @@ +#error "if you see this, cargo_warnings(false) didn't do its job" From 67213e0d7b515b69b5b36d3e56b49ba29b305ca4 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Mon, 15 Jan 2024 15:29:34 +0100 Subject: [PATCH 08/23] this line in the docstring is no longer true --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index c0ee5ef5d..e64cd042b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1066,7 +1066,6 @@ impl Build { /// Define whether compile warnings should be emitted for cargo. Defaults to /// `true`. /// - /// If disabled, compiler messages are printed without the 'cargo:warning' prefix. /// Issues unrelated to the compilation will always produce cargo warnings regardless of this setting. pub fn cargo_warnings(&mut self, cargo_warnings: bool) -> &mut Build { self.cargo_warnings = cargo_warnings; From afada422f573e40415886dd632f6a6f63bb29a1e Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Tue, 16 Jan 2024 09:53:07 +0100 Subject: [PATCH 09/23] apply review suggestions --- src/lib.rs | 60 +++++++++++++++++++----------------------------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e64cd042b..990fa1c0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -295,25 +295,6 @@ impl Object { } } -#[cfg(feature = "parallel")] -macro_rules! writeln_warning { - ($dst:expr $(,)?) => { - $crate::writeln_warning!($dst, "") - }; - ($dst:expr, $($arg:tt)*) => { - ::std::writeln!($dst, "cargo:warning={}", ::std::format_args!($($arg)*)) - }; -} - -macro_rules! println_warning { - () => { - $crate::println_warning!("") - }; - ($($arg:tt)*) => { - ::std::println!("cargo:warning={}", ::std::format_args!($($arg)*)) - }; -} - impl Build { /// Construct a new instance of a blank set of configuration. /// @@ -1066,6 +1047,7 @@ impl Build { /// Define whether compile warnings should be emitted for cargo. Defaults to /// `true`. /// + /// If disabled, compiler messages will not be printed. /// Issues unrelated to the compilation will always produce cargo warnings regardless of this setting. pub fn cargo_warnings(&mut self, cargo_warnings: bool) -> &mut Build { self.cargo_warnings = cargo_warnings; @@ -1203,10 +1185,7 @@ impl Build { objects.push(Object::new(file.to_path_buf(), obj)); } - let print = self - .cargo_warnings - .then(|| PrintThread::new()) - .transpose()?; + let print = self.cargo_warnings.then(PrintThread::new).transpose()?; self.compile_objects(&objects, print.as_ref())?; self.assemble(lib_name, &dst.join(gnu_lib_name), &objects, print.as_ref())?; @@ -1426,9 +1405,7 @@ impl Build { // sure users always see all the compilation failures. has_made_progress.set(true); - if self.cargo_warnings { - let _ = writeln_warning!(stdout, "{}", err); - } + self.print_warning(&err); error = Some(err); false @@ -2203,9 +2180,7 @@ impl Build { cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into()); } _ => { - if self.cargo_warnings { - println_warning!("cpp_set_stdlib is specified, but the {:?} compiler does not support this option, ignored", cmd.family); - } + self.print_warning(&format_args!("cpp_set_stdlib is specified, but the {:?} compiler does not support this option, ignored", cmd.family)); } } } @@ -2760,9 +2735,7 @@ impl Build { } if target.contains("msvc") && tool.family == ToolFamily::Gnu { - if self.cargo_warnings { - println_warning!("GNU compiler is not supported for this target"); - } + self.print_warning(&"GNU compiler is not supported for this target"); } Ok(tool) @@ -3409,6 +3382,12 @@ impl Build { } } + fn print_warning(&self, arg: &dyn Display) { + if self.cargo_warnings { + println!("cargo:warning={}", arg); + } + } + fn fix_env_for_apple_os(&self, cmd: &mut Command) -> Result<(), Error> { let target = self.get_target()?; let host = self.get_host()?; @@ -3511,8 +3490,8 @@ impl Build { // If below 10.9, we round up. if major == 10 && minor < 9 { - println_warning!( - "macOS deployment target ({}) too low, it will be increased", + println!( + "cargo:warning=macOS deployment target ({}) too low, it will be increased", deployment_target_ver ); return String::from("10.9"); @@ -3522,8 +3501,8 @@ impl Build { let major = deployment_target.next().unwrap_or(0); if major < 7 { - println_warning!( - "iOS deployment target ({}) too low, it will be increased", + println!( + "cargo:warning=iOS deployment target ({}) too low, it will be increased", deployment_target_ver ); return String::from(OLD_IOS_MINIMUM_VERSION); @@ -3628,7 +3607,7 @@ impl Tool { Some(s) => s, None => { // --version failed. fallback to gnu - println_warning!("Failed to run: {:?}", cmd); + println!("cargo:warning=Failed to run: {:?}", cmd); return ToolFamily::Gnu; } }; @@ -3638,7 +3617,10 @@ impl Tool { ToolFamily::Gnu } else { // --version doesn't include clang for GCC - println_warning!("Compiler version doesn't include clang or GCC: {:?}", cmd); + println!( + "cargo:warning=Compiler version doesn't include clang or GCC: {:?}", + cmd + ); ToolFamily::Gnu } } @@ -3925,7 +3907,7 @@ fn run(cmd: &mut Command, program: &str, print: Option<&PrintThread>) -> Result< fn run_output(cmd: &mut Command, program: &str, cargo_warnings: bool) -> Result, Error> { cmd.stdout(Stdio::piped()); - let mut print = cargo_warnings.then(|| PrintThread::new()).transpose()?; + let mut print = cargo_warnings.then(PrintThread::new).transpose()?; let mut child = spawn( cmd, program, From a3b461403ce7ab1c38b015ea66e35170c763b025 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Tue, 16 Jan 2024 11:54:56 +0100 Subject: [PATCH 10/23] write warnings to buffered stdout --- src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 990fa1c0b..377d2a011 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1405,7 +1405,9 @@ impl Build { // sure users always see all the compilation failures. has_made_progress.set(true); - self.print_warning(&err); + if self.cargo_warnings { + let _ = writeln!(stdout, "cargo:warning={}", err); + } error = Some(err); false From c8c61a28bf021d99b924dab83f14a82ce451f2a6 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Tue, 16 Jan 2024 19:55:04 +0100 Subject: [PATCH 11/23] add proper output tests --- cc-test/build.rs | 66 +++++++++++++++++-- .../{suppress_warnings.c => compile_error.c} | 0 cc-test/src/dummy.c | 1 + cc-test/tests/output.rs | 42 ++++++++++++ 4 files changed, 102 insertions(+), 7 deletions(-) rename cc-test/src/{suppress_warnings.c => compile_error.c} (100%) create mode 100644 cc-test/src/dummy.c create mode 100644 cc-test/tests/output.rs diff --git a/cc-test/build.rs b/cc-test/build.rs index eeccb2af2..7710b9ffe 100644 --- a/cc-test/build.rs +++ b/cc-test/build.rs @@ -1,12 +1,26 @@ -use std::env; -use std::fs; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::{env, fs}; fn main() { + // if we are being executed from a `fork_run_action` call (i.e. this is a + // "fork"), perform the requested action and then return. + if run_action_if_forked() { + return; + } + let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); fs::remove_dir_all(&out).unwrap(); fs::create_dir(&out).unwrap(); + // The following are builds where we want to capture the output (i.e. stdout and + // stderr). We do that by re-running _this_ executable and passing in the + // action as the first argument. + run_forked_capture_output(&out, "metadata-on"); + run_forked_capture_output(&out, "metadata-off"); + run_forked_capture_output(&out, "warnings-on"); + run_forked_capture_output(&out, "warnings-off"); + cc::Build::new() .file("src/foo.c") .flag_if_supported("-Wall") @@ -103,12 +117,50 @@ fn main() { let out = cc::Build::new().file("src/expand.c").expand(); let out = String::from_utf8(out).unwrap(); assert!(out.contains("hello world")); +} + +#[track_caller] +fn run_forked_capture_output(out: &Path, action: &str) { + let program = env::current_exe().unwrap(); + let output = Command::new(&program).arg(action).output().unwrap(); + assert!(output.status.success()); + // we've captured the output and now we write it to a dedicated directory in the + // build output so our tests can access the output. + let action_dir = out.join(action); + fs::create_dir_all(&action_dir).unwrap(); + fs::write(action_dir.join("stdout"), output.stdout).unwrap(); + fs::write(action_dir.join("stderr"), output.stderr).unwrap(); +} - // Compilations _should_ fail, but we don't want it to show up as a warning. +fn run_action_if_forked() -> bool { + let mut args = env::args(); + let _program = args.next().unwrap(); + let action = args.next(); + match action.as_deref() { + Some("metadata-on") => build_cargo_metadata(true), + Some("metadata-off") => build_cargo_metadata(false), + Some("warnings-on") => build_cargo_warnings(true), + Some("warnings-off") => build_cargo_warnings(false), + // No action requested, we're being called from cargo. Proceed with build. + _ => return false, + } + true +} + +fn build_cargo_warnings(warnings: bool) { cc::Build::new() .cargo_metadata(false) - .cargo_warnings(false) - .file("src/suppress_warnings.c") - .try_compile("suppress_warnings") + .cargo_warnings(warnings) + .file("src/compile_error.c") + .try_compile("compile_error") + // we expect the compilation to fail in this case .unwrap_err(); } + +fn build_cargo_metadata(metadata: bool) { + cc::Build::new() + .cargo_metadata(metadata) + .file("src/dummy.c") + .try_compile("dummy") + .unwrap(); +} diff --git a/cc-test/src/suppress_warnings.c b/cc-test/src/compile_error.c similarity index 100% rename from cc-test/src/suppress_warnings.c rename to cc-test/src/compile_error.c diff --git a/cc-test/src/dummy.c b/cc-test/src/dummy.c new file mode 100644 index 000000000..6eec30e8c --- /dev/null +++ b/cc-test/src/dummy.c @@ -0,0 +1 @@ +/* just an empty file */ diff --git a/cc-test/tests/output.rs b/cc-test/tests/output.rs new file mode 100644 index 000000000..a4c8e2255 --- /dev/null +++ b/cc-test/tests/output.rs @@ -0,0 +1,42 @@ +use std::fs; +use std::path::PathBuf; + +#[test] +fn cargo_warnings_on() { + let (stdout, stderr) = load_output("warnings-on"); + assert!(stderr.is_empty()); + assert!(stdout.contains("cargo:warning=")); +} + +#[test] +fn cargo_warnings_off() { + let (stdout, stderr) = load_output("warnings-off"); + assert!(stderr.is_empty()); + assert!(!stdout.contains("cargo:warning=")); +} + +#[test] +fn cargo_metadata_on() { + let (stdout, stderr) = load_output("metadata-on"); + assert!(stderr.is_empty()); + assert!(stdout.contains("rustc-link-lib=")); + assert!(stdout.contains("rustc-link-search=")); +} + +#[test] +fn cargo_metadata_off() { + let (stdout, stderr) = load_output("metadata-off"); + assert!(stderr.is_empty()); + assert!(!stdout.contains("rustc-link-lib=")); + assert!(!stdout.contains("rustc-link-search=")); +} + +#[track_caller] +fn load_output(action: &str) -> (String, String) { + // these files are written by the `run_forked_capture_output` function in the + // build script. + let action_dir = PathBuf::from(env!("OUT_DIR")).join(action); + let stdout = fs::read_to_string(action_dir.join("stdout")).unwrap(); + let stderr = fs::read_to_string(action_dir.join("stderr")).unwrap(); + (stdout, stderr) +} From 3079bb00fb31abb4ed5f932228cb73fa52cb5498 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Tue, 16 Jan 2024 20:01:01 +0100 Subject: [PATCH 12/23] reduce import diff and always print stdout in tests --- cc-test/build.rs | 3 ++- cc-test/tests/output.rs | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cc-test/build.rs b/cc-test/build.rs index 7710b9ffe..f1f9f1b8e 100644 --- a/cc-test/build.rs +++ b/cc-test/build.rs @@ -1,6 +1,7 @@ +use std::env; +use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; -use std::{env, fs}; fn main() { // if we are being executed from a `fork_run_action` call (i.e. this is a diff --git a/cc-test/tests/output.rs b/cc-test/tests/output.rs index a4c8e2255..3f9b2e9ed 100644 --- a/cc-test/tests/output.rs +++ b/cc-test/tests/output.rs @@ -38,5 +38,7 @@ fn load_output(action: &str) -> (String, String) { let action_dir = PathBuf::from(env!("OUT_DIR")).join(action); let stdout = fs::read_to_string(action_dir.join("stdout")).unwrap(); let stderr = fs::read_to_string(action_dir.join("stderr")).unwrap(); + println!("compile stdout: {:?}", action, stdout); + println!("compile stderr: {:?}", action, stderr); (stdout, stderr) } From 00e980c0e4be74e0c91c569d85a36e0cacaf2ed3 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Tue, 16 Jan 2024 20:02:13 +0100 Subject: [PATCH 13/23] correct println --- cc-test/tests/output.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cc-test/tests/output.rs b/cc-test/tests/output.rs index 3f9b2e9ed..b891d21d4 100644 --- a/cc-test/tests/output.rs +++ b/cc-test/tests/output.rs @@ -38,7 +38,7 @@ fn load_output(action: &str) -> (String, String) { let action_dir = PathBuf::from(env!("OUT_DIR")).join(action); let stdout = fs::read_to_string(action_dir.join("stdout")).unwrap(); let stderr = fs::read_to_string(action_dir.join("stderr")).unwrap(); - println!("compile stdout: {:?}", action, stdout); - println!("compile stderr: {:?}", action, stderr); + println!("compile stdout: {:?}", stdout); + println!("compile stderr: {:?}", stderr); (stdout, stderr) } From fc724998b0a1993569d32927c3c5aff8809dafab Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Tue, 23 Jan 2024 12:10:15 +0100 Subject: [PATCH 14/23] add an output abstraction --- src/lib.rs | 162 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 99 insertions(+), 63 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 377d2a011..3b500a91d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,8 +122,7 @@ pub struct Build { compiler: Option>, archiver: Option>, ranlib: Option>, - cargo_metadata: bool, - cargo_warnings: bool, + cargo_output: CargoOutput, link_lib_modifiers: Vec>, pic: Option, use_plt: Option, @@ -331,8 +330,7 @@ impl Build { compiler: None, archiver: None, ranlib: None, - cargo_metadata: true, - cargo_warnings: true, + cargo_output: CargoOutput::new(), link_lib_modifiers: Vec::new(), pic: None, use_plt: None, @@ -529,7 +527,7 @@ impl Build { let host = self.get_host()?; let mut cfg = Build::new(); cfg.flag(flag) - .cargo_metadata(self.cargo_metadata) + .cargo_metadata(self.cargo_output.metadata) .target(&target) .opt_level(0) .host(&host) @@ -1040,7 +1038,7 @@ impl Build { /// - If `emit_rerun_if_env_changed` is not `false`, `rerun-if-env-changed=`*env* /// pub fn cargo_metadata(&mut self, cargo_metadata: bool) -> &mut Build { - self.cargo_metadata = cargo_metadata; + self.cargo_output.metadata = cargo_metadata; self } @@ -1050,7 +1048,7 @@ impl Build { /// If disabled, compiler messages will not be printed. /// Issues unrelated to the compilation will always produce cargo warnings regardless of this setting. pub fn cargo_warnings(&mut self, cargo_warnings: bool) -> &mut Build { - self.cargo_warnings = cargo_warnings; + self.cargo_output.warnings = cargo_warnings; self } @@ -1185,7 +1183,7 @@ impl Build { objects.push(Object::new(file.to_path_buf(), obj)); } - let print = self.cargo_warnings.then(PrintThread::new).transpose()?; + let print = self.cargo_output.print_thread()?; self.compile_objects(&objects, print.as_ref())?; self.assemble(lib_name, &dst.join(gnu_lib_name), &objects, print.as_ref())?; @@ -1204,7 +1202,7 @@ impl Build { }); if let Some(atlmfc_lib) = atlmfc_lib { - self.print(&format_args!( + self.cargo_output.print_metadata(&format_args!( "cargo:rustc-link-search=native={}", atlmfc_lib.display() )); @@ -1212,15 +1210,16 @@ impl Build { } if self.link_lib_modifiers.is_empty() { - self.print(&format_args!("cargo:rustc-link-lib=static={}", lib_name)); + self.cargo_output + .print_metadata(&format_args!("cargo:rustc-link-lib=static={}", lib_name)); } else { let m = self.link_lib_modifiers.join(","); - self.print(&format_args!( + self.cargo_output.print_metadata(&format_args!( "cargo:rustc-link-lib=static:{}={}", m, lib_name )); } - self.print(&format_args!( + self.cargo_output.print_metadata(&format_args!( "cargo:rustc-link-search=native={}", dst.display() )); @@ -1228,7 +1227,8 @@ impl Build { // Add specific C++ libraries, if enabled. if self.cpp { if let Some(stdlib) = self.get_cpp_link_stdlib()? { - self.print(&format_args!("cargo:rustc-link-lib={}", stdlib)); + self.cargo_output + .print_metadata(&format_args!("cargo:rustc-link-lib={}", stdlib)); } } @@ -1405,7 +1405,7 @@ impl Build { // sure users always see all the compilation failures. has_made_progress.set(true); - if self.cargo_warnings { + if self.cargo_output.warnings { let _ = writeln!(stdout, "cargo:warning={}", err); } error = Some(err); @@ -1581,7 +1581,7 @@ impl Build { .to_string_lossy() .into_owned(); - Ok(run_output(&mut cmd, &name, self.cargo_warnings)?) + Ok(run_output(&mut cmd, &name, &self.cargo_output)?) } /// Run the compiler, returning the macro-expanded version of the input files. @@ -2182,7 +2182,7 @@ impl Build { cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into()); } _ => { - self.print_warning(&format_args!("cpp_set_stdlib is specified, but the {:?} compiler does not support this option, ignored", cmd.family)); + self.cargo_output.print_warning(&format_args!("cpp_set_stdlib is specified, but the {:?} compiler does not support this option, ignored", cmd.family)); } } } @@ -2519,7 +2519,8 @@ impl Build { // AppleClang sometimes requires sysroot even for darwin if cmd.is_xctoolchain_clang() || !target.ends_with("-darwin") { - self.print(&format_args!("Detecting {:?} SDK path for {}", os, sdk)); + self.cargo_output + .print_metadata(&format_args!("Detecting {:?} SDK path for {}", os, sdk)); let sdk_path = if let Some(sdkroot) = env::var_os("SDKROOT") { sdkroot } else { @@ -2543,7 +2544,7 @@ impl Build { fn get_base_compiler(&self) -> Result { if let Some(c) = &self.compiler { - return Ok(Tool::new((**c).to_owned())); + return Ok(Tool::new((**c).to_owned(), &self.cargo_output)); } let host = self.get_host()?; let target = self.get_target()?; @@ -2579,7 +2580,7 @@ impl Build { // semi-buggy build scripts which are shared in // makefiles/configure scripts (where spaces are far more // lenient) - let mut t = Tool::with_clang_driver(tool, driver_mode); + let mut t = Tool::with_clang_driver(tool, driver_mode, &self.cargo_output); if let Some(cc_wrapper) = wrapper { t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); } @@ -2593,12 +2594,12 @@ impl Build { let tool = if self.cpp { "em++" } else { "emcc" }; // Windows uses bat file so we have to be a bit more specific if cfg!(windows) { - let mut t = Tool::new(PathBuf::from("cmd")); + let mut t = Tool::new(PathBuf::from("cmd"), &self.cargo_output); t.args.push("/c".into()); t.args.push(format!("{}.bat", tool).into()); Some(t) } else { - Some(Tool::new(PathBuf::from(tool))) + Some(Tool::new(PathBuf::from(tool), &self.cargo_output)) } } else { None @@ -2653,7 +2654,7 @@ impl Build { default.to_string() }; - let mut t = Tool::new(PathBuf::from(compiler)); + let mut t = Tool::new(PathBuf::from(compiler), &self.cargo_output); if let Some(cc_wrapper) = Self::rustc_wrapper_fallback() { t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); } @@ -2670,7 +2671,7 @@ impl Build { Err(_) => PathBuf::from("nvcc"), Ok(nvcc) => PathBuf::from(&*nvcc), }; - let mut nvcc_tool = Tool::with_features(nvcc, None, self.cuda); + let mut nvcc_tool = Tool::with_features(nvcc, None, self.cuda, &self.cargo_output); nvcc_tool .args .push(format!("-ccbin={}", tool.path.display()).into()); @@ -2737,7 +2738,8 @@ impl Build { } if target.contains("msvc") && tool.family == ToolFamily::Gnu { - self.print_warning(&"GNU compiler is not supported for this target"); + self.cargo_output + .print_warning(&"GNU compiler is not supported for this target"); } Ok(tool) @@ -2988,7 +2990,7 @@ impl Build { let compiler = self.get_base_compiler().ok()?; if compiler.family == ToolFamily::Clang { name = format!("llvm-{}", tool); - search_programs(&mut self.cmd(&compiler.path), &name) + search_programs(&mut self.cmd(&compiler.path), &name, &self.cargo_output) .map(|name| self.cmd(name)) } else { None @@ -3332,10 +3334,12 @@ impl Build { return val.clone(); } if self.emit_rerun_if_env_changed && !provided_by_cargo(v) { - self.print(&format_args!("cargo:rerun-if-env-changed={}", v)); + self.cargo_output + .print_metadata(&format_args!("cargo:rerun-if-env-changed={}", v)); } let r = env::var(v).ok().map(Arc::from); - self.print(&format_args!("{} = {:?}", v, r)); + self.cargo_output + .print_metadata(&format_args!("{} = {:?}", v, r)); cache.insert(v.to_string(), r.clone()); r } @@ -3378,18 +3382,6 @@ impl Build { .collect()) } - fn print(&self, s: &dyn Display) { - if self.cargo_metadata { - println!("{}", s); - } - } - - fn print_warning(&self, arg: &dyn Display) { - if self.cargo_warnings { - println!("cargo:warning={}", arg); - } - } - fn fix_env_for_apple_os(&self, cmd: &mut Command) -> Result<(), Error> { let target = self.get_target()?; let host = self.get_host()?; @@ -3417,7 +3409,7 @@ impl Build { .arg("--sdk") .arg(sdk), "xcrun", - self.cargo_warnings, + &self.cargo_output, )?; let sdk_path = match String::from_utf8(sdk_path) { @@ -3492,10 +3484,10 @@ impl Build { // If below 10.9, we round up. if major == 10 && minor < 9 { - println!( - "cargo:warning=macOS deployment target ({}) too low, it will be increased", + self.cargo_output.print_warning(&format_args!( + "macOS deployment target ({}) too low, it will be increased", deployment_target_ver - ); + )); return String::from("10.9"); } } @@ -3503,10 +3495,10 @@ impl Build { let major = deployment_target.next().unwrap_or(0); if major < 7 { - println!( - "cargo:warning=iOS deployment target ({}) too low, it will be increased", + self.cargo_output.print_warning(&format_args!( + "iOS deployment target ({}) too low, it will be increased", deployment_target_ver - ); + )); return String::from(OLD_IOS_MINIMUM_VERSION); } } @@ -3568,12 +3560,16 @@ impl Default for Build { } impl Tool { - fn new(path: PathBuf) -> Self { - Tool::with_features(path, None, false) + fn new(path: PathBuf, cargo_output: &CargoOutput) -> Self { + Tool::with_features(path, None, false, cargo_output) } - fn with_clang_driver(path: PathBuf, clang_driver: Option<&str>) -> Self { - Self::with_features(path, clang_driver, false) + fn with_clang_driver( + path: PathBuf, + clang_driver: Option<&str>, + cargo_output: &CargoOutput, + ) -> Self { + Self::with_features(path, clang_driver, false, cargo_output) } #[cfg(windows)] @@ -3592,8 +3588,13 @@ impl Tool { } } - fn with_features(path: PathBuf, clang_driver: Option<&str>, cuda: bool) -> Self { - fn detect_family(path: &Path) -> ToolFamily { + fn with_features( + path: PathBuf, + clang_driver: Option<&str>, + cuda: bool, + cargo_output: &CargoOutput, + ) -> Self { + fn detect_family(path: &Path, cargo_output: &CargoOutput) -> ToolFamily { let mut cmd = Command::new(path); cmd.arg("--version"); @@ -3601,7 +3602,7 @@ impl Tool { &mut cmd, &path.to_string_lossy(), // tool detection issues should always be shown as warnings - true, + cargo_output, ) .ok() .and_then(|o| String::from_utf8(o).ok()) @@ -3609,7 +3610,7 @@ impl Tool { Some(s) => s, None => { // --version failed. fallback to gnu - println!("cargo:warning=Failed to run: {:?}", cmd); + cargo_output.print_warning(&format_args!("Failed to run: {:?}", cmd)); return ToolFamily::Gnu; } }; @@ -3619,10 +3620,10 @@ impl Tool { ToolFamily::Gnu } else { // --version doesn't include clang for GCC - println!( - "cargo:warning=Compiler version doesn't include clang or GCC: {:?}", + cargo_output.print_warning(&format_args!( + "Compiler version doesn't include clang or GCC: {:?}", cmd - ); + )); ToolFamily::Gnu } } @@ -3639,10 +3640,10 @@ impl Tool { _ => ToolFamily::Clang, } } else { - detect_family(&path) + detect_family(&path, cargo_output) } } else { - detect_family(&path) + detect_family(&path, cargo_output) }; Tool { @@ -3906,10 +3907,14 @@ fn run(cmd: &mut Command, program: &str, print: Option<&PrintThread>) -> Result< Ok(()) } -fn run_output(cmd: &mut Command, program: &str, cargo_warnings: bool) -> Result, Error> { +fn run_output( + cmd: &mut Command, + program: &str, + cargo_output: &CargoOutput, +) -> Result, Error> { cmd.stdout(Stdio::piped()); - let mut print = cargo_warnings.then(PrintThread::new).transpose()?; + let mut print = cargo_output.print_thread()?; let mut child = spawn( cmd, program, @@ -4156,12 +4161,12 @@ fn which(tool: &Path, path_entries: Option) -> Option { } // search for |prog| on 'programs' path in '|cc| -print-search-dirs' output -fn search_programs(cc: &mut Command, prog: &str) -> Option { +fn search_programs(cc: &mut Command, prog: &str, cargo_output: &CargoOutput) -> Option { let search_dirs = run_output( cc.arg("-print-search-dirs"), "cc", // this doesn't concern the compilation so we always want to show warnings. - true, + cargo_output, ) .ok()?; // clang driver appears to be forcing UTF-8 output even on Windows, @@ -4200,6 +4205,37 @@ impl AsmFileExt { } } +#[derive(Clone, Debug)] +struct CargoOutput { + metadata: bool, + warnings: bool, +} + +impl CargoOutput { + const fn new() -> Self { + Self { + metadata: true, + warnings: true, + } + } + + fn print_metadata(&self, s: &dyn Display) { + if self.metadata { + println!("{}", s); + } + } + + fn print_warning(&self, arg: &dyn Display) { + if self.warnings { + println!("cargo:warning={}", arg); + } + } + + fn print_thread(&self) -> Result, Error> { + self.warnings.then(PrintThread::new).transpose() + } +} + struct PrintThread { handle: Option>, pipe_writer: Option, From fc2fb6623049bb22f9264a2fb449d27485c97595 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Tue, 23 Jan 2024 12:50:38 +0100 Subject: [PATCH 15/23] hopefully make the tests work on win32 --- cc-test/build.rs | 9 ++++----- cc-test/src/compile_error.c | 1 - cc-test/src/compile_warning.c | 3 +++ cc-test/src/dummy.c | 2 ++ cc-test/tests/output.rs | 27 +++++++++++++++++++++++---- 5 files changed, 32 insertions(+), 10 deletions(-) delete mode 100644 cc-test/src/compile_error.c create mode 100644 cc-test/src/compile_warning.c diff --git a/cc-test/build.rs b/cc-test/build.rs index f1f9f1b8e..4215da986 100644 --- a/cc-test/build.rs +++ b/cc-test/build.rs @@ -124,7 +124,7 @@ fn main() { fn run_forked_capture_output(out: &Path, action: &str) { let program = env::current_exe().unwrap(); let output = Command::new(&program).arg(action).output().unwrap(); - assert!(output.status.success()); + assert!(output.status.success(), "output: {:#?}", output); // we've captured the output and now we write it to a dedicated directory in the // build output so our tests can access the output. let action_dir = out.join(action); @@ -152,10 +152,9 @@ fn build_cargo_warnings(warnings: bool) { cc::Build::new() .cargo_metadata(false) .cargo_warnings(warnings) - .file("src/compile_error.c") - .try_compile("compile_error") - // we expect the compilation to fail in this case - .unwrap_err(); + .file("src/compile_warning.c") + .try_compile("compile_warning") + .unwrap(); } fn build_cargo_metadata(metadata: bool) { diff --git a/cc-test/src/compile_error.c b/cc-test/src/compile_error.c deleted file mode 100644 index 535ae3419..000000000 --- a/cc-test/src/compile_error.c +++ /dev/null @@ -1 +0,0 @@ -#error "if you see this, cargo_warnings(false) didn't do its job" diff --git a/cc-test/src/compile_warning.c b/cc-test/src/compile_warning.c new file mode 100644 index 000000000..46cab3e2d --- /dev/null +++ b/cc-test/src/compile_warning.c @@ -0,0 +1,3 @@ +#warning "if you see this, cargo_warnings(false) didn't do its job" + +void compile_warning(void) {} diff --git a/cc-test/src/dummy.c b/cc-test/src/dummy.c index 6eec30e8c..0edb14bee 100644 --- a/cc-test/src/dummy.c +++ b/cc-test/src/dummy.c @@ -1 +1,3 @@ /* just an empty file */ + +void dummy(void) {} diff --git a/cc-test/tests/output.rs b/cc-test/tests/output.rs index b891d21d4..a06641e73 100644 --- a/cc-test/tests/output.rs +++ b/cc-test/tests/output.rs @@ -19,16 +19,35 @@ fn cargo_warnings_off() { fn cargo_metadata_on() { let (stdout, stderr) = load_output("metadata-on"); assert!(stderr.is_empty()); - assert!(stdout.contains("rustc-link-lib=")); - assert!(stdout.contains("rustc-link-search=")); + assert!(stdout.contains("cargo:rustc-link-lib=")); + assert!(stdout.contains("cargo:rustc-link-search=")); } #[test] fn cargo_metadata_off() { let (stdout, stderr) = load_output("metadata-off"); assert!(stderr.is_empty()); - assert!(!stdout.contains("rustc-link-lib=")); - assert!(!stdout.contains("rustc-link-search=")); + + // most of the instructions aren't currently used + const INSTRUCTIONS: &[&str] = &[ + "cargo:rerun-if-changed=", + "cargo:rerun-if-env-changed=", + "cargo:rustc-cdylib-link-arg=", + "cargo:rustc-cfg=", + "cargo:rustc-env=", + "cargo:rustc-flags=", + "cargo:rustc-link-arg-benches=", + "cargo:rustc-link-arg-bin=", + "cargo:rustc-link-arg-bins=", + "cargo:rustc-link-arg-examples=", + "cargo:rustc-link-arg-tests=", + "cargo:rustc-link-arg=", + "cargo:rustc-link-lib=", + "cargo:rustc-link-search=", + ]; + for instr in INSTRUCTIONS { + assert!(!stdout.contains(instr), "instruction present: {}", instr); + } } #[track_caller] From 690269a41e10c7a2dc5fe3ceb9582374b52b9377 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Tue, 23 Jan 2024 13:05:35 +0100 Subject: [PATCH 16/23] msvc-compatible warnings --- cc-test/src/compile_warning.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cc-test/src/compile_warning.c b/cc-test/src/compile_warning.c index 46cab3e2d..01ed76e04 100644 --- a/cc-test/src/compile_warning.c +++ b/cc-test/src/compile_warning.c @@ -1,3 +1,7 @@ -#warning "if you see this, cargo_warnings(false) didn't do its job" +#if _MSC_VER +# pragma message("if you see this, cargo_warnings(false) didn't do its job") +#else +# warning "if you see this, cargo_warnings(false) didn't do its job" +#endif void compile_warning(void) {} From a6296908381ab08a07f670eee10c866f73258cc6 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Tue, 23 Jan 2024 15:26:15 +0100 Subject: [PATCH 17/23] turns out we can't capture warnings for msvc... --- cc-test/build.rs | 16 ++++++++++++---- cc-test/src/compile_error.c | 1 + cc-test/src/compile_warning.c | 7 ------- cc-test/tests/output.rs | 5 +++++ 4 files changed, 18 insertions(+), 11 deletions(-) create mode 100644 cc-test/src/compile_error.c delete mode 100644 cc-test/src/compile_warning.c diff --git a/cc-test/build.rs b/cc-test/build.rs index 4215da986..8968eb530 100644 --- a/cc-test/build.rs +++ b/cc-test/build.rs @@ -19,8 +19,16 @@ fn main() { // action as the first argument. run_forked_capture_output(&out, "metadata-on"); run_forked_capture_output(&out, "metadata-off"); - run_forked_capture_output(&out, "warnings-on"); + run_forked_capture_output(&out, "warnings-off"); + if cc::Build::new().get_compiler().is_like_msvc() { + // MSVC doesn't output warnings to stderr, so we can't capture them. + // the test will use this env var to know whether to run the test. + println!("cargo:rustc-env=TEST_WARNINGS_ON=0"); + } else { + println!("cargo:rustc-env=TEST_WARNINGS_ON=1"); + run_forked_capture_output(&out, "warnings-on"); + } cc::Build::new() .file("src/foo.c") @@ -152,9 +160,9 @@ fn build_cargo_warnings(warnings: bool) { cc::Build::new() .cargo_metadata(false) .cargo_warnings(warnings) - .file("src/compile_warning.c") - .try_compile("compile_warning") - .unwrap(); + .file("src/compile_error.c") + .try_compile("compile_error") + .unwrap_err(); } fn build_cargo_metadata(metadata: bool) { diff --git a/cc-test/src/compile_error.c b/cc-test/src/compile_error.c new file mode 100644 index 000000000..535ae3419 --- /dev/null +++ b/cc-test/src/compile_error.c @@ -0,0 +1 @@ +#error "if you see this, cargo_warnings(false) didn't do its job" diff --git a/cc-test/src/compile_warning.c b/cc-test/src/compile_warning.c deleted file mode 100644 index 01ed76e04..000000000 --- a/cc-test/src/compile_warning.c +++ /dev/null @@ -1,7 +0,0 @@ -#if _MSC_VER -# pragma message("if you see this, cargo_warnings(false) didn't do its job") -#else -# warning "if you see this, cargo_warnings(false) didn't do its job" -#endif - -void compile_warning(void) {} diff --git a/cc-test/tests/output.rs b/cc-test/tests/output.rs index a06641e73..2264dab2c 100644 --- a/cc-test/tests/output.rs +++ b/cc-test/tests/output.rs @@ -3,6 +3,11 @@ use std::path::PathBuf; #[test] fn cargo_warnings_on() { + if env!("TEST_WARNINGS_ON") == "0" { + // in some cases we don't catch compiler warnings and turn them into cargo + // instructions. + assert!(false); + } let (stdout, stderr) = load_output("warnings-on"); assert!(stderr.is_empty()); assert!(stdout.contains("cargo:warning=")); From 19174cb0eabb67b75fd89a5a54625970c1133691 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Tue, 23 Jan 2024 15:26:33 +0100 Subject: [PATCH 18/23] fix unconditional metadata output --- src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3b500a91d..06a88d563 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1266,10 +1266,10 @@ impl Build { } } if libtst && libdir.is_dir() { - println!( + self.cargo_output.print_metadata(&format_args!( "cargo:rustc-link-search=native={}", libdir.to_str().unwrap() - ); + )); } // And now the -l flag. @@ -1278,7 +1278,8 @@ impl Build { "static" => "cudart_static", bad => panic!("unsupported cudart option: {}", bad), }; - println!("cargo:rustc-link-lib={}", lib); + self.cargo_output + .print_metadata(&format_args!("cargo:rustc-link-lib={}", lib)); } } From 4b5cdf46cad48fd7adf0693d5e4b1568f57a8e03 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Tue, 23 Jan 2024 15:29:12 +0100 Subject: [PATCH 19/23] skip warnings_on test for msvc --- cc-test/tests/output.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cc-test/tests/output.rs b/cc-test/tests/output.rs index 2264dab2c..9bfe61dc5 100644 --- a/cc-test/tests/output.rs +++ b/cc-test/tests/output.rs @@ -6,7 +6,7 @@ fn cargo_warnings_on() { if env!("TEST_WARNINGS_ON") == "0" { // in some cases we don't catch compiler warnings and turn them into cargo // instructions. - assert!(false); + return; } let (stdout, stderr) = load_output("warnings-on"); assert!(stderr.is_empty()); From 4ab4158aad2fe8082175fcdde26f79048ca00b38 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Wed, 24 Jan 2024 11:20:11 +0100 Subject: [PATCH 20/23] Update src/lib.rs Co-authored-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 06a88d563..c3f25d3de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4287,7 +4287,7 @@ impl PrintThread { /// /// Will panic if the pipe writer has already been taken. fn clone_pipe_writer(&self) -> Result { - self.try_clone_pipe_writer().map(|writer| writer.unwrap()) + self.try_clone_pipe_writer().map(Option::unwrap) } fn try_clone_pipe_writer(&self) -> Result, Error> { From 02f8895d8f6023890ff43045f781d17a3e53af37 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Wed, 24 Jan 2024 11:20:19 +0100 Subject: [PATCH 21/23] Update src/lib.rs Co-authored-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 c3f25d3de..f153ec613 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3919,7 +3919,7 @@ fn run_output( let mut child = spawn( cmd, program, - print.as_mut().map(|print| print.take_pipe_writer()), + print.as_mut().map(PrintThread::take_pipe_writer), )?; let mut stdout = vec![]; From 7495e35690596b9a47abf096d59d233bbb91ccf9 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Wed, 24 Jan 2024 11:20:26 +0100 Subject: [PATCH 22/23] Update src/lib.rs Co-authored-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 f153ec613..d716449aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3902,7 +3902,7 @@ fn run_inner(cmd: &mut Command, program: &str, pipe_writer: Option) -> Res } fn run(cmd: &mut Command, program: &str, print: Option<&PrintThread>) -> Result<(), Error> { - let pipe_writer = print.map(|print| print.clone_pipe_writer()).transpose()?; + let pipe_writer = print.map(PrintThread::clone_pipe_writer).transpose()?; run_inner(cmd, program, pipe_writer)?; Ok(()) From d475e932ecff159a8d30e04cf45bf4c639ac1e76 Mon Sep 17 00:00:00 2001 From: Simon Berger Date: Wed, 24 Jan 2024 15:06:56 +0100 Subject: [PATCH 23/23] Update src/lib.rs Co-authored-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 d716449aa..ba1c2242e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1440,7 +1440,7 @@ impl Build { YieldOnce::default().await } }; - let pipe_writer = print.map(|print| print.clone_pipe_writer()).transpose()?; + let pipe_writer = print.map(PrintThread::clone_pipe_writer).transpose()?; let child = spawn(&mut cmd, &program, pipe_writer)?; cell_update(&pendings, |mut pendings| {