Skip to content

Commit

Permalink
Disable broken Make jobserver support on OSX to fix parallel builds (#…
Browse files Browse the repository at this point in the history
…229)

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.
  • Loading branch information
kesyog authored Jan 27, 2025
1 parent 94da9de commit 9e1fce1
Showing 1 changed file with 32 additions and 5 deletions.
37 changes: 32 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -1115,8 +1121,19 @@ 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_string_lossy()
// auth option as defined in
// https://www.gnu.org/software/make/manual/html_node/POSIX-Jobserver.html#POSIX-Jobserver
.contains("--jobserver-auth=fifo:")
}

#[cfg(test)]
mod tests {
use super::uses_named_pipe_jobserver;
use super::Version;

#[test]
Expand All @@ -1132,4 +1149,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()
));
}
}

0 comments on commit 9e1fce1

Please sign in to comment.