¿Cómo activo C ++ 11 en CMake?

356

Cuando intento ejecutar un archivo MAKE generado por CMake para compilar mi programa, aparece el error que

el rango basado en bucles no se admite en el modo C ++ 98.

Traté de agregar add_definitions(-std=c++0x)a mi CMakeLists.txt, pero no me ayudó.

Intenté esto también:

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

Cuando lo hago g++ --version, obtengo:

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

También lo he intentado SET(CMAKE_CXX_FLAGS "-std=c++0x"), lo que tampoco funciona.

No entiendo cómo puedo activar las funciones de C ++ 11 usando CMake.

Subhamoy S.
fuente
11
El SET(CMAKE_CXX_FLAGS "-std=c++0x")bien funciona para mí, por lo que es probablemente un problema en otro lugar en el archivo CMakeLists. Asegúrese de no sobrescribir accidentalmente el contenido de CMAKE_CXX_FLAGS más adelante.
ComicSansMS
77
add_definitions (-std = c ++ 11) funciona para mí con CMake 2.8.8
kyku
@ComicSansMS: ¡Tienes toda la razón! Lo sobrescribí, que fue mi propio error. Lo he corregido, ¡y ahora funciona bien! ¡C ++ 11 cosas es muy genial! Quería hacer un bucle en un vector de estructuras, lo que requeriría un iterador y un ruido de codificación innecesario si no tuviera un rango basado en bucles. Aunque creo que podría usar BOOST_FOREACH, pero bueno ...
Subhamoy S.
32
Para CMake ≥3.1, set(CMAKE_CXX_STANDARD 11)(antes de definir el objetivo) es la mejor manera.
emlai
@tuple_cat También puedes hacerlo basado en objetivos. Pero tenga en cuenta que CXX_STANDARDlo hace no trabajo en MSVC, así que básicamente tiene que caer de nuevo a target_compile_featuressi quieres algo que funciona multiplataforma.
Ela782

Respuestas:

395

CMake 3.1 introdujo la variable CMAKE_CXX_STANDARD que puede usar. Si sabe que siempre tendrá CMake 3.1 disponible, puede escribir esto en su archivo CMakeLists.txt de nivel superior, o ponerlo justo antes de definir un nuevo objetivo:

set (CMAKE_CXX_STANDARD 11)

Si necesita admitir versiones anteriores de CMake, aquí hay una macro que se me ocurrió que puede usar:

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 solo es compatible con GCC en este momento, pero debería ser sencillo expandirla a otros compiladores.

Luego, podría escribir use_cxx11()en la parte superior de cualquier archivo CMakeLists.txt que defina un destino que use C ++ 11.

CMake problema # 15943 para usuarios clang dirigidos a macOS

Si está utilizando CMake y clang para apuntar a macOS, hay un error que puede hacer que la CMAKE_CXX_STANDARDfunción simplemente no funcione (no agregue ningún indicador del compilador). Asegúrese de hacer una de las siguientes cosas:

  • Utilice cmake_minimum_required para requerir CMake 3.0 o posterior, o
  • Establezca la política CMP0025 en NUEVO con el siguiente código en la parte superior de su archivo CMakeLists.txt antes del projectcomando:

    # Fix behavior of CMAKE_CXX_STANDARD when targeting macOS.
    if (POLICY CMP0025)
      cmake_policy(SET CMP0025 NEW)
    endif ()
    
David Grayson
fuente
12
Esta debería ser la respuesta aceptada. No requiere tocar las propiedades de cada objetivo individualmente, y funciona multiplataforma.
DevSolar
44
De acuerdo, esta debería ser la respuesta aceptada a partir de CMake 3.1+. Sin embargo, no parece funcionar para mí en Mac. Puede forzarlo a que le dé --std = c ++ 11 con --stdlib = libc ++, el valor predeterminado en Mac. En cambio, CMAKE_CXX_STANDARD siempre incluye las extensiones gnu si son compatibles, y el resultado no parece compilarse contra --stdlib = libc ++. En su lugar, debe cambiar a gnu's --stdlib = libstdc ++. Sin embargo, la Mac es el caso especial. Para Linux, elegir gnu ++ 11 con libstdc ++ es la norma. Por supuesto, eso se corrige fácilmente con un if (APPLE) add_compile_options () para agregar las banderas.
Atifm
2
Un problema de este enfoque es que gnu++11se aplica, incluso cuando se definen estas variables set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(CMAKE_ANDROID_STL_TYPE c++_static). Para mí, la única forma viable era el clásicoset (CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
Antonio
2
No funciona para mí en macOS (CMake 3.9.4, homebrew-clang). Salvar a otros la desesperación. No estoy seguro de por qué funciona para @EvanMoran pero no para mí.
Unapiedra
2
@Unapiedra: es un error de CMake, pero puede solucionarlo
David Grayson el
186

El comando CMake target_compile_features()se usa para especificar la función C ++ requerida cxx_range_for. CMake inducirá el estándar C ++ que se utilizará.

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)

