Come posso attivare C ++ 11 in CMake?


356

Quando provo ad eseguire un makefile generato da CMake per compilare il mio programma, ottengo l'errore

l'intervallo basato su loop non è supportato in modalità C ++ 98.

Ho provato ad aggiungere add_definitions(-std=c++0x)al mio CMakeLists.txt, ma non ha aiutato.

Ho provato anche questo:

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

Quando lo faccio g++ --version, ottengo:

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

Ho anche provato SET(CMAKE_CXX_FLAGS "-std=c++0x"), che non funziona.

Non capisco come posso attivare le funzionalità di C ++ 11 usando CMake.


11
Il SET(CMAKE_CXX_FLAGS "-std=c++0x")bene funziona per me, quindi non c'è probabilmente un problema da qualche altra parte nel file CMakeLists. Assicurati di non sovrascrivere accidentalmente il contenuto di CMAKE_CXX_FLAGS in seguito.
ComicSansMS

7
add_definitions (-std = c ++ 11) funziona per me con CMake 2.8.8
kyku

@ComicSansMS: hai perfettamente ragione! L'ho sovrascritto, che è stato il mio errore. L'ho corretto e ora funziona bene! Le cose in C ++ 11 sono molto interessanti! Volevo fare un ciclo su un vettore di strutture, che richiederebbe iteratore e rumore di codifica inutile se non avessi un range basato su loop. Immagino di poter usare BOOST_FOREACH però, ma vabbè ...
Subhamoy S.

32
Per CMake ≥3.1, set(CMAKE_CXX_STANDARD 11)(prima di definire l'obiettivo) è il modo migliore.
emlai,

@tuple_cat Puoi farlo anche in base al target. Ma essere consapevoli che CXX_STANDARDnon non lavoro su MSVC, quindi sostanzialmente bisogna ricadere target_compile_featuresse si desidera qualcosa che funziona cross-platform.
Ela782

Risposte:


395

CMake 3.1 ha introdotto la variabile CMAKE_CXX_STANDARD che è possibile utilizzare. Se sai che avrai sempre a disposizione CMake 3.1, puoi semplicemente scriverlo nel tuo file CMakeLists.txt di livello superiore o metterlo subito prima che venga definita una nuova destinazione:

set (CMAKE_CXX_STANDARD 11)

Se hai bisogno di supportare versioni precedenti di CMake, ecco una macro che mi è venuta in mente che puoi usare:

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)

La macro supporta solo GCC in questo momento, ma dovrebbe essere semplice per espanderlo ad altri compilatori.

Quindi è possibile scrivere use_cxx11()nella parte superiore di qualsiasi file CMakeLists.txt che definisce una destinazione che utilizza C ++ 11.

Emissione CMake n. 15943 per utenti clang indirizzati a macOS

Se stai usando CMake e clang per indirizzare macOS c'è un bug che può CMAKE_CXX_STANDARDsemplicemente non far funzionare la funzione (non aggiungere alcun flag del compilatore). Assicurati di eseguire una delle seguenti operazioni:

  • Utilizzare cmake_minimum_required per richiedere CMake 3.0 o versione successiva oppure
  • Impostare il criterio CMP0025 su NUOVO con il seguente codice nella parte superiore del file CMakeLists.txt prima del projectcomando:

    # Fix behavior of CMAKE_CXX_STANDARD when targeting macOS.
    if (POLICY CMP0025)
      cmake_policy(SET CMP0025 NEW)
    endif ()

12
Questa dovrebbe essere la risposta accettata. Non richiede il contatto individuale delle proprietà di ciascun bersaglio e funziona su più piattaforme.
DevSolar,

4
D'accordo, questa dovrebbe essere la risposta accettata a partire da CMake 3.1+. Tuttavia, non sembra funzionare per me sul Mac. Puoi forzarlo a darti --std = c ++ 11 con --stdlib = libc ++, il default sul Mac. Invece CMAKE_CXX_STANDARD include sempre le estensioni gnu se sono supportate e il risultato non sembra costruire su --stdlib = libc ++. Invece devi passare a --stdlib = libstdc ++ di gnu. Il Mac è il caso speciale però. Per Linux, la scelta di gnu ++ 11 con libstdc ++ è la norma. Ovviamente, ciò viene facilmente corretto con un if (APPLE) add_compile_options () da virare sulle bandiere.
Atifm,

2
Un problema di questo approccio è che gnu++11viene applicato, anche quando queste variabili sono definite set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(CMAKE_ANDROID_STL_TYPE c++_static). Per me l'unico modo possibile era il classicoset (CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
Antonio,

2
Non funziona per me su macOS (CMake 3.9.4, homebrew-clang). Salvare la disperazione degli altri. Non sono sicuro del perché funzioni per @EvanMoran ma non per me.
Unapiedra,

2
@Unapiedra: è un bug di CMake ma puoi aggirarlo
David Grayson,

186

Il comando CMake target_compile_features()viene utilizzato per specificare la funzione C ++ richiesta cxx_range_for. CMake indurrà quindi lo standard C ++ da utilizzare.

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)

