Comment activer C ++ 11 dans CMake?

356

Lorsque j'essaie d'exécuter un makefile généré par CMake pour compiler mon programme, j'obtiens l'erreur

La plage basée sur les boucles n'est pas prise en charge en mode C ++ 98.

J'ai essayé d' ajouter add_definitions(-std=c++0x)à mon CMakeLists.txt, mais il n'a pas aidé.

J'ai aussi essayé ça:

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

Quand je le fais g++ --version, je reçois:

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

J'ai également essayé SET(CMAKE_CXX_FLAGS "-std=c++0x"), ce qui ne fonctionne pas non plus.

Je ne comprends pas comment activer les fonctionnalités C ++ 11 à l'aide de CMake.

Subhamoy S.
la source
11
Le SET(CMAKE_CXX_FLAGS "-std=c++0x")fonctionne très bien pour moi, donc il y a probablement un problème ailleurs dans le fichier CMakeLists. Assurez-vous de ne pas écraser accidentellement le contenu de CMAKE_CXX_FLAGS ultérieurement.
ComicSansMS
7
add_definitions (-std = c ++ 11) fonctionne pour moi avec CMake 2.8.8
kyku
@ComicSansMS: Vous avez tout à fait raison! Je l'ai écrasé, ce qui était ma propre erreur. Je l'ai corrigé, et maintenant ça marche bien! Le contenu C ++ 11 est très cool! Je voulais boucler sur un vecteur de structures, ce qui nécessiterait un itérateur et un bruit de codage inutile si je n'avais pas de plage basée sur les boucles. Je suppose que je pourrais utiliser BOOST_FOREACH cependant, mais bon ...
Subhamoy S.
32
Pour CMake ≥3.1, set(CMAKE_CXX_STANDARD 11)(avant de définir la cible) est le meilleur moyen.
emlai
@tuple_cat Vous pouvez également le faire en fonction de la cible. Mais sachez que CXX_STANDARDcela ne fonctionne pas sur MSVC, donc en gros, vous devez vous rabattre sur target_compile_featuressi vous voulez quelque chose qui fonctionne sur plusieurs plates-formes.
Ela782

Réponses:

395

CMake 3.1 a introduit la variable CMAKE_CXX_STANDARD que vous pouvez utiliser. Si vous savez que CMake 3.1 sera toujours disponible, vous pouvez simplement l'écrire dans votre fichier CMakeLists.txt de niveau supérieur ou le placer juste avant la définition d'une nouvelle cible:

set (CMAKE_CXX_STANDARD 11)

Si vous devez prendre en charge les anciennes versions de CMake, voici une macro que j'ai imaginée que vous pouvez utiliser:

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 ne prend en charge que GCC pour le moment, mais il devrait être simple de l'étendre à d'autres compilateurs.

Ensuite, vous pouvez écrire use_cxx11()en haut de n'importe quel fichier CMakeLists.txt qui définit une cible qui utilise C ++ 11.

Problème CMake # 15943 pour les utilisateurs de Clang ciblant macOS

