Як у CMake я можу перевірити, чи є компілятором Clang?


151

У нас є набір сценаріїв побудови міжплатформних CMake , і ми підтримуємо побудову за допомогою Visual C ++ та GCC .

Ми пробуємо Clang , але я не можу зрозуміти, як перевірити, чи є компілятор Clang за допомогою нашого сценарію CMake.

Що слід перевірити, чи є компілятор Clang чи ні? Наразі ми використовуємо MSVCта CMAKE_COMPILER_IS_GNU<LANG>тестуємо Visual C ++ та GCC відповідно.


Ви можете встановити компілятор, встановивши CMAKE_C_COMPILER і CMAKE_CXX_COMPILER для шляху до кланг або кланг ++. +1 для кланг.
Заффі

Чому ти повинен дбати? Clang дуже GCC, як з точки зору прийнятих варіантів компілятора ...
Basile Starynkevitch

2
@BasileStarynkevitch Оскільки ми підтримували MSVC, нам потрібно було виявити Clang, щоб ми знали, чи вмикати параметри, схожі на GCC, або варіанти, подібні MSVC. Мені вже давно запам'ятовується, але, безумовно, можливо, що ми використовували варіанти, які також не підтримує Кланг.
leedm777

1
@BasileStarynkevitch - Clang претендує на те, що є обом __GNUC__і _MSC_VER, але він не може споживати ті самі програми, що і будь-який компілятор. Виявлення LLVM Clang та Apple Clang має вирішальне значення для забезпечення компіляції та виконання коду, як очікувалося. Мені набридло мати справу з BS Кланг, що ми просто порушуємо компіляцію в Windows . Ми прийняли політику дозволу користувачам скаржитися на LLVM, щоб Clang devs змінив свою поведінку. Також див. Як сказати Клангу, щоб він не прикидався іншими компіляторами?
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для Apple додається Clang AppleClang. Щоб перевірити як доданий Apple, так і звичайний Clang, використовуйте наступне, якщо це умова:

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

Також дивіться опис політики AppleClang .

CMake 3.15 додав підтримку як для clang-cl, так і для звичайного переднього торця. Ви можете визначити варіант переднього кінця, перевіривши змінну 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()

Документація 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()
Fred Schoen

4
Якщо вас бентежить, чому ви не можете виявити AppleClangконкретно, @sakra вказує, що cmake 3.0.0випущеноAppleClang . Однак лише тому, що cmake --versionзвітів, рівних або вище, недостатньо - вам потрібно для cmake_minimum_required(VERSION 3.0.0)того, щоб використовувати 3.0.0стандарти!
svenevs

2

Вихідний код двигуна OGRE 3D використовує таку перевірку :

if (CMAKE_CXX_COMPILER MATCHES ".*clang")
    set(CMAKE_COMPILER_IS_CLANGXX 1)
endif ()

3
Це близько, але не працює, коли ви використовуєте ccache (тобто export CXX="ccache clang++")
leedm777

4
Досить близько, я вам його віддам. Раніше я if ("${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" MATCHES ".*clang")працював із справою кеша.
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).


Дійсно, як сьогодні, невідчутне відношення до справ не можливо cmake.org/pipermail/cmake/2017-May/065432.html
fferri

-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
...
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.