Como ativo o C ++ 11 no CMake?

356

Quando tento executar um makefile gerado pelo CMake para compilar meu programa, recebo o erro que

o intervalo baseado em loops não é suportado no modo C ++ 98.

Tentei adicionar add_definitions(-std=c++0x)ao meu CMakeLists.txt, mas não ajudou.

Eu tentei isso também:

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

Quando eu faço g++ --version, recebo:

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

Eu também tentei SET(CMAKE_CXX_FLAGS "-std=c++0x"), o que também não funciona.

Não entendo como posso ativar os recursos do C ++ 11 usando o CMake.

Subhamoy S.
fonte
11
O SET(CMAKE_CXX_FLAGS "-std=c++0x")fino trabalha para mim, então provavelmente há um problema em algum outro lugar no arquivo CMakeLists. Certifique-se de não substituir acidentalmente o conteúdo de CMAKE_CXX_FLAGS posteriormente.
ComicSansMS
7
add_definitions (-std = c ++ 11) funciona para mim com CMake 2.8.8
kyku
@ComicSansMS: Você está totalmente certo! Eu o substitui, o que foi meu próprio erro. Eu o corrigi e agora está funcionando bem! O material C ++ 11 é muito legal! Eu queria fazer um loop em um vetor de estruturas, o que exigiria iterador e ruído de codificação desnecessário se eu não tivesse um intervalo baseado em loops. Acho que eu poderia usar o BOOST_FOREACH, mas tudo bem ...
Subhamoy S.
32
Para o CMake ≥3,1, set(CMAKE_CXX_STANDARD 11)(antes de definir o alvo) é o melhor caminho.
emlai
@tuple_cat Você também pode fazer isso com base no destino. Mas esteja ciente de que CXX_STANDARDfaz não trabalho em MSVC, então basicamente você tem que cair de volta para target_compile_featuresse você quer algo que funciona em várias plataformas.
precisa saber é o seguinte

Respostas:

395

O CMake 3.1 introduziu a variável CMAKE_CXX_STANDARD que você pode usar. Se você sabe que sempre terá o CMake 3.1 disponível, basta escrevê-lo no seu arquivo CMakeLists.txt de nível superior ou corrigi-lo antes que qualquer novo destino seja definido:

set (CMAKE_CXX_STANDARD 11)

Se você precisar oferecer suporte a versões mais antigas do CMake, aqui está uma macro que você pode 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)

A macro suporta apenas o GCC no momento, mas deve ser simples expandi-la para outros compiladores.

Em seguida, você pode escrever use_cxx11()na parte superior de qualquer arquivo CMakeLists.txt que defina um destino que use C ++ 11.

Problema no CMake # 15943 para usuários de clang que segmentam o macOS

Se você estiver usando o CMake e clang para segmentar o macOS, há um erro que pode fazer com que o CMAKE_CXX_STANDARDrecurso simplesmente não funcione (não adicione nenhum sinalizador do compilador). Certifique-se de executar um dos seguintes procedimentos:

  • Use cmake_minimum_required para exigir o CMake 3.0 ou posterior, ou
  • Defina a política CMP0025 como NEW com o seguinte código na parte superior do arquivo CMakeLists.txt antes do projectcomando:

    # Fix behavior of CMAKE_CXX_STANDARD when targeting macOS.
    if (POLICY CMP0025)
      cmake_policy(SET CMP0025 NEW)
    endif ()
    
David Grayson
fonte
12
Essa deve ser a resposta aceita. Não requer tocar nas propriedades de cada alvo individualmente e funciona em várias plataformas.
precisa saber é o seguinte
4
Concordado, essa deve ser a resposta aceita no CMake 3.1+. Parece não funcionar para mim no mac. Você pode forçá-lo a fornecer a você --std = c ++ 11 com --stdlib = libc ++, o padrão no Mac. Em vez disso, o CMAKE_CXX_STANDARD sempre inclui as extensões gnu, se suportadas, e o resultado não parece ser construído contra --stdlib = libc ++. Em vez disso, você precisa mudar para o gnu --stdlib = libstdc ++. O Mac é o caso especial. Para Linux, escolher o gnu ++ 11 com libstdc ++ é a norma. Obviamente, isso é facilmente corrigido com um if (APPLE) add_compile_options () para colocar as bandeiras.
Atifm 23/05
2
Um problema dessa abordagem é a gnu++11imposição, mesmo quando essas variáveis ​​são definidas set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(CMAKE_ANDROID_STL_TYPE c++_static). Para mim, o único caminho viável era o clássicoset (CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
Antonio
2
Não funciona para mim no macOS (CMake 3.9.4, homebrew-clang). Salvando os outros o desespero. Não sei por que funciona para @EvanMoran, mas não para mim.
Unapiedra
2
@Unapiedra: É um bug CMake mas você pode trabalhar em torno dele, ver gitlab.kitware.com/cmake/cmake/issues/15943
David Grayson
186

O comando CMake target_compile_features()é usado para especificar o recurso C ++ necessário cxx_range_for. O CMake induz o padrão C ++ a ser usado.

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)

