cmake-rs
cmake-rs copied to clipboard
Parallel builds break when combined with cc-rs using the "parallel" feature
TL;DR - cmake-rs 0.1.49 breaks parallel builds when the build script also performs a cc-rs build with the "parallel" feature enabled.
I don't think this is a cmake-rs bug, but it's the cmake-rs behavior that isn't right, so I thought this was the right place to file the issue.
At work, we have a project that uses https://github.com/dtolnay/cxx to wrap a quite large CMake C++ library with Rust bindings. I can't share the project, but the build script looks something like
fn main() {
let cxxbridge_source_files = vec![ ... ];
cxx_build::bridges(&cxx_bridge_source_files)
.include("src/")
.flag("-std=c++11")
.compile("cxxbridge-foo");
let install_dir = cmake::Config::new("submodules/foo")
.cxxflag("-w")
.build();
println!("cargo:rustc-link-search=native={}/build/lib/", install_dir.display());
println!("cargo:rustc-link-lib=static=foo");
println!("cargo:rerun-if-changed=submodules/foo/src/");
println!("cargo:rerun-if-changed=submodules/foo/include/");
println!("cargo:rerun-if-changed=src/cpp/");
for source_file in cxxbridge_source_files {
println!("cargo:rerun-if-changed={}", source_file);
}
}
I was able to reproduce the issue with a much smaller example project here: https://github.com/Notgnoshi/cmake-jobserver-bug. I tried to use the commit history to help narrow in on the issue.
My attempt at explaining the example project
$ export MAKEFLAGS=-j16
$ cargo build -vv
...
[cmake-jobserver-bug 0.1.0] -- Build files have been written to: /home/nots/workspace/cmake-jobserver-bug/target/debug/build/cmake-jobserver-bug-00c8459a6b87808e/out/build
[cmake-jobserver-bug 0.1.0] running: "cmake" "--build" "." "--target" "install" "--config" "Debug"
[cmake-jobserver-bug 0.1.0] gmake: warning: jobserver unavailable: using -j1. Add '+' to parent make rule.
...
I see the same behavior whether I export MAKEFLAGS=-j16 or NUM_JOBS=16.
When I update the cmake-rs submodule to revert the commits
Submodule cmake-rs 07cbf8f..cfe11fc (rewind):
< Merge pull request #166 from atouchet/http
< Merge pull request #165 from thomcc/bump-version
< Use SPDX-compatible license format
< Remove support for publishing to gh-pages (docs.rs exists now)
< Update links in Cargo.toml
< Disable some targets where zlib seems to no longer compile
< use jobserver if available
the behavior changes:
$ export MAKEFLAGS=-j16
$ cargo build -vv
...
[cmake-jobserver-bug 0.1.0] -- Build files have been written to: /home/nots/workspace/cmake-jobserver-bug/target/debug/build/cmake-jobserver-bug-5d863cf04a2d52eb/out/build
[cmake-jobserver-bug 0.1.0] running: "cmake" "--build" "." "--target" "install" "--config" "Debug" "--parallel" "16"
[cmake-jobserver-bug 0.1.0] gmake: warning: -j16 forced in submake: resetting jobserver mode.
...
but I still don't think this is right - it should share the same jobserver as cc-rs and cargo instead if starting a new one for just the spdlog build.
What I think the cause is
Notice that in the Cargo.toml, there's something suspicious:
# cc is a dependency of cxx-build. The "parallel" feature is not turned on by default, but it
# significantly decreases the compile time, so we want to enable it.
# cxx-build pins the cc version, so to enable the "parallel"
# feature, we do NOT pin the version, so that we get whatever version cxx-build pinned.
cc = { version = "*", features = ["parallel"] }
We do this in our work project, because the cxx_bridge build is slow (it's a quite large project, and there's lots of files). Building in parallel made things magically better <3
If we instead do
cc = { version = "1.0", features = [] }
the spdlog parallel CMake build works as expected (I visually verified that the build was parallel by watching htop in a separate window)
$ export MAKEFLAGS=-j16
$ cargo build -vv
...
[cmake-jobserver-bug 0.1.0] -- Build files have been written to: /home/nots/workspace/cmake-jobserver-bug/target/debug/build/cmake-jobserver-bug-e634a5cc4fbc3085/out/build
[cmake-jobserver-bug 0.1.0] running: "cmake" "--build" "." "--target" "install" "--config" "Debug"
...
but the cc-rs build (and the cxx_bridge build in our work project) is no longer parallel :(
I think this points the finger at an awkward jobserver interplay between cmake-rs and cc-rs when the cc-rs "parallel" feature is enabled.
version details:
- Ubuntu 22.04
- Rust 1.65.0
- CMake 3.22.1
- GNU Make 4.3
- cmake-rs 0.1.49 (but I can reproduce as far back as 0.1.35 and probably earlier)
- cc-rs 1.0.77
I'm now convinced this is a cc-rs issue. Using binary search, I was able to narrow it down to the 1.0.42 release of cc-rs, which is the release that first included jobserver support. So I don't think this is a regression, just unexpected behavior. I'll go file a cc-rs issue shortly.