W CMake, jak mogę sprawdzić, czy kompilatorem jest Clang?

151

Mamy zestaw wieloplatformowych skryptów kompilacji CMake i wspieramy budowanie za pomocą Visual C ++ i GCC .

Próbujemy Clang , ale nie mogę dowiedzieć się, jak sprawdzić, czy kompilator jest Clang z naszym skryptem CMake.

Co powinienem przetestować, aby sprawdzić, czy kompilator jest Clang, czy nie? Obecnie używamy MSVCi CMAKE_COMPILER_IS_GNU<LANG>do testowania odpowiednio dla Visual C ++ i GCC.

leedm777
źródło
Możesz ustawić kompilator, ustawiając CMAKE_C_COMPILER i CMAKE_CXX_COMPILER na ścieżkę do clang lub clang ++. +1 za brzęk.
Zaffy,
Dlaczego powinno Cię to obchodzić? Clang jest bardzo podobny do GCC pod względem akceptowanych opcji kompilatora ...
Basile Starynkevitch
2
@BasileStarynkevitch Ponieważ wspieraliśmy MSVC, musieliśmy wykryć Clang, więc wiedzieliśmy, czy włączyć opcje podobne do GCC, czy opcje podobne do MSVC. Za dużo czasu nie pamiętałem, ale z pewnością możliwe, że korzystaliśmy z opcji nieobsługiwanych przez Clang.
leedm777
1
@BasileStarynkevitch - Clang udaje, że jest jednocześnie __GNUC__i _MSC_VER, ale nie może używać tych samych programów co żaden z kompilatorów. Wykrywanie LLVM Clang i Apple Clang ma kluczowe znaczenie dla zapewnienia, że ​​kod kompiluje się i uruchamia zgodnie z oczekiwaniami. Jestem tak zmęczony radzeniem sobie z BS Clanga, że ​​po prostu przerywamy kompilację w systemie Windows . Przyjęliśmy zasadę pozwalającą użytkownikom na składanie skarg do LLVM, aby deweloperzy Clang zmienili swoje zachowanie. Zobacz także Jak powiedzieć Clangowi, aby przestał udawać inne kompilatory?
jww

Odpowiedzi:

242

Wiarygodnym sprawdzeniem jest użycie CMAKE_<LANG>_COMPILER_IDzmiennych. Na przykład, aby sprawdzić kompilator 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()

Te również działają poprawnie, jeśli używana jest otoka kompilatora, taka jak pamięć podręczna .

Począwszy od CMake 3.0.0, CMAKE_<LANG>_COMPILER_IDwartość Clang dostarczonego przez Apple wynosi teraz AppleClang. Aby przetestować zarówno Clang dostarczony przez Apple, jak i zwykły Clang, użyj następującego warunku if:

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

Zobacz także opis zasad AppleClang .

CMake 3.15 dodał obsługę zarówno dla clang-cl, jak i dla zwykłego clang. Możesz określić wariant interfejsu użytkownika, sprawdzając zmienną 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
źródło
Dokumentacja cmake stwierdza: „Jest to używane przy określaniu kompilatora i może ulec zmianie”. W przeciwnym razie byłoby idealnie :-(
leedm777 Kwietnia
17
Od CMake 2.8.10 ta zmienna jest (wreszcie!) Udokumentowana. Zobacz: cmake.org/cmake/help/v2.8.10/…
Nick Hutchinson
9
Zwróć uwagę, że CMAKE_CXX_COMPILER_IDzmienna jest dostępna tylko po poleceniu project(Foo CXX).
waldyrious
5
A dla flag, które akceptują zarówno gcc, jak i clang, używamif (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") ... endif()
Fred Schoen,
4
Jeśli nie wiesz, dlaczego nie możesz AppleClangdokładnie wykryć , @sakra wskazuje, że został cmake 3.0.0wydanyAppleClang . Jednak tylko dlatego, że cmake --versionraporty równe lub wyższe nie wystarczą - musisz to zrobić cmake_minimum_required(VERSION 3.0.0), aby 3.0.0standardy były używane!
svenevs
2

Kod źródłowy silnika OGRE 3D wykorzystuje następujące sprawdzenie :

if (CMAKE_CXX_COMPILER MATCHES ".*clang")
    set(CMAKE_COMPILER_IS_CLANGXX 1)
endif ()
arrowd
źródło
3
To blisko, ale nie działa, gdy używasz ccache (tj. export CXX="ccache clang++")
leedm777
4
Wystarczająco blisko, dam ci to. Kiedyś if ("${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" MATCHES ".*clang")zajmowałem się sprawą pamięci podręcznej.
leedm777
1
To nie działa dla mnie jako ${CMAKE_CXX_COMPILER} == /Library/Developer/CommandLineTools/usr/bin/c++. Zaakceptowana odpowiedź działa.
Fred Schoen
1

Aby uniknąć problemów z pisownią, używam porównania bez rozróżniania wielkości liter, na przykład:

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

Aby uczynić regex bez MATCHESrozróżniania wielkości liter, próbowałem tutaj wszystkiego bez powodzenia (nie wydaje się być obsługiwane w CMake).

Antonio
źródło
rzeczywiście, tak jak dzisiaj, dopasowanie bez uwzględniania wielkości liter nie jest możliwe cmake.org/pipermail/cmake/2017-May/065432.html
fferri
-2

To jest nieco bardziej szczegółowa odpowiedź dla nowicjuszy cmake, zmodyfikowana z odpowiedzi Sakry, po prostu dołącz następujące wiersze do 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()

Następnie uruchom cmake .w folderze, w którym znajduje się CMakeLists.txt. Następnie zobaczysz kilka wyników wraz z odpowiedzią.

...
-- Detecting CXX compile features
-- Detecting CXX compile features - done
GNU
-- Configuring done
-- Generating done
...
Searene
źródło