Não há necessidade de usar add_definitions(-std=c++11)ou modificar a variável CMake CMAKE_CXX_FLAGS, porque o CMake garantirá que o compilador C ++ seja chamado com os sinalizadores de linha de comando apropriados.

Talvez o seu programa C ++ use outros recursos do C ++ que não cxx_range_for. A propriedade global CMake CMAKE_CXX_KNOWN_FEATURESlista os recursos do C ++ que você pode escolher.

Em vez de usar, target_compile_features()você também pode especificar explicitamente o padrão C ++, definindo as propriedades do CMake CXX_STANDARD e CXX_STANDARD_REQUIREDpara o seu destino no CMake.

Veja também minha resposta mais detalhada .

Erik Sjölund
fonte
4
Parece que a edição de hoje é enganosa. O CMake 3.0.0 não contém target_compile_features. Corrija-me se eu estiver errado. Eu acho que o comando está presente apenas nas versões noturnas do CMake.
Erik Sjölund
4
Eu diria que esta é a resposta mais precisa
Michał Walenciak
8
Eu acho que é assim que deve ser feito. As outras respostas apenas adicionam sinalizadores manualmente e, portanto, introduzem incompatibilidades. No entanto, isso parece estar disponível apenas no CMake 3.1+
Uli Köhler
2
@ UliKöhler isso ainda não está disponível e pode aparecer para alguns compiladores no 3.2. Não use esse método a curto prazo; não é completamente portátil.
Doug
2
Alguma idéia de como fazer isso no CMake 2.6?
Nzololilo
93

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

Mas se você quiser brincar C++11, g++ 4.6.1é bem antigo. Tente obter uma g++versão mais recente.

KoKuToru
fonte
4
Esta é, para mim, a única resposta correta e agradável para esta pergunta, com o cmake atual (lançado) no Linux mais recente 'usando g ++.
Patrick B.
11
Copiou e colou isso e funcionou perfeitamente. Estou no Cygwin usando o CMAKE 2.8.9. Conheço a maioria das abordagens que estou lendo aqui, porque sigo a lista de discussão do CMAKE e levei o WebKit para uma variedade de compiladores. O que fizemos para as portas do WebKit foi instalar o CMake 2.8.12. No entanto, como sei que o CMAKE da Cygwin é antigo, eu queria algo que se aplicasse a essa versão. (Não portando WebKit para Cygwin, desculpe)
cardiff space man
Ótimo, este é um exemplo para o antigo CMake e g ++ 4.6 (e à prova de futuro). Também votei nas CXX_STANDARDrespostas baseadas em votos , mas essa foi a única resposta útil na minha situação.
Tomasz Gandor
Isso é exatamente o que eu estava procurando, no entanto, não está claro qual é a versão mínima do cmake necessária para usar esse módulo. O cmake --help-module não ajuda muito nisso.
Jan Segre
11
@JanSegre o módulo apareceu primeiro em 2,4, cmake.org/...
KoKuToru
57

A maneira mais fácil de definir o padrão Cxx é:

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

Consulte a documentação do CMake para obter mais detalhes.

Luckyrand
fonte
2
Sim, isso definitivamente parece uma das melhores maneiras de fazê-lo no CMake moderno (3.1+)
Erbureth diz Reinstate Monica
14
Ou você pode apenas set(CMAKE_CXX_STANDARD 11)definir a propriedade padrão para todos os destinos criados depois disso.
emlai
11
Essa também é a solução que você precisa se deseja definir diferentes padrões de C ++ em diferentes destinos, porque o setcomando sugerido por @emlai é global e afeta todos os destinos subsequentes.
Elliott Slaughter
40

Como se vê, SET(CMAKE_CXX_FLAGS "-std=c++0x")ativa muitos recursos do C ++ 11. O motivo pelo qual não funcionou foi que a declaração era assim:

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

Seguindo essa abordagem, de alguma forma a -std=c++0xbandeira foi substituída e não funcionou. Definir os sinalizadores um por um ou usar um método de lista está funcionando.

