Jak aktywować C ++ 11 w CMake?

356

Kiedy próbuję uruchomić plik makefile wygenerowany przez CMake w celu skompilowania mojego programu, pojawia się błąd

zakres oparty na pętlach nie jest obsługiwany w trybie C ++ 98.

Próbowałem dodać add_definitions(-std=c++0x)do mojego CMakeLists.txt, ale to nie pomogło.

Próbowałem też:

if(CMAKE_COMPILER_IS_GNUCXX)
    add_definitions(-std=gnu++0x)
endif()

Kiedy to robię g++ --version, otrzymuję:

g ++ (Ubuntu / Linaro 4.6.1-9ubuntu3) 4.6.1

Próbowałem też SET(CMAKE_CXX_FLAGS "-std=c++0x"), co też nie działa.

Nie rozumiem, jak mogę aktywować funkcje C ++ 11 za pomocą CMake.

Subhamoy S.
źródło
11
SET(CMAKE_CXX_FLAGS "-std=c++0x")Działa dobrze dla mnie, więc nie ma chyba problem gdzie indziej w pliku CMakeLists. Upewnij się, że później nie przypadkowo zastąpisz zawartość CMAKE_CXX_FLAGS.
ComicSansMS
7
add_definitions (-std = c ++ 11) działa dla mnie z CMake 2.8.8
kyku
@ComicSansMS: Masz całkowitą rację! Nadpisałem to, co było moim błędem. Poprawiłem to, a teraz działa dobrze! C ++ 11 rzeczy jest bardzo fajne! Chciałem zapętlić wektor struktur, który wymagałby iteratora i niepotrzebnego szumu kodowania, gdybym nie miał zasięgu opartego na pętlach. Chyba mógłbym użyć BOOST_FOREACH, ale no cóż ...
Subhamoy S.
32
W przypadku CMake ≥3.1 set(CMAKE_CXX_STANDARD 11)(przed zdefiniowaniem celu) jest najlepszym sposobem.
emlai
@tuple_cat Możesz to zrobić również w oparciu o cele. Ale pamiętaj, że CXX_STANDARDto nie działa na MSVC, więc w zasadzie musisz cofnąć się, target_compile_featuresjeśli chcesz czegoś, co działa na wielu platformach.
Ela782,

Odpowiedzi:

395

CMake 3.1 wprowadził zmienną CMAKE_CXX_STANDARD , której możesz użyć. Jeśli wiesz, że zawsze będziesz mieć dostępną wersję CMake 3.1, możesz po prostu napisać ją w pliku CMakeLists.txt najwyższego poziomu lub ustawić ją przed zdefiniowaniem nowego obiektu docelowego:

set (CMAKE_CXX_STANDARD 11)

Jeśli potrzebujesz obsługi starszych wersji CMake, oto makro, które wymyśliłem, którego możesz użyć:

macro(use_cxx11)
  if (CMAKE_VERSION VERSION_LESS "3.1")
    if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
      set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
    endif ()
  else ()
    set (CMAKE_CXX_STANDARD 11)
  endif ()
endmacro(use_cxx11)

Makro obsługuje obecnie tylko GCC, ale powinno być łatwe do rozszerzenia na inne kompilatory.

Następnie możesz napisać use_cxx11()na górze dowolnego pliku CMakeLists.txt, który definiuje cel, który używa C ++ 11.

CMake numer 15943 dla użytkowników clang atakujących macOS

Jeśli używasz CMake i clang do targetowania macOS, istnieje błąd, który może powodować, że CMAKE_CXX_STANDARDfunkcja po prostu nie działa (nie dodaje żadnych flag kompilatora). Upewnij się, że wykonujesz jedną z następujących czynności:

  • Użyj cmake_minimum_required, aby wymagać CMake 3.0 lub nowszego, lub
  • Ustaw zasadę CMP0025 na NOWY z następującym kodem u góry pliku CMakeLists.txt przed projectpoleceniem:

    # Fix behavior of CMAKE_CXX_STANDARD when targeting macOS.
    if (POLICY CMP0025)
      cmake_policy(SET CMP0025 NEW)
    endif ()
