203

We have a set of cross-platform CMake build scripts, and we support building with Visual C++ and GCC.

We're trying out Clang, but I can't figure out how to test whether or not the compiler is Clang with our CMake script.

What should I test to see if the compiler is Clang or not? We're currently using MSVC and CMAKE_COMPILER_IS_GNU<LANG> to test for Visual C++ and GCC, respectively.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
leedm777
  • 23,444
  • 10
  • 58
  • 87
  • 1
    You can set compiler by setting CMAKE_C_COMPILER and CMAKE_CXX_COMPILER to path to clang or clang++. +1 for clang. – Zaffy Apr 06 '12 at 19:15
  • Why should you care? Clang is very GCC like, in terms of accepted compiler options ... – Basile Starynkevitch Jan 04 '15 at 18:27
  • 2
    @BasileStarynkevitch Since we supported MSVC, we needed to detect Clang so we knew whether to turn on the GCC-like options, or the MSVC-like options. It's been too long for me to remember, but it's also certainly possible we were using options not supported by Clang as well. – leedm777 Jan 05 '15 at 14:39
  • 2
    @BasileStarynkevitch - Clang pretends to be both `__GNUC__` and `_MSC_VER`, but it can't consume the same programs as either compiler. Detecting LLVM Clang and Apple Clang is crucial to ensuring the code compiles and executes as expected. I'm so tired of dealing with Clang's BS we just [break the compile on Windows](http://github.com/weidai11/cryptopp/issues/147#issuecomment-227747846). We've adopted the policy of let users complain to LLVM so the Clang devs change their behavior. Also see [How to tell Clang to stop pretending to be other compilers?](http://stackoverflow.com/q/38499462) – jww Sep 13 '16 at 16:29

5 Answers5

327

A reliable check is to use the CMAKE_<LANG>_COMPILER_ID variables. E.g., to check the C++ compiler:

if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
  # using Clang
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
  # using GCC
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
  # using Intel C++
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
  # using Visual Studio C++
endif()

These also work correctly if a compiler wrapper like ccache is used.

As of CMake 3.0.0 the CMAKE_<LANG>_COMPILER_ID value for Apple-provided Clang is now AppleClang. To test for both the Apple-provided Clang and the regular Clang use the following if condition:

if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  # using regular Clang or AppleClang
endif()

Also see the AppleClang policy description.

CMake 3.15 has added support for both the clang-cl and the regular clang front end. You can determine the front end variant by inspecting the variable CMAKE_<LANG>_COMPILER_FRONTEND_VARIANT:

if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
  if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
    # using clang with clang-cl front end
  elseif (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
    # using clang with regular front end
  endif()
endif()
starball
  • 20,030
  • 7
  • 43
  • 238
sakra
  • 62,199
  • 16
  • 168
  • 151
  • The [cmake documentation](http://www.cmake.org/cmake/help/cmake-2-8-docs.html#variable:CMAKE_LANG_COMPILER_ID) states "This is used in determining the compiler and is subject to change". Otherwise, it would be perfect :-( – leedm777 Apr 07 '12 at 15:19
  • It's probably not a good idea to use the `CMAKE_CXX_COMPILER_ARG1` based solution, either. This one does not seem to be documented at all. – sakra Apr 07 '12 at 16:12
  • 18
    As of CMake 2.8.10, this variable is (finally!) documented. See: http://www.cmake.org/cmake/help/v2.8.10/cmake.html#variable:CMAKE_LANG_COMPILER_ID – Nick Hutchinson Nov 19 '12 at 01:07
  • +1, this is what we used 5-6 years as well in here: https://projects.kde.org/projects/playground/games/gluon/repository/revisions/master/entry/CMakeLists.txt#L41 – László Papp Dec 12 '13 at 12:42
  • 14
    Note that the `CMAKE_CXX_COMPILER_ID` variable is only available after the command `project(Foo CXX)`. – waldyrious Jun 01 '16 at 18:28
  • 6
    And for flags that both gcc and clang accept, I use `if (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") ... endif()` – Fred Schoen Jun 07 '17 at 07:59
  • 5
    If you are confused why you cannot detect `AppleClang` specifically, @sakra indicates that [`cmake 3.0.0` released `AppleClang`](https://cmake.org/Wiki/CMake/ChangeLog). However, just because `cmake --version` reports equal to or higher is not enough -- you have to `cmake_minimum_required(VERSION 3.0.0)` in order for the `3.0.0` standards to be used! – svenevs Jun 09 '17 at 00:56
  • Time to add 3.0.0/AppleClang to the main code snippet. – Victor Sergienko Oct 25 '17 at 19:54
  • I had to drop the double quotes around `Clang` to make this work. ¯\_(ツ)_/¯ – lionello May 03 '20 at 23:53
7

This is a slightly more detailed answer for cmake newbies, modified from sakra's answer. The minimum version of 3.1 seems to be important as it changes the way CMake processes the quoted "MSVC" string (according to policy CMP0054).

cmake_minimum_required(VERSION 3.1)
project(MyProject CXX)

if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
  MESSAGE("Clang")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
  MESSAGE("GNU")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
  MESSAGE("Intel")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
  MESSAGE("MSVC")
endif()
Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
Searene
  • 25,920
  • 39
  • 129
  • 186
3

If your cmake_minimum_required VERSION is less than 3.1, then you have to use quoted variable to determine compiler, if together with STREQUAL command, i.e.

if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
  MESSAGE("MSVC")
endif()

Or, if you don't like quoted stuff, you can use MATCHES command:

if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
  MESSAGE("MSVC")
endif()

And if you specify cmake_minimum_required VERSION >= 3.1, then you can happily use STREQUAL without quotes:

if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
  MESSAGE("MSVC")
endif()

the cmake 3.1 version issue, is documented here: https://cmake.org/cmake/help/latest/policy/CMP0054.html

ChrisZZ
  • 1,521
  • 2
  • 17
  • 24
2

Just to avoid any misspelling problem, I am using Case-insensitive compare, like:

string( TOLOWER "${CMAKE_CXX_COMPILER_ID}" COMPILER_ID )
if (COMPILER_ID STREQUAL "clang")
    set(IS_CLANG_BUILD true)
else ()
    set(IS_CLANG_BUILD false)
endif ()

For making the regex of MATCHES case-insensitive, I tried everything here without success (doesn't seem to be supported in CMake).

Top-Master
  • 7,611
  • 5
  • 39
  • 71
Antonio
  • 19,451
  • 13
  • 99
  • 197
  • indeed, as today, case insensitive matching it is not possible https://cmake.org/pipermail/cmake/2017-May/065432.html – fferri Dec 08 '17 at 18:02
2

You can test for Clang and it's frontends like this:

if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
  if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") # clang-cl
    # ...
  elseif (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU") # clang native
    # ...
  endif()
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") # both
    # ...
endif()

CMAKE_CXX_COMPILER_FRONTEND_VARIANT requires CMake v3.14+.

Jens A. Koch
  • 39,862
  • 13
  • 113
  • 141