No es necesario usar add_definitions(-std=c++11)o modificar la variable CMake CMAKE_CXX_FLAGS, porque CMake se asegurará de que se invoque el compilador de C ++ con los indicadores de línea de comando apropiados.

Tal vez su programa C ++ usa otras características de C ++ que cxx_range_for. La propiedad global CMake CMAKE_CXX_KNOWN_FEATURESenumera las características de C ++ que puede elegir.

En lugar de usar target_compile_features(), también puede especificar el estándar C ++ explícitamente estableciendo las propiedades de CMake CXX_STANDARD y CXX_STANDARD_REQUIREDpara su objetivo CMake.

Vea también mi respuesta más detallada .

Erik Sjölund
fuente
44
Parece que la edición de hoy es engañosa. CMake 3.0.0 no contiene target_compile_features. Corrígeme si estoy equivocado. Creo que el comando solo está presente en las versiones nocturnas de CMake.
Erik Sjölund
44
Yo diría que esta es la respuesta más precisa
Michał Walenciak
8
Creo que así es como se supone que debe hacer. Las otras respuestas simplemente agregan indicadores manualmente y, por lo tanto, introducen incompatibilidades. Sin embargo, esto parece estar solo disponible en CMake 3.1+
Uli Köhler
2
@ UliKöhler, esto todavía no está disponible, y posiblemente aparezca en algunos compiladores en 3.2. No use este método a corto plazo; No es completamente portátil.
Doug
2
¿Alguna idea de cómo hacer esto en CMake 2.6?
nuzzolilo
93

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

Pero si quieres jugar C++11, g++ 4.6.1es bastante viejo. Intenta obtener una g++versión más nueva .

KoKuToru
fuente
44
Esta es, para mí, la única respuesta correcta y agradable a esta pregunta, con el cmake actual (implementado) en la versión más reciente de Linux usando g ++.
Patrick B.
1
Copié y pegué esto y funcionó perfectamente. Estoy en Cygwin usando CMAKE 2.8.9. Sé sobre la mayoría de los enfoques que estoy leyendo aquí porque sigo la lista de correo CMAKE y he portado WebKit a una variedad de compiladores. Lo que habíamos hecho para los puertos WebKit fue instalar CMake 2.8.12. Sin embargo, porque sé que CMAKE de Cygwin es viejo, quería algo que se aplicara a esa versión. (No portar WebKit a Cygwin, lo siento)
cardiff space man
Genial, este es un complemento para CMake antiguo y g ++ 4.6 (y a prueba de futuro). También voté por las CXX_STANDARDrespuestas basadas en, pero esta fue la única respuesta útil en mi situación.
Tomasz Gandor
Esto es exactamente lo que estaba buscando, sin embargo, no está claro cuál es la versión mínima de cmake necesaria para usar ese módulo. cmake --help-module no ayuda mucho al respecto.
Jan Segre
1
@ JanSegre, el módulo apareció por primera vez en 2.4, cmake.org/…
KoKuToru
57

La forma más fácil de establecer el estándar Cxx es:

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

Consulte la documentación de CMake para más detalles.

Luckyrand
fuente
2
Sí, esta definitivamente parece una de las mejores maneras de hacerlo en CMake moderno (3.1+)
Erbureth dice que reinstala a Monica
14
O simplemente puede set(CMAKE_CXX_STANDARD 11)definir la propiedad predeterminada para todos los objetivos creados después de eso.
emlai
1
Esta es también la solución que necesita si desea establecer diferentes estándares de C ++ en diferentes objetivos, porque el setcomando sugerido por @emlai es global y afecta a todos los objetivos posteriores.
Elliott Slaughter
40

Como resultado, SET(CMAKE_CXX_FLAGS "-std=c++0x")activa muchas características de C ++ 11. La razón por la que no funcionó fue porque la declaración se veía así:

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

Siguiendo este enfoque, de alguna manera -std=c++0xse sobrescribió la bandera y no funcionó. Establecer las banderas una por una o usar un método de lista está funcionando.

