Not setting -fms-compatibility-version= when -fno-ms-compatibility is set

I’m trying to use Clang to cross-compile runtimes for Fuchsia on Windows. The problem I’m hitting is that CMake checks the existence of MSC_VER macro, and if set it detects the compiler as “Clang with GNU-like command line” which is a special mode in which CMake treats clang as clang-cl. This breaks cross-compilation for runtimes because CMake no longer passes --target= flag even if CMAKE*_COMPILER_TARGET is set, etc. because of this logic: https://github.com/Kitware/CMake/blob/master/Modules/Compiler/Clang.cmake#L13

This is IMHO a bug in CMake: it shouldn’t blindly assume that Clang is clang-cl without first consulting other variables like CMAKE_*_COMPILER_TARGET or CMAKE_SYSTEM_NAME, but I’m not sure how easy or difficult would it be to change CMake, and even then we would have a problem with rolling out new CMake version everywhere.

So instead, I’m hoping to bypass CMake’s detection and force it to treat Clang as clang (note that this is only for the purpose of cross-compilation) and to do so I need to unset _MSC_VER. Looking at the driver code, it seems like _MSC_VER is only defined if -fms-compatibility-version is set. I was hoping that setting -fno-ms-compatibility would do the trick, but it doesn’t because -fms-compatibility-version is set independently of -f[no]-ms-compatibility: https://github.com/llvm/llvm-project/blob/69bf40c45fd7f6dfe11b47de42571d8bff5ef94f/clang/lib/Driver/ToolChains/Clang.cpp#L5395. When MSVC target is the default driver, -fms-compatibility-version is going to be set because https://github.com/llvm/llvm-project/blob/69bf40c45fd7f6dfe11b47de42571d8bff5ef94f/clang/lib/Driver/ToolChains/MSVC.cpp#L1320 returns a non-empty string, and AFAICT there’s no way to disable it, which doesn’t match the documentation: https://github.com/llvm/llvm-project/blob/69bf40c45fd7f6dfe11b47de42571d8bff5ef94f/clang/include/clang/Driver/Options.td#L1362

Does anyone know if this is intentional or just a bug? Would it make sense to change the driver to avoid setting -fms-compatibility-version when -fno-ms-compatibility is set?

This sounds like an issue with how CMake does compiler identification in mode advanced setups; I've often run into issues where I'd like to configure with something like CMAKE_C_COMPILER=clang CMAKE_C_FLAGS="-target <other-system-tuple>", but it first does all the compiler identification steps only with ${CMAKE_C_COMPILER} in isolation. This is much more straightforward with GCC like cross compilers, where one would have CMAKE_C_COMPILER=<other-system-tuple>-gcc. For that case iirc I managed it to behave correctly by using CMAKE_C_FLAGS_INIT="-target <other-system-tuple>", which ensures that the flag is used along with CMAKE_C_COMPILER even for the very first compiler identification steps.

However, I'm not very proficient with CMake, I'm just fumblingly trying to make things work for me.

// Martin

Passing --target= through CMAKE_FLAGS works, but it defeats the point of using CMAKE_COMPILER_TARGET, which feels more idiomatic.

After reading a bit more through CMake internals, I think I can workaround this by setting:

set(CMAKE_C_COMPILER_ID_RUN OFF)
set(CMAKE_CXX_COMPILER_ID_RUN OFF)
set(CMAKE_C_COMPILER_ID Clang)
set(CMAKE_CXX_COMPILER_ID Clang)

in the runtimes build, and then set:

set(CMAKE_C_SIMULATE_ID MSVC)
set(CMAKE_CXX_SIMULATE_ID MSVC)

when targeting *-pc-windows-msvc with Clang.