How to determine if `clang` or `clang-cl` is used on Windows?

Lately, I started developing more on Windows and I now want to determine if I am using clang or clang-cl?

While googling I became aware of CMAKE_<LANG>_COMPILER_FRONTEND_VARIANT. However, I am not finding any documentation about it.
Is it a CMake-internal variable that should not be used by normal developers? Or is it just missing documentation?

If it is internal, is there some other established way to determine with which <mode> value (cl, gcc, g++) for the --driver-mode=<mode> option Clang was called?

I think you’re looking for CMAKE_<LANG>_SIMULATE_ID.

1 Like

Thanks, that probably really is the variable I am looking for.
(I probably overlooked it because it did not contain the COMPILER keyword.)

Is CMAKE_<LANG>_COMPILER_FRONTEND_VARIANT therefore really only an internal variable that should not be used by CMakeLists.txt writers/developers?

Yeah, it seems to be internal AFAICT.

Sadly, I realized that CMAKE_<LANG>_SIMULATE_ID is not really helpful.

Whether I use clang or clang-cl it always evaluates to MSVC.
CMAKE_<LANG>_COMPILER_FRONTEND_VARIANT on the other hand only evaluates to MSVC if using clang-cl and to GNU for clang.

So what I really need to pass options to Clang with the correct format is CMAKE_<LANG>_COMPILER_FRONTEND_VARIANT.

Is there any reason, why that variable is supposed to be a CMake-internal one?

I would suggest to officially expose it to users and to provide proper documentation to both variables, because the documentation for CMAKE_<LANG>_SIMULATE_ID seems not to reflect what that variable really shows. (It seems more as if CMAKE_<LANG>_SIMULATE_ID determines if I am calling Clang from a Visual Studio prompt but not in what driver-mode it is running.)

I created an issue (#22666) in CMake’s issue tracker that suggests to officially support CMAKE_<LANG>_COMPILER_FRONTEND_VARIANT by documenting it.

I found this, but I am not sure, if it works (I prefer to work on unix systems)
see ApprovalTests.cpp/WarningsAsErrors.cmake at master · approvals/ApprovalTests.cpp · GitHub

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_SIMULATE_ID MATCHES "MSVC")
  target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
  target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -Werror -Wshadow)

  if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 10.0)
    target_compile_options(${PROJECT_NAME} PRIVATE -Wdeprecated-copy-dtor -Wnewline-eof)
  endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
  string(REGEX REPLACE " /W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
  target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX)
endif()

No, sadly this will fail if clang or clang++ (and not clang-cl) is used on Windows (unless probably used from Cygwin/MSYS2 environment).

Is there something wrong with just checking the executable name CMAKE_<LANG>_COMPILER?

The basic CMAKE_<LANG>_COMPILER_FRONTEND_VARIANT test looks like:

        # Test whether an MSVC-like command-line option works.
        execute_process(COMMAND "${CMAKE_${lang}_COMPILER}" -?
          RESULT_VARIABLE _clang_result
          OUTPUT_VARIABLE _clang_stdout
          ERROR_VARIABLE _clang_stderr)
        if(_clang_result EQUAL 0)
          set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "MSVC")
        else()
          set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "GNU")
        endif()

You probably could test -? is usable with CheckCompilerFlag.
Or you could see what the default build flags look like to judge which frontend is being used.

If it were me I’d probably just use CMAKE_<LANG>_COMPILER_FRONTEND_VARIANT while checking that it is defined and either MSVC or GNU in case something about CMake changes. You could always propose a patch to document and test the variable.

CMAKE_<LANG>_SIMULATE_ID is telling what kind of ABI compatibility the generated code will have, whereas CMAKE_<LANG>_COMPILER_FONTEND_VARIANT describes what command line options and language extensions the compiler frontend expects.

The clang on Windows you are using has CMAKE_CXX_SIMULATE_ID = MSVC and will generate code that can link with code generated by other MSVC compilers, like Visual Studio. Since, clang's CMAKE_CXX_COMPILER_FRONTEND_VARIANT is GNU it will take the gnu-style command line options.

As you have observed, when CMAKE_CXX_COMPILER_FRONTEND_VARIANT is MSVC the compiler takes the MSVC compatible options.