-
Notifications
You must be signed in to change notification settings - Fork 148
Description
The problem
I use CMake toolchain files a lot, and this package interacts badly with a certain way of using CMake toolchain files. I have a proposed fix, but I want to get people's feedback on if it should be turned into a PR.
Toolchain files with essential compiler flags
I would like Rust to select the C and C++ compiler via a toolchain file, e.g.
CMAKE_TOOLCHAIN_FILE=$HOME/share/cmake-toolchains/musl-clang19-x64v4-libstdcxx.cmake cargo buildHere is what a toolchain file like this does:
set(CMAKE_C_COMPILER /usr/lib/llvm/19/bin/clang)
set(CMAKE_CXX_COMPILER /usr/lib/llvm/19/bin/clang++)
set(CMAKE_ASM_FLAGS_INIT -march=x86-64-v4)
set(CMAKE_C_FLAGS_INIT "-march=x86-64-v4 --gcc-toolchain=/opt/gnu/gcc-15.2 --target=x86_64-pc-linux-musl")
set(CMAKE_CXX_FLAGS_INIT "-march=x86-64-v4 -stdlib=libstdc++ --gcc-toolchain=/opt/gnu/gcc-15.2 --target=x86_64-pc-linux-musl")Note the setting of the CMAKE_<LANG>_FLAGS_INIT variables. Because this clang19 uses a non-system gcc (to pick up its newer standard library), and also a musl libc, the compiler invocation always needs special C and C++ flags to function correctly.
Inconsistent behavior between CMake CFLAGS environment expansion and -DCMAKE_C_FLAGS
CMake does something odd here.
If you were to specify additional, project-wide C flags via an environment variable (i.e., CFLAGS), CMake would merge the values of CMAKE_C_FLAGS_INIT and the CFLAGS environment variable. This is (I think) almost always what you want: the _INIT value still provides the essential parameters for the toolchain to operate, but you let people inject top-level override stuff too.
However, if you use instead pass -DCMAKE_C_FLAGS via a command line, this will completely overwrite the flags in CMAKE_C_FLAGS_INIT, and the toolchain will no longer function correctly.
I think perhaps the no_default_flags feature was added to fix this problem but there are two issues with it:
- It doesn't actually work (it removes most of the flags but somewhere else, it still injects a
-wand overwrites the toolchain's flags) - Perhaps I want to keep whatever cc-rs thinks are good default flags; I just want my
CMAKE_C_FLAGS_INITstuff too
Potential solution
An easy way to fix this would be to allow the user (via a configuration option) to choose to pass compiler flags via environment variables instead of command line parameters, which has better mergeability behavior inside CMake. Perhaps it could even be configurable in the following way:
- I want to use
CMAKE_C_FLAGS - I want to use default
CFLAGSas a passing mechanism, but containing only the values as determined by thecc-rspackage - I want to do the above, and
${CFLAGS}is a union of the values computed bycc-rspackage plus the value thatCFLAGShas in the calling environment
The ugly workaround I am using now
In case someone stumbles upon this issue and is desperate to fix their problem, here is a workaround that works right now. Add the following to your Rust CMake build configuration:
.configure_arg("-UCMAKE_ASM_FLAGS")
.configure_arg("-UCMAKE_C_FLAGS")
.configure_arg("-UCMAKE_CXX_FLAGS")
Undefining these value on the command line after they are defined somehow by cmake-rs will cause CMake to ignore them, preserving the intended value from the toolchain file.