Skip to content

Commit e16d8b9

Browse files
committed
feat: add cargo_output to eliminate last vestiges of stdout pollution
1 parent 2802459 commit e16d8b9

File tree

5 files changed

+66
-17
lines changed

5 files changed

+66
-17
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ libc = { version = "0.2.62", default-features = false, optional = true }
3030

3131
[features]
3232
parallel = ["dep:libc", "dep:jobserver", "dep:once_cell"]
33+
# enables OutputKind::Stderr which requires rustc 1.74.0 -- currently above msrv
34+
stdout_to_stderr = []
3335

3436
[dev-dependencies]
3537
tempfile = "3"

src/command_helpers.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ use std::{
1515
},
1616
};
1717

18-
use crate::{Error, ErrorKind, Object};
18+
use crate::{Error, ErrorKind, Object, OutputKind};
1919

2020
#[derive(Clone, Debug)]
2121
pub(crate) struct CargoOutput {
2222
pub(crate) metadata: bool,
2323
pub(crate) warnings: bool,
2424
pub(crate) debug: bool,
25+
pub(crate) output: OutputKind,
2526
checked_dbg_var: Arc<AtomicBool>,
2627
}
2728

@@ -31,6 +32,7 @@ impl CargoOutput {
3132
Self {
3233
metadata: true,
3334
warnings: true,
35+
output: OutputKind::Forward,
3436
debug: std::env::var_os("CC_ENABLE_DEBUG_OUTPUT").is_some(),
3537
checked_dbg_var: Arc::new(AtomicBool::new(false)),
3638
}
@@ -65,6 +67,16 @@ impl CargoOutput {
6567
Stdio::null()
6668
}
6769
}
70+
71+
fn stdio_for_output(&self) -> Stdio {
72+
match self.output {
73+
OutputKind::Capture => Stdio::piped(),
74+
OutputKind::Forward => Stdio::inherit(),
75+
OutputKind::Discard => Stdio::null(),
76+
#[cfg(feature = "stdout_to_stderr")]
77+
OutputKind::Stderr => std::io::stderr().into(),
78+
}
79+
}
6880
}
6981

