From 875cf7249352f60626a89c3220c82216ae47fdb1 Mon Sep 17 00:00:00 2001 From: Kesavan Yogeswaran Date: Fri, 27 Dec 2024 01:34:14 -0500 Subject: [PATCH 1/2] Disable legacy Make jobserver support on OSX On OSX, CMake (via libuv) spawns child processes, including make, via the Apple-specific `posix_spawn` attribute `POSIX_SPAWN_CLOEXEC_DEFAULT`. This blocks make from accessing all non-stdio file descriptors from the parent process, including those of the jobserver. Because make was getting passed jobserver information via MAKEFLAGS but was unable to access the jobserver, it prints an error like the following and proceeds to run a single-threaded build: ``` make: warning: jobserver unavailable: using -j1. Add '+' to parent make rule. ``` As a workaround, disable jobserver support on OSX so that cmake-rs instead passes `--parallel $NUM_JOBS` to CMake, allowing for a faster multi-threaded build. However, there is an exception made if the available jobserver is based on a named pipe. Since access to this pipe does not rely on the inheritance of file descriptors, the underlying build will be able to access the jobserver in this case. --- src/lib.rs | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 35ce4cb..e99b4ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -837,16 +837,22 @@ impl Config { let mut use_jobserver = false; if fs::metadata(build.join("Makefile")).is_ok() { match env::var_os("CARGO_MAKEFLAGS") { - // Only do this on non-windows and non-bsd - // On Windows, we could be invoking make instead of - // mingw32-make which doesn't work with our jobserver - // bsdmake also does not work with our job server + // Only do this on non-windows, non-bsd, and non-macos (unless a named pipe + // jobserver is available) + // * On Windows, we could be invoking make instead of + // mingw32-make which doesn't work with our jobserver + // * bsdmake also does not work with our job server + // * On macOS, CMake blocks propagation of the jobserver's file descriptors to make + // However, if the jobserver is based on a named pipe, this will be available to + // the build. Some(ref makeflags) if !(cfg!(windows) || cfg!(target_os = "openbsd") || cfg!(target_os = "netbsd") || cfg!(target_os = "freebsd") - || cfg!(target_os = "dragonfly")) => + || cfg!(target_os = "dragonfly") + || (cfg!(target_os = "macos") + && !uses_named_pipe_jobserver(makeflags))) => { use_jobserver = true; cmd.env("MAKEFLAGS", makeflags); @@ -1115,8 +1121,20 @@ fn fail(s: &str) -> ! { panic!("\n{}\n\nbuild script failed, must exit now", s) } +/// Returns whether the given MAKEFLAGS indicate that there is an available +/// jobserver that uses a named pipe (fifo) +fn uses_named_pipe_jobserver(makeflags: &OsStr) -> bool { + makeflags + .to_str() + // auth option as defined in + // https://www.gnu.org/software/make/manual/html_node/POSIX-Jobserver.html#POSIX-Jobserver + .map(|flags| flags.contains("--jobserver-auth=fifo:")) + .unwrap_or(false) +} + #[cfg(test)] mod tests { + use super::uses_named_pipe_jobserver; use super::Version; #[test] @@ -1132,4 +1150,14 @@ CMake suite maintained and supported by Kitware (kitware.com/cmake). let _v = Version::from_command("cmake".as_ref()).unwrap(); } + + #[test] + fn test_uses_fifo_jobserver() { + assert!(uses_named_pipe_jobserver( + "-j --jobserver-auth=fifo:/foo".as_ref() + )); + assert!(!uses_named_pipe_jobserver( + "-j --jobserver-auth=8:9".as_ref() + )); + } } From 959d8c6258f1b33728d3828fbd6e6bc8f6a0c6ca Mon Sep 17 00:00:00 2001 From: Kesavan Yogeswaran Date: Sun, 29 Dec 2024 07:12:33 -0500 Subject: [PATCH 2/2] Use to_string_lossy in uses_named_pipe_jobserver This allows a fifo path to contain non-utf8 characters Co-authored-by: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> --- src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e99b4ad..a569184 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1125,11 +1125,10 @@ fn fail(s: &str) -> ! { /// jobserver that uses a named pipe (fifo) fn uses_named_pipe_jobserver(makeflags: &OsStr) -> bool { makeflags - .to_str() + .to_string_lossy() // auth option as defined in // https://www.gnu.org/software/make/manual/html_node/POSIX-Jobserver.html#POSIX-Jobserver - .map(|flags| flags.contains("--jobserver-auth=fifo:")) - .unwrap_or(false) + .contains("--jobserver-auth=fifo:") } #[cfg(test)]