list( APPEND CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")
Subhamoy S.
fonte
36
Eu sempre apenas usar: SET (CMAKE_CXX_FLAGS "$ {CMAKE_CXX_FLAGS} -std = c ++ 11") # para gcc> = 4,7, ou c ++ 0x para 4,6
David Doria
Uma vez fiz um pequeno script para que (embora não completa): github.com/Morwenn/POLDER/blob/master/cmake/set_cxx_norm.cmake
Morwenn
9
-1. Se você especificar qualquer CMAKE_CXX_FLAGS na linha de comando, o segundo método produzirá um ponto-e-vírgula no comando build (e repita o CMAKE_CXX_FLAGS original duas vezes).
Nikolai
em vez de adicionar manualmente o sinalizador -g, defina a variável CMAKE_BUILD_TYPE para depurar: voices.canonical.com/jussi.pakkanen/2013/03/26/…
bames53
11
A CXX_STANDARDpropriedade é melhor, pois é independente do compilador.
Jaskmar
23

O jeito mais fácil:

add_compile_options(-std=c++11)

alvarez
fonte
5
Apenas disponível a partir de cmake 3.0
Raúl Salinas-Monteagudo
4
Isso causa aviso e erros ao compilar arquivos C no mesmo projeto.
rosewater
19

Para o CMake 3.8 e mais recente, você pode usar

target_compile_features(target PUBLIC cxx_std_11)
Cílio
fonte
11
esta é a maneira recomendada de versão mais recente do CMake
camino
Qual é a função PUBLICdaqui?
Rotsiser Mho,
2
@RotsiserMho PUBLICsignifica que outros destinos que dependem do seu destino também usarão o C ++ 11. Por exemplo, se o seu destino for uma biblioteca, todos os destinos vinculados à sua biblioteca target_link_librariesserão compilados com o suporte ao C ++ 11.
Eyelash
17

Essa é outra maneira de ativar o suporte ao C ++ 11,

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

Eu encontrei instâncias em que apenas esse método funciona e outros métodos falham. Talvez tenha algo a ver com a versão mais recente do CMake.

Hindol
fonte
9
Isso só funcionará se você estiver usando SOMENTE o compilador C ++. Se você também estiver usando o compilador CC, ele falhará.
Emmanuel
5
add_definitionsdeve ser usado apenas para adicionar DEFINIÇÕES, ou seja, -D ALGO. E como o @Emmanuel disse, isso não funciona em muitos casos.
xuhdev
Eu usei isso antes, mas tive problemas quando incluí um arquivo C porque add_definitionsnão foi criado para definir sinalizadores.
Jan Segre
17

No CMake moderno (> = 3.1), a melhor maneira de definir requisitos globais é:

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

É traduzido como "Quero C ++ 11 para todos os destinos, não é opcional, não quero usar nenhuma extensão GNU ou Microsoft". A partir do C ++ 17, este ainda é o IMHO da melhor maneira.

Fonte: Habilitando o C ++ 11 e posterior no CMake

MateuszL
fonte
11
Dessa forma, não é ideal para as versões mais recentes do C ++, se você não tiver o CMake mais recente. Por exemplo, você não pode ativar o C ++ 2a dessa maneira até o CMake 3.12.
Ruslan
6

O que funciona para mim é definir a seguinte linha no seu CMakeLists.txt:

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

A configuração desse comando ativa os recursos do C ++ 11 para o compilador e, após a execução do cmake ..comando, você poderá usar range based for loopsseu código e compilá-lo sem erros.

Kevin Katzke
fonte
No final, essa é a melhor resposta, se você quiser exatamente -std=c++11, pois set (CMAKE_CXX_STANDARD 11)usará a bandeira -std=gnu++11, o que pode ser indesejável.
Antonio
11
@Antonioset (CMAKE_CXX_EXTENSIONS OFF)
mloskot
3

Eu acho que apenas essas duas linhas são suficientes.

set(CMAKE_CXX_STANDARD 11)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
Ehsan Panahi
fonte
11
Isso faz sentido quando todos os destinos em um projeto usam o mesmo padrão C ++ (todas as bibliotecas e executáveis ​​compilados usam C ++ 11, por exemplo). Caso contrário, a target_compile_featuresfunção Cmake , aplicada a cada destino individual, como mostrado em outras respostas, é uma abordagem mais recomendada.
Allan
3

Caso você deseje sempre ativar o padrão C ++ mais recente, aqui está minha extensão da resposta de David Grayson , à luz das recentes adições (CMake 3.8 e CMake 3.11) dos valores 17 e 20 para CMAKE_CXX_STANDARD (CMake 3.8 e CMake 3.11):

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 esse código no lugar de set (CMAKE_CXX_STANDARD 11)na resposta vinculada.)

codeling
fonte
1

O cmake moderno oferece maneiras mais simples de configurar os compiladores para usar uma versão específica do C ++. A única coisa que alguém precisa fazer é definir as propriedades de destino relevantes. Entre as propriedades suportadas pelo cmake , as usadas para determinar como configurar os compiladores para dar suporte a uma versão específica do C ++ são as seguintes:

  • CXX_STANDARDdefine o padrão C ++ cujos recursos são solicitados para criar o destino. Defina isso como 11destino C ++ 11.

  • CXX_EXTENSIONS, um booleano que especifica se extensões específicas do compilador são solicitadas. Definir isso como Offdesabilita o suporte a qualquer extensão específica do compilador.

Para demonstrar, aqui está um exemplo de trabalho mínimo 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
fonte
-5

Relacionados com OS X e Homebrew LLVM:

Não se esqueça de chamar cmake_minimum_required (VERSÃO 3.3) e project () depois!

Ou o CMake será inserido project()implicitamente antes da linha 1, causando problemas na detecção da versão do Clang e possivelmente em outros tipos de problemas. Aqui está uma questão relacionada .

senz
fonte
2
A questão não está relacionada ao OSX ou LVVM, especificamente. Além disso, não há razão para exigir o CMake v3.x para o desenvolvimento do C ++ 11. Quanto à detecção de versão clang - não foi sobre isso que o OP perguntou.
einpoklum