Si vous utilisez CMake et clang pour cibler macOS, un bogue peut empêcher la CMAKE_CXX_STANDARDfonctionnalité de fonctionner (n'ajoutez aucun indicateur de compilation). Assurez-vous de faire l'une des choses suivantes:

  • Utilisez cmake_minimum_required pour exiger CMake 3.0 ou une version ultérieure, ou
  • Définissez la stratégie CMP0025 sur NEW avec le code suivant en haut de votre fichier CMakeLists.txt avant la projectcommande:

    # Fix behavior of CMAKE_CXX_STANDARD when targeting macOS.
    if (POLICY CMP0025)
      cmake_policy(SET CMP0025 NEW)
    endif ()
    
David Grayson
la source
12
Ce devrait être la réponse acceptée. Il ne nécessite pas de toucher individuellement les propriétés de chaque cible et fonctionne sur plusieurs plates-formes.
DevSolar
4
D'accord, cela devrait être la réponse acceptée à partir de CMake 3.1+. Cela ne semble pas fonctionner pour moi sur le mac. Vous pouvez le forcer à vous donner --std = c ++ 11 avec --stdlib = libc ++, la valeur par défaut sur Mac. Au lieu de cela, CMAKE_CXX_STANDARD inclut toujours les extensions gnu si elles sont prises en charge, et le résultat ne semble pas s'appuyer sur --stdlib = libc ++. Au lieu de cela, vous devez passer à --stdlib = libstdc ++ de gnu. Le Mac est cependant un cas particulier. Pour Linux, choisir gnu ++ 11 avec libstdc ++ est la norme. Bien sûr, cela est facilement corrigé avec un if (APPLE) add_compile_options () pour virer de bord sur les drapeaux.
Atifm
2
Un problème de cette approche est qu'elle gnu++11est appliquée, même lorsque ces variables sont définies set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(CMAKE_ANDROID_STL_TYPE c++_static). Pour moi, le seul moyen viable était le classiqueset (CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
Antonio
2
Ne fonctionne pas pour moi sur macOS (CMake 3.9.4, homebrew-clang). Sauver les autres le désespoir. Je ne sais pas pourquoi cela fonctionne pour @EvanMoran mais pas pour moi.
Unapiedra
2
@Unapiedra: C'est un bogue CMake mais vous pouvez le contourner, voir gitlab.kitware.com/cmake/cmake/issues/15943
David Grayson
186

La commande CMake target_compile_features()est utilisée pour spécifier la fonctionnalité C ++ requise cxx_range_for. CMake induira alors le standard C ++ à utiliser.

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)

Il n'est pas nécessaire d'utiliser add_definitions(-std=c++11)ou de modifier la variable CMake CMAKE_CXX_FLAGS, car CMake s'assurera que le compilateur C ++ est appelé avec les indicateurs de ligne de commande appropriés.

Peut-être que votre programme C ++ utilise d'autres fonctionnalités C ++ que cxx_range_for. La propriété globale CMake CMAKE_CXX_KNOWN_FEATURESrépertorie les fonctionnalités C ++ parmi lesquelles vous pouvez choisir.

Au lieu d'utiliser, target_compile_features()vous pouvez également spécifier explicitement la norme C ++ en définissant les propriétés CMake CXX_STANDARD et CXX_STANDARD_REQUIREDpour votre cible CMake.

Voir aussi ma réponse plus détaillée .

Erik Sjölund
la source
4
Il semble que l'édition d'aujourd'hui soit trompeuse. CMake 3.0.0 ne contient pas de target_compile_features. Corrige moi si je me trompe. Je pense que la commande n'est présente que dans les versions nocturnes de CMake.
Erik Sjölund
4
Je dirais que c'est la réponse la plus exacte
Michał Walenciak
8
Je pense que c'est ainsi que cela est censé se faire. Les autres réponses ajoutent simplement des indicateurs manuellement et introduisent donc des incompatibilités. Cependant, cela ne semble être disponible que dans CMake 3.1+
Uli Köhler
2
@ UliKöhler, ceci n'est en fait toujours pas disponible, et peut éventuellement apparaître pour certains compilateurs en 3.2. N'utilisez pas cette méthode à court terme; son complètement pas portable.
Doug
2
Une idée de comment faire cela dans CMake 2.6?
nuzzolilo
93

j'utilise

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

Mais si vous voulez jouer avec C++11, g++ 4.6.1c'est assez vieux. Essayez d'obtenir une g++version plus récente.

KoKuToru
la source
4
C'est, pour moi, la seule bonne et agréable réponse à cette question, avec cmake actuel (déployé) sur Linux le plus récent utilisant g ++.
Patrick B.19
1
Copié et collé cela et cela a fonctionné parfaitement. Je suis sur Cygwin en utilisant CMAKE 2.8.9. Je connais la plupart des approches que je lis ici parce que je suis la liste de diffusion CMAKE et que j'ai porté WebKit sur une variété de compilateurs. La chose que nous avions faite pour les ports WebKit était d'installer CMake 2.8.12. Cependant, comme je sais que le CMAKE de Cygwin est ancien, je voulais quelque chose qui s'applique à cette version. (Ne pas porter WebKit sur Cygwin, désolé)
Cardiff Space Man
Très bien, c'est un drop-in pour les anciens CMake et g ++ 4.6 (et à l'épreuve du temps). J'ai également voté en faveur des CXX_STANDARDréponses basées sur, mais c'était la seule réponse utile dans ma situation.
Tomasz Gandor
C'est exactement ce que je cherchais, mais il n'est pas clair quelle est la version minimale de cmake nécessaire pour utiliser ce module. cmake --help-module n'aide pas beaucoup à ce sujet.
Jan Segre
1
@JanSegre le module est apparu pour la première fois en 2.4, cmake.org/…
KoKuToru
57

