В CMake, как я могу проверить, является ли компилятор Clang?

151

У нас есть набор межплатформенных сценариев сборки CMake , и мы поддерживаем сборку с помощью Visual C ++ и GCC .

Мы пробуем Clang , но я не могу понять, как проверить, является ли компилятор Clang с нашим сценарием CMake.

Что я должен проверить, чтобы увидеть, является ли компилятор Clang или нет? В настоящее время мы используем MSVCи CMAKE_COMPILER_IS_GNU<LANG>для тестирования Visual C ++ и GCC, соответственно.

leedm777
источник
Вы можете установить компилятор, установив для CMAKE_C_COMPILER и CMAKE_CXX_COMPILER путь к clang или clang ++. +1 за лязг
Zaffy
Почему ты должен заботиться? Clang очень похож на GCC, с точки зрения допустимых опций компилятора ...
Basile Starynkevitch
2
@BasileStarynkevitch Так как мы поддерживали MSVC, нам нужно было обнаружить Clang, чтобы мы знали, включать ли опции, подобные GCC, или опции, подобные MSVC. Это было слишком долго для меня, чтобы помнить, но также возможно, что мы использовали опции, не поддерживаемые Clang.
leedm777
1
@BasileStarynkevitch - Clang притворяется и тем __GNUC__и другим _MSC_VER, но он не может использовать те же программы, что и любой компилятор. Обнаружение LLVM Clang и Apple Clang имеет решающее значение для обеспечения того, чтобы код компилировался и выполнялся как ожидалось. Я так устал от работы с BS Clang, что мы просто ломаем компиляцию на Windows . Мы приняли политику разрешать пользователям жаловаться в LLVM, чтобы разработчики Clang меняли свое поведение. Также смотрите Как сказать Clang перестать притворяться другими компиляторами?
jww

Ответы:

242

Надежной проверкой является использование CMAKE_<LANG>_COMPILER_IDпеременных. Например, чтобы проверить компилятор C ++:

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()

Они также работают правильно, если используется оболочка компилятора, такая как ccache .

Начиная с CMake 3.0.0 CMAKE_<LANG>_COMPILER_IDзначение для Clang, предоставляемого Apple, теперь AppleClang. Чтобы проверить и Clang, предоставленный Apple, и обычный Clang, используйте следующее условие if:

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

Также см. Описание политики AppleClang .

В CMake 3.15 добавлена ​​поддержка как clang-cl, так и обычного внешнего интерфейса clang. Вы можете определить интерфейсный вариант, проверив переменную CMAKE_CXX_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()
Sakra
источник
Документация cmake гласит: «Это используется при определении компилятора и может быть изменено». Иначе было бы идеально :-(
leedm777
17
Начиная с CMake 2.8.10, эта переменная (наконец-то!) Задокументирована. См .: cmake.org/cmake/help/v2.8.10/…
Ник Хатчинсон
9
Обратите внимание, что CMAKE_CXX_COMPILER_IDпеременная доступна только после команды project(Foo CXX).
Waldyrious
5
И для флагов, которые принимают и gcc, и clang, я используюif (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") ... endif()
Фред Шоен
4
Если вы не понимаете, почему не можете обнаружить AppleClangконкретно, @sakra указывает, что cmake 3.0.0выпущеноAppleClang . Однако, просто потому, что cmake --versionотчеты равны или выше, недостаточно - вы должны cmake_minimum_required(VERSION 3.0.0)использовать 3.0.0стандарты!
Свеневс
2

Исходный код движка OGRE 3D использует следующую проверку :

if (CMAKE_CXX_COMPILER MATCHES ".*clang")
    set(CMAKE_COMPILER_IS_CLANGXX 1)
endif ()
arrowd
источник
3
Это близко, но не работает, когда вы используете ccache (т.е. export CXX="ccache clang++")
leedm777
4
Достаточно близко, я дам тебе. Я имел обыкновение if ("${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" MATCHES ".*clang")обращаться с делом ccache.
leedm777
1
Это не работает для меня, как ${CMAKE_CXX_COMPILER} == /Library/Developer/CommandLineTools/usr/bin/c++. Принятый ответ работает.
Фред Шоен
1

Просто, чтобы избежать ошибок, я использую сравнение без учета регистра, например:

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 ()

Для создания регулярного выражения без учета MATCHESрегистра я попробовал все здесь безуспешно (похоже, не поддерживается в CMake).

Антонио
источник
действительно, как и сегодня, сопоставление без учета
регистра
-2

Это немного более подробный ответ для новичков cmake, модифицированный из ответа Сакры, просто добавьте следующие строки CMakeLists.txt:

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()

Затем запустите cmake .в папке, где лежит CMakeLists.txt. Затем вы увидите кучу результатов вместе с вашим ответом.

...
-- Detecting CXX compile features
-- Detecting CXX compile features - done
GNU
-- Configuring done
-- Generating done
...
Searene
источник