list( APPEND CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")
Subhamoy S.
fuente
36
Siempre uso: SET (CMAKE_CXX_FLAGS "$ {CMAKE_CXX_FLAGS} -std = c ++ 11") # para gcc> = 4.7, o c ++ 0x para 4.6
David Doria
Una vez hice un pequeño script para eso (aunque no está completo): github.com/Morwenn/POLDER/blob/master/cmake/set_cxx_norm.cmake
Morwenn
99
-1. Si especifica cualquier CMAKE_CXX_FLAGS desde la línea de comando, el segundo método producirá un punto y coma en el comando de compilación (y repetirá el CMAKE_CXX_FLAGS original dos veces).
Nikolai
en lugar de agregar manualmente el indicador -g, debe configurar la variable CMAKE_BUILD_TYPE para depurar: voices.canonical.com/jussi.pakkanen/2013/03/26/…
bames53
1
La CXX_STANDARDpropiedad es mejor ya que es independiente del compilador.
jaskmar
23

La forma más fácil:

add_compile_options(-std=c++11)

Alvarez
fuente
55
Solo disponible en cmake 3.0
Raúl Salinas-Monteagudo
44
Esto provoca advertencias y errores al compilar archivos C en el mismo proyecto.
Rosewater
19

Para CMake 3.8 y posteriores puedes usar

target_compile_features(target PUBLIC cxx_std_11)
pestaña
fuente
1
esta es la forma recomendada de la última versión de CMake
camino
¿Cuál es la función de PUBLICaquí?
Rotsiser Mho
2
@RotsiserMho PUBLICsignifica que otros objetivos que dependen de su objetivo también usarán C ++ 11. Por ejemplo, si su objetivo es una biblioteca, todos los objetivos que se vinculen con su biblioteca target_link_librariesse compilarán con compatibilidad con C ++ 11.
pestañas
17

Esta es otra forma de habilitar el soporte de C ++ 11,

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

He encontrado casos en los que solo funciona este método y otros métodos fallan. Quizás tenga algo que ver con la última versión de CMake.

Hindol
fuente
99
Eso solo funcionará si SOLO está utilizando el compilador de C ++. Si también está utilizando el compilador CC, fallará.
Emmanuel
55
add_definitionsse supone que solo se usa para agregar DEFINICIONES, es decir, -D ALGO. Y como dijo @Emmanuel, en muchos casos no funciona.
Xuhdev
Lo usé antes, pero tuve problemas cuando incluí un archivo C porque add_definitionsno estaba hecho para configurar banderas.
Jan Segre
17

En CMake moderno (> = 3.1), la mejor manera de establecer requisitos globales es:

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

Se traduce como "Quiero C ++ 11 para todos los objetivos, no es opcional, no quiero usar ninguna extensión de GNU o Microsoft". A partir de C ++ 17, esto sigue siendo en mi humilde opinión la mejor manera.

Fuente: Habilitación de C ++ 11 y posterior en CMake

MateuszL
fuente
1
De esta manera, no es ideal para las versiones más nuevas de C ++ si no tiene la última versión de CMake. Por ejemplo, no puede habilitar C ++ 2a de esta manera hasta CMake 3.12.
Ruslan
6

Lo que funciona para mí es establecer la siguiente línea en su CMakeLists.txt:

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

Al configurar este comando, se activan las funciones de C ++ 11 para el compilador y, después de ejecutar el cmake ..comando, debe poder usar range based for loopssu código y compilarlo sin ningún error.

Kevin Katzke
fuente
Al final, esta es la mejor respuesta si lo desea exactamente -std=c++11, ya set (CMAKE_CXX_STANDARD 11)que usará la bandera -std=gnu++11, que podría ser indeseable.
Antonio
1
@Antonioset (CMAKE_CXX_EXTENSIONS OFF)
mloskot
3

Creo que solo estas dos líneas son suficientes.

set(CMAKE_CXX_STANDARD 11)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
Ehsan Panahi
fuente
1
Esto tiene sentido cuando todos los objetivos en un proyecto usan el mismo estándar C ++ (todas las bibliotecas compiladas y ejecutables usan C ++ 11, por ejemplo). De lo contrario, la target_compile_featuresfunción Cmake , aplicada para cada objetivo individual, como se muestra en otras respuestas, es un enfoque más recomendado.
Allan
3

En caso de que quiera activar siempre el último estándar de C ++, aquí está mi extensión de la respuesta de David Grayson , a la luz de las recientes (CMake 3.8 y CMake 3.11) adiciones de valores de 17 y 20 para 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)

(Use ese código en lugar de set (CMAKE_CXX_STANDARD 11)en la respuesta vinculada).

codeling
fuente
1

El cmake moderno ofrece formas más simples de configurar compiladores para usar una versión específica de C ++. Lo único que alguien debe hacer es establecer las propiedades de destino relevantes. Entre las propiedades compatibles con cmake , las que se utilizan para determinar cómo configurar compiladores para admitir una versión específica de C ++ son las siguientes:

  • CXX_STANDARDestablece el estándar C ++ cuyas características se solicitan para construir el objetivo. Establezca esto como 11objetivo C ++ 11.

  • CXX_EXTENSIONS, un valor booleano que especifica si se solicitan extensiones específicas del compilador. Establecer esto como Offdeshabilita el soporte para cualquier extensión específica del compilador.

Para demostrar, aquí hay un ejemplo mínimo de trabajo de 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
    )
RAM
fuente
-5

OS X y Homebrew LLVM relacionados:

¡No olvides llamar a cmake_minimum_required (VERSION 3.3) y project () después!

O CMake se insertará project()implícitamente antes de la línea 1, causando problemas con la detección de la versión de Clang y posiblemente otros tipos de problemas. Aquí hay un problema relacionado .

senz
fuente
2
La pregunta no está relacionada con OSX o LVVM, específicamente. Además, no hay razón para requerir CMake v3.x para el desarrollo de C ++ 11. En cuanto a la detección de versiones de clang, eso no es lo que OP preguntó.
einpoklum