David Grayson
źródło
12
To powinna być zaakceptowana odpowiedź. Nie wymaga indywidualnego dotykania właściwości każdego celu i działa na różnych platformach.
DevSolar
4
Uzgodnione, powinna to być zaakceptowana odpowiedź od CMake 3.1+. Jednak wydaje mi się, że nie działa na komputerze Mac. Możesz zmusić go, aby dał ci --std = c ++ 11 z opcją --stdlib = libc ++, domyślnie na Macu. Zamiast tego CMAKE_CXX_STANDARD zawsze zawiera rozszerzenia GNU, jeśli są obsługiwane, a wynik nie wydaje się być oparty na --stdlib = libc ++. Zamiast tego musisz przełączyć na GNU --stdlib = libstdc ++. Mac to jednak wyjątkowy przypadek. W Linuksie wybór gnu ++ 11 z libstdc ++ jest normą. Oczywiście można to łatwo poprawić za pomocą if (APPLE) add_compile_options (), aby sczepić flagi.
Atifm
2
Jednym z problemów tego podejścia jest gnu++11wymuszanie, nawet gdy te zmienne są zdefiniowane set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(CMAKE_ANDROID_STL_TYPE c++_static). Dla mnie jedynym realnym sposobem był klasykset (CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
Antonio
2
Nie działa dla mnie na macOS (CMake 3.9.4, homebrew-clang). Ratowanie innych rozpaczy. Nie jestem pewien, dlaczego to działa dla @EvanMoran, ale nie dla mnie.
Unapiedra
2
@Unapiedra: To błąd CMake, ale można go obejść, patrz gitlab.kitware.com/cmake/cmake/issues/15943
David Grayson
186

Polecenie CMake target_compile_features()służy do określania wymaganej funkcji C ++ cxx_range_for. CMake wywoła następnie użycie standardu C ++.

cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
project(foobar CXX)
add_executable(foobar main.cc)
target_compile_features(foobar PRIVATE cxx_range_for)

Nie ma potrzeby używania add_definitions(-std=c++11)ani modyfikowania zmiennej CMake CMAKE_CXX_FLAGS, ponieważ CMake upewni się, że kompilator C ++ zostanie wywołany z odpowiednimi flagami wiersza poleceń.

Być może twój program C ++ używa innych funkcji C ++ niż cxx_range_for. Globalna właściwość CMake CMAKE_CXX_KNOWN_FEATURESzawiera listę funkcji C ++ do wyboru.

Zamiast używać target_compile_features()można również jawnie określić standard C ++, ustawiając właściwości CMake CXX_STANDARD i CXX_STANDARD_REQUIREDcel CMake.

Zobacz także moją bardziej szczegółową odpowiedź .

Erik Sjölund
źródło
4
Wydaje się, że dzisiejsza edycja wprowadza w błąd. CMake 3.0.0 nie zawiera target_compile_features. Popraw mnie, jeśli się mylę. Myślę, że polecenie jest obecne tylko w nocnych wersjach CMake.
Erik Sjölund
4
Powiedziałbym, że to najdokładniejsza odpowiedź
Michał Walenciak,
8
Myślę, że tak właśnie powinno być. Inne odpowiedzi po prostu ręcznie dodają flagi, a zatem wprowadzają niezgodności. Jednak wydaje się, że jest to dostępne tylko w CMake 3.1+
Uli Köhler
2
@ UliKöhler jest to wciąż niedostępne i może się pojawić w przypadku niektórych kompilatorów w wersji 3.2. Nie używaj tej metody w krótkim okresie; jest całkowicie nieprzenośny.
Doug
2
Masz pomysł, jak to zrobić w CMake 2.6?
nuzzolilo
93

ja używam

include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
        message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

Ale jeśli chcesz się bawić C++11, g++ 4.6.1jest dość stary. Spróbuj uzyskać nowszą g++wersję.

KoKuToru
źródło
4
To jest dla mnie jedyna słuszna i miła odpowiedź na to pytanie, z obecnym (rozwiniętym) cmake na najnowszym Linuksie używającym g ++.
Patrick B.,
1
Skopiowałem i wkleiłem to i działało idealnie. Korzystam z Cygwin przy użyciu CMAKE 2.8.9. Wiem o większości podejść, które tutaj czytam, ponieważ śledzę listę mailingową CMAKE i przeniosłem WebKit do różnych kompilatorów. To, co zrobiliśmy dla portów WebKit, to zainstalowanie CMake 2.8.12. Ponieważ jednak wiem, że CMAKE Cygwina jest stary, chciałem czegoś, co dotyczyłoby tej wersji. (Przepraszam, nie przenosiłem WebKit do Cygwina)
kosmonauta z Cardiff
Świetnie, jest to drop-up dla starego CMake i g ++ 4.6 (i przyszłości). Głosowałem również za CXX_STANDARDodpowiedziami na podstawie, ale była to jedyna odpowiedź przydatna w mojej sytuacji.
Tomasz Gandor
Właśnie tego szukałem, jednak nie jest jasne, jaka jest minimalna wersja cmake potrzebna do korzystania z tego modułu. cmake --help-module niewiele na to pomaga.
Jan Segre
1
@ JanSegre moduł pojawił się po raz pierwszy w 2.4, cmake.org/…
KoKuToru
57

Najłatwiejszym sposobem ustawienia standardu Cxx jest:

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

Więcej informacji znajduje się w dokumentacji CMake .

Luckyrand
źródło
2
Tak, to zdecydowanie wygląda na jeden z najlepszych sposobów, aby to zrobić we współczesnym CMake (3.1+)
Erbureth mówi Przywróć Monikę
14
Możesz też set(CMAKE_CXX_STANDARD 11)zdefiniować domyślną właściwość dla wszystkich celów utworzonych później.
emlai
1
Jest to również rozwiązanie potrzebne, jeśli chcesz ustawić różne standardy C ++ dla różnych celów, ponieważ setpolecenie sugerowane przez @emlai ma charakter globalny i wpływa na wszystkie kolejne cele.
Elliott Slaughter
40

Jak się okazuje, SET(CMAKE_CXX_FLAGS "-std=c++0x")aktywuje wiele funkcji C ++ 11. Powodem, dla którego nie zadziałało, było to, że oświadczenie wyglądało tak:

set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")

Po tym podejściu -std=c++0xflaga została w jakiś sposób nadpisana i nie działała. Działa ustawianie flag jeden po drugim lub przy użyciu metody listy.

list( APPEND CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")
Subhamoy S.
źródło
36
Zawsze po prostu używam: SET (CMAKE_CXX_FLAGS "$ {CMAKE_CXX_FLAGS} -std = c ++ 11") # dla gcc> = 4,7 lub c ++ 0x dla 4,6
David Doria,
Kiedyś napisałem do tego mały skrypt (choć nie jest kompletny): github.com/Morwenn/POLDER/blob/master/cmake/set_cxx_norm.cmake
Morwenn
9
-1. Jeśli określisz dowolny CMAKE_CXX_FLAGS z wiersza poleceń, druga metoda wygeneruje średnik w poleceniu kompilacji (i powtórz oryginalny CMAKE_CXX_FLAGS dwa razy).
Nikołaj
zamiast ręcznego dodawania flagi -g powinieneś ustawić zmienną CMAKE_BUILD_TYPE na debugowanie: voices.canonical.com/jussi.pakkanen/2013/03/26/…
bames53
1
CXX_STANDARDNieruchomość jest lepszy, ponieważ jest to kompilator-agnostykiem.
jaskmar
23

Najłatwiejszy sposób:

add_compile_options(-std=c++11)

alvarez
źródło
5
Dostępne tylko z cmake 3.0
Raúl Salinas-Monteagudo
4
Powoduje to ostrzeżenie i błędy podczas kompilacji plików C w tym samym projekcie.
woda różana
19

Do CMake 3.8 i nowszych możesz użyć

target_compile_features(target PUBLIC cxx_std_11)
rzęsa
źródło
1
jest to sposób zalecany w najnowszej wersji CMake
camino
Jaka jest PUBLICtutaj funkcja ?
Rotsiser Mho
2
@RotsiserMho PUBLICoznacza, że ​​inne cele zależne od twojego celu również będą używać C ++ 11. Na przykład, jeśli twoim celem jest biblioteka, wówczas wszystkie cele łączące się z twoją biblioteką target_link_librarieszostaną skompilowane z obsługą C ++ 11.
rzęsa
17

To kolejny sposób włączenia obsługi C ++ 11,

ADD_DEFINITIONS(
    -std=c++11 # Or -std=c++0x
    # Other flags
)

Napotkałem przypadki, w których działa tylko ta metoda, a inne metody zawodzą. Może ma to coś wspólnego z najnowszą wersją CMake.

Hindol
źródło
9
Działa to tylko wtedy, gdy używasz TYLKO kompilatora C ++. Jeśli używasz również kompilatora CC, zakończy się niepowodzeniem.
Emmanuel,
5
add_definitionssłuży tylko do dodawania DEFINICJI, tj. -D COŚ. I jak powiedział @Emmanuel, w wielu przypadkach nie działa.
xuhdev
Użyłem tego wcześniej, ale miałem problemy, gdy dołączyłem plik C, ponieważ add_definitionsnie został stworzony do ustawiania flag.
Jan Segre
17

Na współczesnym CMake (> = 3.1) najlepszym sposobem na ustawienie globalnych wymagań jest:

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

Przekłada się to na „Chcę C ++ 11 dla wszystkich celów, nie jest opcjonalny, nie chcę używać żadnych rozszerzeń GNU ani Microsoft”. Począwszy od C ++ 17, nadal jest to najlepszy sposób IMHO.

Źródło: Włączanie C ++ 11 i później w CMake

MateuszL
źródło
1
Ten sposób nie jest idealny dla najnowszych wersji C ++, jeśli nie masz najnowszej wersji CMake. Np. Nie można włączyć C ++ 2a w ten sposób, dopóki CMake 3.12.
Ruslan
6

To, co działa dla mnie, to ustawić następujący wiersz w pliku CMakeLists.txt:

set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

Ustawienie tego polecenia aktywuje funkcje C ++ 11 dla kompilatora, a po wykonaniu cmake ..polecenia powinieneś być w stanie korzystać range based for loopsz kodu i skompilować go bez żadnych błędów.

Kevin Katzke
źródło
To jest w końcu najlepsza odpowiedź, jeśli chcesz dokładnie -std=c++11, ponieważ set (CMAKE_CXX_STANDARD 11)użyje flagi -std=gnu++11, co może być niepożądane.
Antonio
1
@Antonioset (CMAKE_CXX_EXTENSIONS OFF)
mloskot
3

Myślę, że wystarczy te dwie linie.

set(CMAKE_CXX_STANDARD 11)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
Ehsan Panahi
źródło
1
Ma to sens, gdy wszystkie cele w projekcie używają tego samego standardu C ++ (na przykład wszystkie skompilowane biblioteki i pliki wykonywalne używają C ++ 11). W przeciwnym razie target_compile_featuresfunkcja Cmake , zastosowana dla każdego celu, jak pokazano w innych odpowiedziach, jest bardziej zalecanym podejściem.
Allan,
3

Jeśli chcesz zawsze aktywować najnowszy standard C ++, oto moje rozszerzenie odpowiedzi Davida Graysona , w świetle ostatnich (CMake 3.8 i CMake 3.11) dodatków o wartościach 17 i 20 dla CMAKE_CXX_STANDARD):

IF (CMAKE_VERSION VERSION_LESS "3.8")
    SET(CMAKE_CXX_STANDARD 14)
ELSEIF (CMAKE_VERSION VERSION_LESS "3.11")
    SET(CMAKE_CXX_STANDARD 17)
ELSE()
    SET(CMAKE_CXX_STANDARD 20)
ENDIF()

# Typically, you'll also want to turn off compiler-specific extensions:
SET(CMAKE_CXX_EXTENSIONS OFF)

(Użyj tego kodu zamiast set (CMAKE_CXX_STANDARD 11)linku w odpowiedzi.)

kodowanie
źródło
1

Nowoczesne cmake oferuje prostsze sposoby konfigurowania kompilatorów do używania konkretnej wersji C ++. Jedyne, co każdy musi zrobić, to ustawić odpowiednie właściwości docelowe. Wśród właściwości obsługiwanych przez cmake są te, które są używane do określenia, jak skonfigurować kompilatory do obsługi określonej wersji C ++:

  • CXX_STANDARDustawia standard C ++, którego funkcji wymaga budowanie obiektu docelowego. Ustaw to jako 11docelowe C ++ 11.

  • CXX_EXTENSIONS, wartość logiczna określająca, czy wymagane są rozszerzenia specyficzne dla kompilatora. Ustawienie tego jako Offwyłącza obsługę dowolnego rozszerzenia specyficznego dla kompilatora.

Aby to zademonstrować, oto minimalny działający przykład CMakeLists.txt.

cmake_minimum_required(VERSION 3.1)

project(testproject LANGUAGES CXX )

set(testproject_SOURCES
    main.c++
    )

add_executable(testproject ${testproject_SOURCES})

set_target_properties(testproject
    PROPERTIES
    CXX_STANDARD 11
    CXX_EXTENSIONS off
    )
Baran
źródło
-5

Związane z OS X i Homebrew LLVM:

Nie zapomnij wywołać cmake_minimum_required (VERSION 3.3) i project () po nim!

Lub CMake wstawi project()niejawnie przed wierszem 1, powodując problemy z wykrywaniem wersji Clanga i ewentualnie inne problemy. Oto pokrewny problem .

senz
źródło
2
Pytanie nie dotyczy konkretnie OSX ani LVVM. Ponadto nie ma powodu, aby wymagać CMake v3.x do programowania w C ++ 11. Jeśli chodzi o wykrywanie wersji clang - nie o to pytał OP.
einpoklum