cmake-rs icon indicating copy to clipboard operation
cmake-rs copied to clipboard

gracefully handling of CC/CXX change

Open Dushistov opened this issue 4 years ago • 3 comments

I use something like this in my build.rs:

    let dst = cmake::Config::new(Path::new("couchbase-lite-core"))
        .define("DISABLE_LTO_BUILD", "True")
        .define("MAINTAINER_MODE", "False")
        .define("ENABLE_TESTING", "False")
        .build_target("all")
        .build()
        .join("build");

all fine, until user changed CC/CXX environment variable and force rebuild with already cached cmake build, then:

cmake ...
-- Configuring done
You have changed variables that require your cache to be deleted.
Configure will be re-run and you may have to reset some variables.

and all my settings is gone, like DISABLE_LTO_BUILD, MAINTAINER_MODE etc.

Can cmake-rs detect if CC/CXX changed and rerun cmake twice? So on the second time it get proper values of variables?

Dushistov avatar May 31 '20 16:05 Dushistov

Do you mean you're running cmake out of band (i.e. by hand)?

The build.rs script might not even be invoked again. Have you tried emitting rerun-if?

aloucks avatar May 31 '20 17:05 aloucks

@aloucks

Do you mean you're running cmake out of band (i.e. by hand)?

I always run cmake via cmake-rs, the log that I provided in the first post I get via RUST_LOG=cmake=trace cargo build

The build.rs script might not even be invoked again. Have you tried emitting rerun-if?

Not sure what you mean, let me rephase problem again. I publish my foo-sys crate that uses cmake-rs. It contains:

    println!("cargo:rerun-if-env-changed=CC");
    println!("cargo:rerun-if-env-changed=CXX");

User build it via cargo build once, then user decide to change compiler and run build like this:

CC=clang CXX=clang++ cargo build

All recompiled fine, but in fact resulted foo library was bad, because of all options that I set via build.rs were missed.

If represent problem as sequence of shell commands:

$ CC=gcc CXX=g++ cargo build
$ grep DISABLE_LTO_BUILD target/debug/build/foo-sys-e0d8523e5679fc5c/out/build/CMakeCache.txt
DISABLE_LTO_BUILD:BOOL=True
$ CC=clang CXX=clang++ cargo build
$ grep DISABLE_LTO_BUILD target/debug/build/foo-sys-e0d8523e5679fc5c/out/build/CMakeCache.txt
DISABLE_LTO_BUILD:BOOL=False

as you see DISABLE_LTO_BUILD is resetted into default False value, while build.rs set it True, according to cmake-rs + log + env_logger, the cmake reset cached variables after compiler change, but cmake-rs does not take this into consideration.

Alternatively you can run cmake -DDISABLE_LTO_BUILD=True manually, but got DISABLE_LTO_BUILD=False in CMakeCache.txt, because of if cmake find out that compiler changed it resetted it's state.

Dushistov avatar May 31 '20 20:05 Dushistov

I have been recently hit by this issue. This issue is especially annoying in the cross compilation situation, as targets (and thus toolchain files) may change at any time. In the worst case, the cmake build itself finishes but artifacts are located in wrong locations so the final linkage step will fail, and the only reasonable remedy would be cargo clean.

To my knowledge this is an explicit design decision from CMake's part (which I strongly disagrees), and any users of cmake-rs currently have to work around this issue to ensure the correct build:

  • Mangle the output directory or cache file path so that different targets and defines do not affect each other.
  • Alternatively, put as many defines and options as possible into a toolchain file. The normal -DCMAKE_TOOLCHAIN_FILE will be lost on reconfiguration, but I think the environment variable is retained and reread after the cache got reset.
  • One can also just configure or run the build twice, if this wouldn't result in any side effect.

Future versions of cmake-rs may also implement some of these workarounds as a reasonable default.

lifthrasiir avatar Jun 07 '23 08:06 lifthrasiir