Non è necessario utilizzare add_definitions(-std=c++11)o modificare la variabile CMake CMAKE_CXX_FLAGS, poiché CMake si assicurerà che il compilatore C ++ venga richiamato con i flag della riga di comando appropriati.

Forse il tuo programma C ++ utilizza altre funzionalità C ++ di cxx_range_for. La proprietà globale CMake CMAKE_CXX_KNOWN_FEATURESelenca le funzionalità C ++ che è possibile scegliere.

Invece di utilizzare target_compile_features()è anche possibile specificare esplicitamente lo standard C ++ impostando le proprietà CMake CXX_STANDARD e CXX_STANDARD_REQUIREDper il proprio target CMake.

Vedi anche la mia risposta più dettagliata .


4
Sembra che la modifica di oggi sia fuorviante. CMake 3.0.0 non contiene target_compile_features. Correggimi se sbaglio. Penso che il comando sia presente solo nelle build notturne di CMake.
Erik Sjölund,

4
Direi che questa è la risposta più accurata
Michał Walenciak,

8
Penso che sia così che dovrebbe fare. Le altre risposte aggiungono semplicemente flag manualmente e quindi introducono incompatibilità. Tuttavia, questo sembra essere disponibile solo in CMake 3.1+
Uli Köhler

2
@ UliKöhler questo in realtà non è ancora disponibile e potrebbe eventualmente presentarsi per alcuni compilatori in 3.2. Non utilizzare questo metodo a breve termine; è completamente non portatile.
Doug

2
Qualche idea su come farlo in CMake 2.6?
nuzzolilo,

93

sto usando

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

Ma se vuoi giocare C++11, g++ 4.6.1è piuttosto vecchio. Prova a ottenere una g++versione più recente.


4
Questa è, per me, l'unica risposta giusta e piacevole a questa domanda, con l'attuale (implementato) cmake sul Linux più recente 'usando g ++.
Patrick B.

1
Questo è stato copiato e incollato e ha funzionato perfettamente. Sono su Cygwin usando CMAKE 2.8.9. Conosco la maggior parte degli approcci che sto leggendo qui perché seguo la mailing list di CMAKE e ho portato WebKit su una varietà di compilatori. La cosa che avevamo fatto per le porte WebKit era installare CMake 2.8.12. Tuttavia, poiché so che il CMAKE di Cygwin è vecchio, volevo qualcosa da applicare a quella versione. (Non portare WebKit su Cygwin, scusate)
cardiff space man

Ottimo, questo è un drop-in per i vecchi CMake e g ++ 4.6 (e a prova di futuro). Ho anche valutato le CXX_STANDARDrisposte basate su, ma questa è stata l'unica risposta utile nella mia situazione.
Tomasz Gandor,

Questo è esattamente quello che stavo cercando, tuttavia non è chiaro quale sia la versione minima di cmake necessaria per utilizzare quel modulo. cmake --help-module non aiuta molto al riguardo.
Jan Segre,

1
@JanSegre il modulo è apparso per la prima volta in 2.4, cmake.org/…
KoKuToru

57

Il modo più semplice per impostare lo standard Cxx è:

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

Vedere la documentazione di CMake per maggiori dettagli.


2
Sì, questo sembra sicuramente uno dei modi migliori per farlo nella moderna CMake (3.1+)
Erbureth dice Reinstate Monica

14
Oppure puoi semplicemente set(CMAKE_CXX_STANDARD 11)definire la proprietà predefinita per tutte le destinazioni create successivamente.
emlai,

1
Questa è anche la soluzione di cui hai bisogno se vuoi impostare diversi standard C ++ su target diversi, perché il setcomando suggerito da @emlai è globale e influenza tutti i target successivi.
Elliott Slaughter,

40

A quanto pare, SET(CMAKE_CXX_FLAGS "-std=c++0x")attiva molte funzionalità di C ++ 11. La ragione per cui non ha funzionato è stata che la dichiarazione sembrava così:

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

Seguendo questo approccio, in qualche modo la -std=c++0xbandiera è stata sovrascritta e non ha funzionato. L'impostazione dei flag uno alla volta o l'utilizzo di un metodo elenco funziona.

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

36
Uso sempre: SET (CMAKE_CXX_FLAGS "$ {CMAKE_CXX_FLAGS} -std = c ++ 11") # per gcc> = 4.7 o c ++ 0x per 4.6
David Doria

Una volta ho fatto una piccola sceneggiatura (non completa): github.com/Morwenn/POLDER/blob/master/cmake/set_cxx_norm.cmake
Morwenn