7082
pub(crate) struct StderrForwarder {
@@ -321,9 +333,10 @@ pub(crate) fn run_output(
321333
) -> Result<Vec<u8>, Error> {
322334
let program = program.as_ref();
323335

324-
cmd.stdout(Stdio::piped());
325-
326-
let mut child = spawn(cmd, program, cargo_output)?;
336+
// We specifically need the output to be captured, so override default
337+
let mut captured_cargo_output = cargo_output.clone();
338+
captured_cargo_output.output = OutputKind::Capture;
339+
let mut child = spawn(cmd, program, &captured_cargo_output)?;
327340

328341
let mut stdout = vec![];
329342
child
@@ -333,6 +346,7 @@ pub(crate) fn run_output(
333346
.read_to_end(&mut stdout)
334347
.unwrap();
335348

349+
// Don't care about this output, use the normal settings
336350
wait_on_child(cmd, program, &mut child, cargo_output)?;
337351

338352
Ok(stdout)
@@ -356,7 +370,11 @@ pub(crate) fn spawn(
356370
cargo_output.print_debug(&format_args!("running: {:?}", cmd));
357371

358372
let cmd = ResetStderr(cmd);
359-
let child = cmd.0.stderr(cargo_output.stdio_for_warnings()).spawn();
373+
let child = cmd
374+
.0
375+
.stderr(cargo_output.stdio_for_warnings())
376+
.stdout(cargo_output.stdio_for_output())
377+
.spawn();
360378
match child {
361379
Ok(child) => Ok(child),
362380
Err(ref e) if e.kind() == io::ErrorKind::NotFound => {

src/lib.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,25 @@ impl Object {
375375
}
376376
}
377377

378+
/// Different strategies for handling compiler output (to stdout)
379+
#[derive(Clone, Debug)]
380+
pub enum OutputKind {
381+
/// Forward the output to this process' stdout (Stdio::inherit)
382+
Forward,
383+
/// Discard the output (Stdio::null)
384+
Discard,
385+
/// Capture the result
386+
///
387+
/// Currently this is internal-only (it's just redundant with Discard as a public interface)
388+
#[doc(hidden)]
389+
Capture,
390+
/// Forward the output to this process' stderr
391+
///
392+
/// Requires Rust 1.74.0
393+
#[cfg(feature = "stdout_to_stderr")]
394+
Stderr,
395+
}
396+
378397
impl Build {
379398
/// Construct a new instance of a blank set of configuration.
380399
///
@@ -1196,6 +1215,16 @@ impl Build {
11961215
self
11971216
}
11981217

1218+
/// Define whether compiler output (to stdout) should be emitted. Defaults to `Forward`
1219+
/// (forward compiler stdout to this process' stdout)
1220+
///
1221+
/// Some compilers emit errors to stdout, so if you *really* need stdout to be clean
1222+
/// you should also set this to `Discard`.
1223+
pub fn cargo_output(&mut self, cargo_output: OutputKind) -> &mut Build {
1224+
self.cargo_output.output = cargo_output;
1225+
self
1226+
}
1227+
11991228
/// Adds a native library modifier that will be added to the
12001229
/// `rustc-link-lib=static:MODIFIERS=LIBRARY_NAME` metadata line
12011230
/// emitted for cargo if `cargo_metadata` is enabled.

src/tool.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ use std::{
55
ffi::{OsStr, OsString},
66
io::Write,
77
path::{Path, PathBuf},
8-
process::{Command, Stdio},
8+
process::Command,
99
sync::RwLock,
1010
};
1111

1212
use crate::{
1313
command_helpers::{run_output, CargoOutput},
1414
run,
1515
tempfile::NamedTempfile,
16-
Error, ErrorKind,
16+
Error, ErrorKind, OutputKind,
1717
};
1818

1919
/// Configuration used to represent an invocation of a C compiler.
@@ -158,14 +158,14 @@ impl Tool {
158158
cargo_output.print_debug(&stdout);
159159

160160
// https://gitlab.kitware.com/cmake/cmake/-/blob/69a2eeb9dff5b60f2f1e5b425002a0fd45b7cadb/Modules/CMakeDetermineCompilerId.cmake#L267-271
161-
let accepts_cl_style_flags =
162-
run(Command::new(path).arg("-?").stdout(Stdio::null()), path, &{
163-
// the errors are not errors!
164-
let mut cargo_output = cargo_output.clone();
165-
cargo_output.warnings = cargo_output.debug;
166-
cargo_output
167-
})
168-
.is_ok();
161+
let accepts_cl_style_flags = run(Command::new(path).arg("-?"), path, &{
162+
// the errors are not errors!
163+
let mut cargo_output = cargo_output.clone();
164+
cargo_output.warnings = cargo_output.debug;
165+
cargo_output.output = OutputKind::Discard;
166+
cargo_output
167+
})
168+
.is_ok();
169169

170170
let clang = stdout.contains(r#""clang""#);
171171
let gcc = stdout.contains(r#""gcc""#);
@@ -283,7 +283,7 @@ impl Tool {
283283
/// Don't push optimization arg if it conflicts with existing args.
284284
pub(crate) fn push_opt_unless_duplicate(&mut self, flag: OsString) {
285285
if self.is_duplicate_opt_arg(&flag) {
286-
println!("Info: Ignoring duplicate arg {:?}", &flag);
286+
eprintln!("Info: Ignoring duplicate arg {:?}", &flag);
287287
} else {
288288
self.push_cc_arg(flag);
289289
}

src/windows/find_tools.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ mod impl_ {
257257
impl LibraryHandle {
258258
fn new(name: &[u8]) -> Option<Self> {
259259
let handle = unsafe { LoadLibraryA(name.as_ptr() as _) };
260-
(!handle.is_null()).then(|| Self(handle))
260+
(!handle.is_null()).then_some(Self(handle))
261261
}
262262

263263
/// Get a function pointer to a function in the library.

0 commit comments

Comments
 (0)