cmake-rs
cmake-rs copied to clipboard
gracefully handling of CC/CXX change
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?
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
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.
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.