CMake -Werror flag removal logic may break ABI detection

CMake compiles a temporary C program to detect values for CMAKE_SIZEOF_VOID_P and other variables.

I have a toolchain file that defined the linker flag -pie for executable targets and for the temporary program to compile and set CMAKE_SIZEOF_VOID_P correctly it requires the compiler flags -fPIC or -fPIE.
But if I put -fPIC immediately after -Werror in CMAKE_C_FLAGS in the toolchain file then it would have no effect on the temporary program. It would simply get removed along with -Werror thus causing the temporary program fails to compile and CMAKE_SIZEOF_VOID_P left unset.

The minimum reproducible example:

# CMakeLists.txt
cmake_minimum_required(VERSION 3.14.1)
# toolchain.cmake
set(CMAKE_C_FLAGS "-Werror -fPIC")

By executing cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake . with CMake 3.20.5 I get the following output which shows that CMAKE_SIZEOF_VOID_P is unset:


I expect the following output on my 64 bit machine as a lower version of CMake (such as CMake 3.16.5) would correctly output:


I believe the problem is introduced by the following change to “Handle NVCC-style -Werror flags” which was first released in CMake 3.19 or so. While handling the “NVCC-style flags” it also erroneously removes other unrelated flags which can cause problems.

I fixed it by setting -Werror as the last flag of CMAKE_C_FLAGS so no flags will be removed along with it but it is rather hackish. I hope that CMake could do a better job at handling -Werror removal possibly by modifying the regular expression to treat flags immediately after -Werror that start with a - differently so that they aren’t mistaken as NVCC Werror arguments and therefore not removed incorrectly.

This indeed sounds like a regression. Could you please file an issue?

Cc: @brad.king @tambre

Surprising this went unnoticed for so long.