diff --git a/src/command_helpers.rs b/src/command_helpers.rs index 2fce90a9..f3cb655c 100644 --- a/src/command_helpers.rs +++ b/src/command_helpers.rs @@ -22,15 +22,28 @@ pub(crate) struct CargoOutput { pub(crate) metadata: bool, pub(crate) warnings: bool, pub(crate) debug: bool, + pub(crate) output: OutputKind, checked_dbg_var: Arc, } +/// Different strategies for handling compiler output (to stdout) +#[derive(Clone, Debug)] +pub(crate) enum OutputKind { + /// Forward the output to this process' stdout (Stdio::inherit) + Forward, + /// Discard the output (Stdio::null) + Discard, + /// Capture the result + Capture, +} + impl CargoOutput { pub(crate) fn new() -> Self { #[allow(clippy::disallowed_methods)] Self { metadata: true, warnings: true, + output: OutputKind::Forward, debug: std::env::var_os("CC_ENABLE_DEBUG_OUTPUT").is_some(), checked_dbg_var: Arc::new(AtomicBool::new(false)), } @@ -65,6 +78,14 @@ impl CargoOutput { Stdio::null() } } + + fn stdio_for_output(&self) -> Stdio { + match self.output { + OutputKind::Capture => Stdio::piped(), + OutputKind::Forward => Stdio::inherit(), + OutputKind::Discard => Stdio::null(), + } + } } pub(crate) struct StderrForwarder { @@ -321,9 +342,10 @@ pub(crate) fn run_output( ) -> Result, Error> { let program = program.as_ref(); - cmd.stdout(Stdio::piped()); - - let mut child = spawn(cmd, program, cargo_output)?; + // We specifically need the output to be captured, so override default + let mut captured_cargo_output = cargo_output.clone(); + captured_cargo_output.output = OutputKind::Capture; + let mut child = spawn(cmd, program, &captured_cargo_output)?; let mut stdout = vec![]; child @@ -333,6 +355,7 @@ pub(crate) fn run_output( .read_to_end(&mut stdout) .unwrap(); + // Don't care about this output, use the normal settings wait_on_child(cmd, program, &mut child, cargo_output)?; Ok(stdout) @@ -356,7 +379,11 @@ pub(crate) fn spawn( cargo_output.print_debug(&format_args!("running: {:?}", cmd)); let cmd = ResetStderr(cmd); - let child = cmd.0.stderr(cargo_output.stdio_for_warnings()).spawn(); + let child = cmd + .0 + .stderr(cargo_output.stdio_for_warnings()) + .stdout(cargo_output.stdio_for_output()) + .spawn(); match child { Ok(child) => Ok(child), Err(ref e) if e.kind() == io::ErrorKind::NotFound => { diff --git a/src/lib.rs b/src/lib.rs index 55a0039b..55d3c4ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1196,6 +1196,20 @@ impl Build { self } + /// Define whether compiler output (to stdout) should be emitted. Defaults to `true` + /// (forward compiler stdout to this process' stdout) + /// + /// Some compilers emit errors to stdout, so if you *really* need stdout to be clean + /// you should also set this to `false`. + pub fn cargo_output(&mut self, cargo_output: bool) -> &mut Build { + self.cargo_output.output = if cargo_output { + OutputKind::Forward + } else { + OutputKind::Discard + }; + 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. diff --git a/src/tool.rs b/src/tool.rs index 72fc23b5..3a015f36 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::RwLock, }; @@ -13,7 +13,7 @@ use crate::{ command_helpers::{run_output, CargoOutput}, run, tempfile::NamedTempfile, - Error, ErrorKind, + Error, ErrorKind, OutputKind, }; /// Configuration used to represent an invocation of a C compiler. @@ -158,14 +158,14 @@ impl Tool { cargo_output.print_debug(&stdout); // https://gitlab.kitware.com/cmake/cmake/-/blob/69a2eeb9dff5b60f2f1e5b425002a0fd45b7cadb/Modules/CMakeDetermineCompilerId.cmake#L267-271 - let accepts_cl_style_flags = - run(Command::new(path).arg("-?").stdout(Stdio::null()), path, &{ - // the errors are not errors! - let mut cargo_output = cargo_output.clone(); - cargo_output.warnings = cargo_output.debug; - cargo_output - }) - .is_ok(); + let accepts_cl_style_flags = run(Command::new(path).arg("-?"), path, &{ + // the errors are not errors! + let mut cargo_output = cargo_output.clone(); + cargo_output.warnings = cargo_output.debug; + cargo_output.output = OutputKind::Discard; + cargo_output + }) + .is_ok(); let clang = stdout.contains(r#""clang""#); let gcc = stdout.contains(r#""gcc""#); @@ -283,7 +283,7 @@ impl Tool { /// Don't push optimization arg if it conflicts with existing args. pub(crate) fn push_opt_unless_duplicate(&mut self, flag: OsString) { if self.is_duplicate_opt_arg(&flag) { - println!("Info: Ignoring duplicate arg {:?}", &flag); + eprintln!("Info: Ignoring duplicate arg {:?}", &flag); } else { self.push_cc_arg(flag); } diff --git a/src/windows/find_tools.rs b/src/windows/find_tools.rs index 8bd11aa3..d872a3a9 100644 --- a/src/windows/find_tools.rs +++ b/src/windows/find_tools.rs @@ -257,7 +257,7 @@ mod impl_ { impl LibraryHandle { fn new(name: &[u8]) -> Option { let handle = unsafe { LoadLibraryA(name.as_ptr() as _) }; - (!handle.is_null()).then(|| Self(handle)) + (!handle.is_null()).then_some(Self(handle)) } /// Get a function pointer to a function in the library.