La façon la plus simple de définir la norme Cxx est:

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

Voir la documentation de CMake pour plus de détails.

Luckyrand
la source
2
Oui, cela ressemble définitivement à l'une des meilleures façons de le faire dans CMake moderne (3.1+)
Erbureth dit Reinstate Monica
14
Ou vous pouvez simplement set(CMAKE_CXX_STANDARD 11)définir la propriété par défaut pour toutes les cibles créées après cela.
emlai
1
C'est également la solution dont vous avez besoin si vous souhaitez définir différentes normes C ++ sur différentes cibles, car la setcommande suggérée par @emlai est globale et affecte toutes les cibles suivantes.
Elliott Slaughter
40

En fait, SET(CMAKE_CXX_FLAGS "-std=c++0x")il active de nombreuses fonctionnalités C ++ 11. La raison pour laquelle cela n'a pas fonctionné était que la déclaration ressemblait à ceci:

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

Suite à cette approche, le -std=c++0xdrapeau a été en quelque sorte écrasé et cela n'a pas fonctionné. La définition des indicateurs un par un ou l'utilisation d'une méthode de liste fonctionne.

list( APPEND CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")
Subhamoy S.
la source
36
J'utilise toujours juste: SET (CMAKE_CXX_FLAGS "$ {CMAKE_CXX_FLAGS} -std = c ++ 11") # pour gcc> = 4.7, ou c ++ 0x pour 4.6
David Doria
J'ai déjà fait un petit script pour cela (pas complet cependant): github.com/Morwenn/POLDER/blob/master/cmake/set_cxx_norm.cmake
Morwenn
9
-1. Si vous spécifiez un CMAKE_CXX_FLAGS à partir de la ligne de commande, la deuxième méthode produira un point-virgule dans la commande de génération (et répétera deux fois le CMAKE_CXX_FLAGS d'origine).
Nikolai
au lieu d'ajouter manuellement l'indicateur -g, vous devez définir la variable CMAKE_BUILD_TYPE pour déboguer: voices.canonical.com/jussi.pakkanen/2013/03/26/…
bames53
1
La CXX_STANDARDpropriété est meilleure car elle est indépendante du compilateur.
jaskmar
23

La façon la plus simple:

add_compile_options(-std=c++11)

alvarez
la source
5
Uniquement disponible à partir de cmake 3.0
Raúl Salinas-Monteagudo
4
Cela provoque des avertissements et des erreurs lors de la compilation des fichiers C dans le même projet.
rosewater
19

Pour CMake 3.8 et plus récent, vous pouvez utiliser

target_compile_features(target PUBLIC cxx_std_11)
cil
la source
1
c'est la voie recommandée de la dernière version de CMake
camino
Quelle est la fonction d' PUBLICici?
Rotsiser Mho
2
@RotsiserMho PUBLICsignifie que d'autres cibles qui dépendent de votre cible utiliseront également C ++ 11. Par exemple, si votre cible est une bibliothèque, toutes les cibles liées à votre bibliothèque target_link_librariesseront compilées avec le support C ++ 11.
cil
17

Ceci est une autre façon d'activer la prise en charge de C ++ 11,

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

J'ai rencontré des cas où seule cette méthode fonctionne et d'autres méthodes échouent. Peut-être que cela a quelque chose à voir avec la dernière version de CMake.

Hindol
la source
9
Cela ne fonctionnera que si vous utilisez UNIQUEMENT le compilateur C ++. Si vous utilisez également le compilateur CC, il échouera.
Emmanuel
5
add_definitionsn'est censé être utilisé que pour ajouter des DÉFINITIONS, c'est-à-dire -D QUELQUE CHOSE. Et comme @Emmanuel l'a dit, cela ne fonctionne pas dans de nombreux cas.
xuhdev
J'ai utilisé cela auparavant, mais j'ai eu des problèmes lorsque j'ai inclus un fichier C car il add_definitionsn'était pas fait pour définir des indicateurs.
Jan Segre
17

Sur CMake moderne (> = 3.1), la meilleure façon de définir les exigences globales est:

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

Cela se traduit par "Je veux C ++ 11 pour toutes les cibles, ce n'est pas facultatif, je ne veux utiliser aucune extension GNU ou Microsoft." À partir de C ++ 17, c'est toujours à mon humble avis la meilleure façon.

Source: activation de C ++ 11 et versions ultérieures dans CMake

MateuszL
la source
1
Cette méthode n'est pas idéale pour les dernières versions de C ++ si vous ne disposez pas de la dernière version de CMake. Par exemple, vous ne pouvez pas activer C ++ 2a de cette façon avant CMake 3.12.
Ruslan
6

Ce qui fonctionne pour moi, c'est de définir la ligne suivante dans votre CMakeLists.txt:

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

La définition de cette commande active les fonctionnalités C ++ 11 pour le compilateur et après avoir exécuté la cmake ..commande, vous devriez pouvoir l'utiliser range based for loopsdans votre code et le compiler sans aucune erreur.

Kevin Katzke
la source
C'est en fin de compte la meilleure réponse si vous voulez exactement -std=c++11, tout comme set (CMAKE_CXX_STANDARD 11)le drapeau -std=gnu++11, ce qui pourrait être indésirable.
Antonio
1
@Antonioset (CMAKE_CXX_EXTENSIONS OFF)
mloskot
3

Je pense que ces deux lignes suffisent.

set(CMAKE_CXX_STANDARD 11)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
Ehsan Panahi
la source
1
Cela a du sens lorsque toutes les cibles d'un projet utilisent le même standard C ++ (toutes les bibliothèques et exécutables compilés utilisent C ++ 11, par exemple). Sinon, la target_compile_featuresfonction Cmake , appliquée à chaque cible individuelle, comme indiqué dans d'autres réponses, est une approche plus recommandée.
Allan
3

Si vous souhaitez toujours activer la dernière norme C ++, voici mon extension de la réponse de David Grayson , à la lumière des ajouts récents (CMake 3.8 et CMake 3.11) des valeurs de 17 et 20 pour 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)

(Utilisez ce code à la place de set (CMAKE_CXX_STANDARD 11)dans la réponse liée.)

codeling
la source
1

Modern cmake offre des moyens plus simples de configurer les compilateurs pour utiliser une version spécifique de C ++. La seule chose que quiconque doit faire est de définir les propriétés cibles pertinentes. Parmi les propriétés prises en charge par cmake , celles qui sont utilisées pour déterminer comment configurer les compilateurs pour prendre en charge une version spécifique de C ++ sont les suivantes:

  • CXX_STANDARDdéfinit la norme C ++ dont les fonctionnalités sont requises pour construire la cible. Définissez-le comme 11pour cibler C ++ 11.

  • CXX_EXTENSIONS, un booléen spécifiant si des extensions spécifiques au compilateur sont demandées. La définition de ce paramètre Offdésactive la prise en charge de toute extension spécifique au compilateur.

Pour démontrer, voici un exemple de travail minimal d'un 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
    )
RAM
la source
-5

Concernant OS X et Homebrew LLVM:

N'oubliez pas d'appeler cmake_minimum_required (VERSION 3.3) et project () après!

Ou CMake insérera project()implicitement avant la ligne 1, provoquant des problèmes avec la détection de version de Clang et éventuellement d'autres types de problèmes. Voici un problème connexe .

senz
la source
2
La question n'est pas spécifiquement liée à OSX ou LVVM. De plus, il n'y a aucune raison d'exiger CMake v3.x pour le développement C ++ 11. Quant à la détection de version de clang - ce n'est pas ce que OP a demandé.
einpoklum