9
-1. Se si specifica CMAKE_CXX_FLAGS dalla riga di comando, il secondo metodo produrrà un punto e virgola nel comando build (e ripeterà due volte l'originale CMAKE_CXX_FLAGS).
Nikolai,

invece di aggiungere manualmente il flag -g dovresti impostare la variabile CMAKE_BUILD_TYPE su debug: voices.canonical.com/jussi.pakkanen/2013/03/26/…
bames53

1
La CXX_STANDARDproprietà è migliore in quanto è indipendente dal compilatore.
Jaskmar,


19

Per CMake 3.8 e versioni successive è possibile utilizzare

target_compile_features(target PUBLIC cxx_std_11)

1
questo è il modo raccomandato dell'ultima versione di CMake
camino

Qual è la funzione di PUBLICqui?
Rotsiser Mho,

2
@RotsiserMho PUBLICsignifica che anche altri target che dipendono dal tuo target useranno C ++ 11. Ad esempio, se la destinazione è una libreria, tutte le destinazioni collegate alla libreria target_link_librariesverranno compilate con il supporto C ++ 11.
ciglia

17

Questo è un altro modo per abilitare il supporto C ++ 11,

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

Ho riscontrato casi in cui funziona solo questo metodo e altri metodi falliscono. Forse ha qualcosa a che fare con l'ultima versione di CMake.


9
Funzionerà solo se stai usando SOLO compilatore C ++. Se stai usando anche il compilatore CC, fallirà.
Emmanuel,

5
add_definitionsdovrebbe solo essere usato per aggiungere DEFINIZIONI, cioè MrGreen QUALCOSA. E come ha detto @Emmanuel, in molti casi non funziona.
xuhdev,

L'ho usato prima, ma ho avuto problemi quando ho incluso un file C perché add_definitionsnon è stato creato per l'impostazione dei flag.
Jan Segre,

17

Su CMake moderno (> = 3.1) il modo migliore per impostare requisiti globali è:

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

Si traduce in "Voglio C ++ 11 per tutte le destinazioni, non è facoltativo, non voglio usare alcuna estensione GNU o Microsoft." A partire da C ++ 17, questo è ancora IMHO il modo migliore.

Fonte: Abilitazione di C ++ 11 e versioni successive in CMake


1
In questo modo non è l'ideale per le versioni più recenti di C ++ se non si dispone dell'ultima CMake. Ad esempio, non è possibile abilitare C ++ 2a in questo modo fino a CMake 3.12.
Ruslan,

6

Ciò che funziona per me è impostare la seguente riga in CMakeLists.txt:

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

L'impostazione di questo comando attiva le funzionalità di C ++ 11 per il compilatore e dopo aver eseguito il cmake ..comando, dovresti essere in grado di utilizzarlo range based for loopsnel tuo codice e compilarlo senza errori.


Questa è alla fine la risposta migliore se vuoi esattamente -std=c++11, come set (CMAKE_CXX_STANDARD 11)userai la bandiera -std=gnu++11, che potrebbe essere indesiderabile.
Antonio,

1
@Antonioset (CMAKE_CXX_EXTENSIONS OFF)
mloskot

3

Penso che solo queste due linee siano sufficienti.

set(CMAKE_CXX_STANDARD 11)

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

1
Questo ha senso quando tutte le destinazioni in un progetto usano lo stesso standard C ++ (tutte le librerie e gli eseguibili compilati usano C ++ 11, per esempio). Altrimenti, la target_compile_featuresfunzione Cmake , applicata per ogni singolo bersaglio, come mostrato in altre risposte, è un approccio più raccomandato.
Allan,

3

Nel caso in cui desideri attivare sempre l'ultimo standard C ++, ecco la mia estensione della risposta di David Grayson , alla luce delle recenti aggiunte (CMake 3.8 e CMake 3.11) di valori di 17 e 20 per 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)

(Usa quel codice al posto di set (CMAKE_CXX_STANDARD 11)nella risposta collegata.)


1

Il cmake moderno offre modi più semplici per configurare i compilatori per utilizzare una versione specifica di C ++. L'unica cosa che chiunque deve fare è impostare le proprietà target pertinenti. Tra le proprietà supportate da cmake , quelle utilizzate per determinare come configurare i compilatori per supportare una versione specifica di C ++ sono le seguenti:

  • CXX_STANDARDimposta lo standard C ++ le cui funzionalità sono richieste per creare la destinazione. Impostalo come 11target C ++ 11.

  • CXX_EXTENSIONS, un valore booleano che specifica se sono richieste estensioni specifiche del compilatore. Impostandolo come si Offdisabilita il supporto per qualsiasi estensione specifica del compilatore.

Per dimostrare, ecco un esempio minimo di lavoro di a 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
    )

-5

OS X e Homebrew LLVM correlati:

Non dimenticare di chiamare cmake_minimum_required (VERSIONE 3.3) e project () dopo!

Oppure CMake inserirà project()implicitamente prima della riga 1, causando problemi con il rilevamento della versione di Clang e probabilmente altri tipi di problemi. Ecco un problema correlato .


2
La domanda non è correlata a OSX o LVVM, in particolare. Inoltre, non c'è motivo di richiedere CMake v3.x per lo sviluppo di C ++ 11. Per quanto riguarda il rilevamento della versione di clang, non è stato chiesto a OP.
einpoklum,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.