diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index d3605cd3dce05..105b3e2ed2239 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -10,6 +10,7 @@ similar = "2.5.0" wasmparser = { version = "0.216", default-features = false, features = ["std"] } regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace gimli = "0.31.0" +libc = "0.2" build_helper = { path = "../build_helper" } serde_json = "1.0" libc = "0.2" diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index 6b58173b34304..ee900d3cac484 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -151,6 +151,31 @@ impl Command { self } + /// Set an auxiliary stream passed to the process, besides the stdio streams. + #[cfg(unix)] + pub fn set_aux_fd>( + &mut self, + newfd: std::os::fd::RawFd, + fd: F, + ) -> &mut Self { + use std::os::fd::AsRawFd; + use std::os::unix::process::CommandExt; + + let fd = fd.into(); + unsafe { + self.cmd.pre_exec(move || { + let fd = fd.as_raw_fd(); + let ret = if fd == newfd { + libc::fcntl(fd, libc::F_SETFD, 0) + } else { + libc::dup2(fd, newfd) + }; + if ret == -1 { Err(std::io::Error::last_os_error()) } else { Ok(()) } + }); + } + self + } + /// Run the constructed command and assert that it is successfully run. /// /// By default, std{in,out,err} are [`Stdio::piped()`]. diff --git a/src/tools/run-make-support/src/macros.rs b/src/tools/run-make-support/src/macros.rs index f7fe4f5422399..322ee5314e239 100644 --- a/src/tools/run-make-support/src/macros.rs +++ b/src/tools/run-make-support/src/macros.rs @@ -80,6 +80,17 @@ macro_rules! impl_common_helpers { self } + /// Set an auxiliary stream passed to the process, besides the stdio streams. + #[cfg(unix)] + pub fn set_aux_fd>( + &mut self, + newfd: std::os::fd::RawFd, + fd: F, + ) -> &mut Self { + self.cmd.set_aux_fd(newfd, fd); + self + } + /// Run the constructed command and assert that it is successfully run. #[track_caller] pub fn run(&mut self) -> crate::command::CompletedProcess { diff --git a/tests/run-make/jobserver-error/rmake.rs b/tests/run-make/jobserver-error/rmake.rs index a17add2d81fb8..c18c226285740 100644 --- a/tests/run-make/jobserver-error/rmake.rs +++ b/tests/run-make/jobserver-error/rmake.rs @@ -19,22 +19,24 @@ fn main() { .run_fail() .stderr_utf8(); diff().expected_file("cannot_open_fd.stderr").actual_text("actual", out).run(); - // FIXME(Oneirical): Find how to use file descriptor "3" with run-make-support - // and pipe /dev/null into it. - // Original lines: - // - // bash -c 'echo "fn main() {}" | makeflags="--jobserver-auth=3,3" $(rustc) - 3&1 | diff not_a_pipe.stderr - + + let out = rustc() + .stdin("fn main() {}") + .input("-") + .env("MAKEFLAGS", "--jobserver-auth=3,3") + .set_aux_fd(3, std::fs::File::open("/dev/null").unwrap()) + .run() + .stderr_utf8(); + diff().expected_file("not_a_pipe.stderr").actual_text("actual", out).run(); + // # this test randomly fails, see https://github.com/rust-lang/rust/issues/110321 - // disabled: - // bash -c 'echo "fn main() {}" | makeflags="--jobserver-auth=3,3" $(rustc) - \ - // 3< <(cat /dev/null)' 2>&1 | diff poisoned_pipe.stderr - - // + // let (readpipe, _) = std::pipe::pipe().unwrap(); // let out = rustc() // .stdin("fn main() {}") // .input("-") - // .env("MAKEFLAGS", "--jobserver-auth=0,0") + // .env("MAKEFLAGS", "--jobserver-auth=3,3") + // .set_fd3(readpipe) // .run() // .stderr_utf8(); - // diff().expected_file("not_a_pipe.stderr").actual_text("actual", out).run(); + // diff().expected_file("poisoned_pipe.stderr").actual_text("actual", out).run(); }