Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parallel builds break when combined with cc-rs using the "parallel" feature #172

Open
Notgnoshi opened this issue Dec 1, 2022 · 1 comment

Comments

@Notgnoshi
Copy link

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
@Notgnoshi Notgnoshi changed the title cmake-rs 0.1.49 breaks parallel builds when combined with cc-rs with the "parallel" feature Parallel builds break when combined with cc-rs with the "parallel" feature Dec 1, 2022
@Notgnoshi Notgnoshi changed the title Parallel builds break when combined with cc-rs with the "parallel" feature Parallel builds break when combined with cc-rs using the "parallel" feature Dec 1, 2022
@Notgnoshi
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant