Bagaimana cara mengaktifkan C ++ 11 di CMake?

356

Ketika saya mencoba menjalankan makefile CMake yang dihasilkan untuk mengkompilasi program saya, saya mendapatkan kesalahan itu

rentang berbasis loop tidak didukung dalam mode C ++ 98.

Saya mencoba menambahkan add_definitions(-std=c++0x)ke saya CMakeLists.txt, tetapi tidak membantu.

Saya mencoba ini juga:

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

Ketika saya melakukannya g++ --version, saya mendapatkan:

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

Saya juga sudah mencoba SET(CMAKE_CXX_FLAGS "-std=c++0x"), yang juga tidak berhasil.

Saya tidak mengerti bagaimana saya bisa mengaktifkan fitur C ++ 11 menggunakan CMake.

Subhamoy S.
sumber
11
The SET(CMAKE_CXX_FLAGS "-std=c++0x")bekerja dengan baik bagi saya, jadi mungkin ada masalah di tempat lain dalam file CMakeLists. Pastikan Anda tidak sengaja menimpa konten CMAKE_CXX_FLAGS nanti.
ComicSansMS
7
add_definitions (-std = c ++ 11) bekerja untuk saya dengan CMake 2.8.8
kyku
@ComicSansMS: Anda sepenuhnya benar! Saya menimpanya, yang merupakan kesalahan saya sendiri. Saya telah memperbaikinya, dan sekarang berfungsi dengan baik! C ++ 11 sangat keren! Saya ingin loop pada vektor struktur, yang akan memerlukan iterator dan kebisingan pengkodean yang tidak perlu jika saya tidak memiliki rentang berdasarkan untuk loop. Saya kira saya bisa menggunakan BOOST_FOREACH, tapi oh well ...
Subhamoy S.
32
Untuk CMake ≥3.1, set(CMAKE_CXX_STANDARD 11)(sebelum mendefinisikan target) adalah cara terbaik.
emlai
@tuple_cat Anda juga dapat melakukannya berdasarkan target. Tetapi berhati-hatilah karena CXX_STANDARDitu tidak bekerja pada MSVC, jadi pada dasarnya Anda harus kembali ke target_compile_featuresjika Anda menginginkan sesuatu yang bekerja lintas-platform.
Ela782

Jawaban:

395

CMake 3.1 memperkenalkan variabel CMAKE_CXX_STANDARD yang dapat Anda gunakan. Jika Anda tahu bahwa Anda akan selalu memiliki CMake 3.1, Anda bisa menulis ini di file CMakeLists.txt tingkat atas Anda, atau letakkan tepat sebelum target baru didefinisikan:

set (CMAKE_CXX_STANDARD 11)

Jika Anda perlu mendukung versi CMake yang lebih lama, ini adalah makro yang saya buat yang dapat Anda gunakan:

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 hanya mendukung GCC sekarang, tetapi harus lurus ke depan untuk memperluasnya ke kompiler lain.

Kemudian Anda bisa menulis use_cxx11()di bagian atas file CMakeLists.txt apa pun yang mendefinisikan target yang menggunakan C ++ 11.

Masalah CMake # 15943 untuk pengguna berdentang yang menargetkan macOS

Jika Anda menggunakan CMake dan dentang untuk menargetkan macOS ada bug yang dapat menyebabkan CMAKE_CXX_STANDARDfitur tidak berfungsi (tidak menambahkan flag kompiler). Pastikan Anda melakukan salah satu dari hal-hal berikut:

  • Gunakan cmake_minimum_required untuk meminta CMake 3.0 atau lebih baru, atau
  • Setel kebijakan CMP0025 ke BARU dengan kode berikut di bagian atas file CMakeLists.txt Anda sebelum projectperintah:

    # Fix behavior of CMAKE_CXX_STANDARD when targeting macOS.
    if (POLICY CMP0025)
      cmake_policy(SET CMP0025 NEW)
    endif ()
    
David Grayson
sumber
12
Ini harus menjadi jawaban yang diterima. Tidak perlu menyentuh setiap properti target secara individual, dan bekerja lintas platform.
DevSolar
4
Setuju, ini harus menjadi jawaban yang diterima pada CMake 3.1+. Sepertinya tidak bekerja untuk saya di mac. Anda dapat memaksanya untuk memberi Anda --std = c ++ 11 dengan --stdlib = libc ++, default pada Mac. Sebaliknya CMAKE_CXX_STANDARD selalu menyertakan ekstensi gnu jika didukung, dan hasilnya tampaknya tidak membangun terhadap --stdlib = libc ++. Sebagai gantinya Anda harus beralih ke gnu's --stdlib = libstdc ++. Mac adalah kasus khusus. Untuk Linux, memilih gnu ++ 11 dengan libstdc ++ adalah norma. Tentu saja, itu mudah dikoreksi dengan if (APPLE) add_compile_options () untuk menempel pada flag.
Atifm
2
Salah satu masalah dari pendekatan ini adalah yang gnu++11ditegakkan, bahkan ketika variabel-variabel ini didefinisikan set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(CMAKE_ANDROID_STL_TYPE c++_static). Bagi saya satu-satunya cara yang layak adalah klasikset (CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
Antonio
2
Tidak bekerja untuk saya di macOS (CMake 3.9.4, homebrew-clang). Menyelamatkan orang lain keputusasaan. Tidak yakin mengapa ini bekerja untuk @ EvanMoran tetapi tidak untuk saya.
Unapiedra
2
@Unapiedra: Ini adalah bug CMake tetapi Anda dapat mengatasinya, lihat gitlab.kitware.com/cmake/cmake/issues/15943
David Grayson
186

Perintah CMake target_compile_features()digunakan untuk menentukan fitur C ++ yang diperlukan cxx_range_for. CMake kemudian akan menginduksi standar C ++ untuk digunakan.

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)

Tidak perlu menggunakan add_definitions(-std=c++11)atau memodifikasi variabel CMake CMAKE_CXX_FLAGS, karena CMake akan memastikan kompiler C ++ dipanggil dengan flag baris perintah yang sesuai.

Mungkin program C ++ Anda menggunakan fitur C ++ lainnya cxx_range_for. Properti global CMake CMAKE_CXX_KNOWN_FEATURESmencantumkan fitur C ++ yang dapat Anda pilih.

Alih-alih menggunakan target_compile_features()Anda juga dapat menentukan standar C ++ secara eksplisit dengan mengatur properti CMake CXX_STANDARD dan CXX_STANDARD_REQUIREDuntuk target CMake Anda.

Lihat juga jawaban saya yang lebih terperinci .

Erik Sjölund
sumber
4
Tampaknya hasil edit dari hari ini menyesatkan. CMake 3.0.0 tidak mengandung target_compile_features. Koreksi saya jika saya salah. Saya pikir perintah hanya hadir di CMake nightly.
Erik Sjölund
4
Saya akan mengatakan ini adalah jawaban yang paling akurat
Michał Walenciak
8
Saya pikir inilah yang seharusnya dilakukan. Jawaban lainnya hanya menambahkan bendera secara manual dan karenanya memperkenalkan ketidakcocokan. Namun ini tampaknya hanya tersedia di CMake 3.1+
Uli Köhler
2
@ UliKöhler ini sebenarnya masih belum tersedia, dan mungkin dapat muncul untuk beberapa kompiler di 3.2. Jangan gunakan metode ini dalam jangka pendek; itu sama sekali tidak portabel.
Doug
2
Ada ide bagaimana melakukan ini di CMake 2.6?
nuzzolilo
93

saya menggunakan

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

Tetapi jika Anda ingin bermain dengan C++11, g++ 4.6.1sudah cukup tua. Cobalah untuk mendapatkan g++versi yang lebih baru .

KoKuToru
sumber
4
Bagi saya, ini adalah satu-satunya jawaban yang tepat dan bagus untuk pertanyaan ini, dengan cmake saat ini (diluncurkan) di Linux yang terbaru menggunakan g ++.
Patrick B.
1
Menyalin dan menempel ini dan itu bekerja dengan sempurna. Saya menggunakan Cygwin menggunakan CMAKE 2.8.9. Saya tahu tentang sebagian besar pendekatan yang saya baca di sini karena saya mengikuti milis CMAKE dan saya telah porting WebKit ke berbagai kompiler. Hal yang kami lakukan untuk port WebKit adalah menginstal CMake 2.8.12. Namun karena saya tahu CMAKE Cygwin sudah tua, saya menginginkan sesuatu yang berlaku untuk versi itu. (Tidak mengirim WebKit ke Cygwin, maaf)
cardiff space man
Hebat, ini adalah drop-in untuk CMake dan g ++ 4.6 lama (dan bukti masa depan). Saya juga memutakhirkan CXX_STANDARDjawaban berbasiskan, tetapi ini adalah satu-satunya jawaban yang berguna dalam situasi saya.
Tomasz Gandor
Ini persis apa yang saya cari, namun tidak jelas apa versi minimum cmake yang diperlukan untuk menggunakan modul itu. cmake --help-module tidak banyak membantu.
Jan Segre
1
@ JanSegre modul pertama kali muncul di 2.4, cmake.org/...
KoKuToru
57

Cara termudah untuk menetapkan standar Cxx adalah:

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

Lihat dokumentasi CMake untuk lebih jelasnya.

Luckyrand
sumber
2
Ya, ini jelas merupakan salah satu cara terbaik untuk melakukannya di CMake modern (3.1+)
Erbureth mengatakan Reinstate Monica
14
Atau Anda bisa set(CMAKE_CXX_STANDARD 11)mendefinisikan properti default untuk semua target yang dibuat setelah itu.
emlai
1
Ini juga solusi yang Anda butuhkan jika Anda ingin menetapkan standar C ++ yang berbeda pada target yang berbeda, karena setperintah yang disarankan oleh @emlai bersifat global dan memengaruhi semua target selanjutnya.
Elliott Slaughter
40

Ternyata, SET(CMAKE_CXX_FLAGS "-std=c++0x")memang mengaktifkan banyak fitur C ++ 11. Alasan itu tidak berhasil adalah pernyataan itu terlihat seperti ini:

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

Mengikuti pendekatan ini, entah bagaimana -std=c++0xbendera itu ditimpa dan itu tidak berfungsi. Mengatur bendera satu per satu atau menggunakan metode daftar berfungsi.

list( APPEND CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")
Subhamoy S.
sumber
36
Saya selalu hanya menggunakan: SET (CMAKE_CXX_FLAGS "$ {CMAKE_CXX_FLAGS} -std = c ++ 11") # untuk gcc> = 4.7, atau c ++ 0x untuk 4.6
David Doria
Saya pernah melakukan sedikit skrip untuk itu (tidak lengkap): github.com/Morwenn/POLDER/blob/master/cmake/set_cxx_norm.cmake
Morwenn
9
-1. Jika Anda menentukan CMAKE_CXX_FLAGS dari baris perintah, metode kedua akan menghasilkan titik koma di perintah build (dan ulangi CMAKE_CXX_FLAGS asli dua kali).
Nikolai
alih-alih menambahkan flag -g secara manual, Anda harus mengatur variabel CMAKE_BUILD_TYPE ke debug: voices.canonical.com/jussi.pakkanen/2013/03/26/…
bames53
1
The CXX_STANDARDproperti lebih baik karena compiler-agnostik.
jaskmar
23

Cara termudah:

add_compile_options(-std=c++11)

alvarez
sumber
5
Hanya tersedia dari cmake 3.0
Raúl Salinas-Monteagudo
4
Ini menyebabkan peringatan dan kesalahan saat mengkompilasi file C di proyek yang sama.
rosewater
19

Untuk CMake 3.8 dan yang lebih baru dapat Anda gunakan

target_compile_features(target PUBLIC cxx_std_11)
bulu mata
sumber
1
ini adalah cara yang direkomendasikan untuk versi terbaru CMake
camino
Apa fungsi di PUBLICsini?
Rotsiser Mho
2
@RotsiserMho PUBLICberarti bahwa target lain yang bergantung pada target Anda akan menggunakan C ++ 11 juga. Misalnya jika target Anda adalah pustaka, maka semua target yang terhubung dengan pustaka Anda target_link_librariesakan dikompilasi dengan dukungan C ++ 11.
bulu mata
17

Ini adalah cara lain untuk mengaktifkan dukungan C ++ 11,

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

Saya telah menemukan contoh di mana hanya metode ini bekerja dan metode lain gagal. Mungkin ada hubungannya dengan CMake versi terbaru.

Hindol
sumber
9
Itu hanya akan berfungsi jika Anda HANYA menggunakan kompiler C ++. Jika Anda juga menggunakan kompiler CC itu akan gagal.
Emmanuel
5
add_definitionsseharusnya hanya digunakan untuk menambahkan DEFINISI, yaitu -D SESUATU. Dan seperti yang dikatakan @Emmanuel, itu tidak berfungsi dalam banyak kasus.
xuhdev
Saya menggunakan itu sebelumnya tetapi memiliki masalah ketika saya memasukkan file C karena add_definitionstidak dibuat untuk mengatur bendera.
Jan Segre
17

Pada CMake modern (> = 3.1) cara terbaik untuk menetapkan persyaratan global adalah:

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

Ini diterjemahkan menjadi "Saya ingin C ++ 11 untuk semua target, ini bukan opsional, saya tidak ingin menggunakan ekstensi GNU atau Microsoft." Pada C ++ 17, ini masih IMHO cara terbaik.

Sumber: Mengaktifkan C ++ 11 Dan Selanjutnya Di CMake

MateuszL
sumber
1
Cara ini tidak ideal untuk versi terbaru C ++ jika Anda tidak memiliki CMake terbaru. Misalnya Anda tidak dapat mengaktifkan C ++ 2a dengan cara ini hingga CMake 3.12.
Ruslan
6

Apa yang berhasil bagi saya adalah mengatur baris berikut di CMakeLists.txt Anda:

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

Mengatur perintah ini mengaktifkan fitur C ++ 11 untuk kompiler dan setelah menjalankan cmake ..perintah, Anda harus dapat menggunakan range based for loopskode Anda dan mengompilasinya tanpa kesalahan.

Kevin Katzke
sumber
Ini pada akhirnya adalah jawaban terbaik jika Anda ingin tepat -std=c++11, seperti set (CMAKE_CXX_STANDARD 11)akan menggunakan bendera -std=gnu++11, yang mungkin tidak diinginkan.
Antonio
1
@Antonioset (CMAKE_CXX_EXTENSIONS OFF)
mloskot
3

Saya pikir hanya dua baris ini sudah cukup.

set(CMAKE_CXX_STANDARD 11)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
Ehsan Panahi
sumber
1
Ini masuk akal ketika semua target dalam proyek menggunakan standar C ++ yang sama (semua pustaka yang dikompilasi dan executable menggunakan C ++ 11, misalnya). Kalau tidak, target_compile_featuresfungsi Cmake , diterapkan untuk setiap target individu, seperti yang ditunjukkan dalam jawaban lain, adalah pendekatan yang lebih direkomendasikan.
Allan
3

Jika Anda ingin selalu mengaktifkan standar C ++ terbaru, berikut ini ekstensi saya dari jawaban David Grayson , mengingat penambahan baru-baru ini (CMake 3.8 dan CMake 3.11) dari nilai 17 dan 20 untuk 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)

(Gunakan kode itu sebagai pengganti set (CMAKE_CXX_STANDARD 11)jawaban yang ditautkan.)

pembuatan kode
sumber
1

Cmake modern menawarkan cara yang lebih sederhana untuk mengonfigurasi kompiler untuk menggunakan versi khusus C ++. Satu-satunya hal yang perlu dilakukan oleh siapa pun adalah mengatur properti target yang relevan. Di antara properti yang didukung oleh cmake , yang digunakan untuk menentukan cara mengonfigurasi kompiler untuk mendukung versi C ++ tertentu adalah sebagai berikut:

  • CXX_STANDARDmenetapkan standar C ++ yang fitur-fiturnya diminta untuk membangun target. Tetapkan ini sebagai 11untuk menargetkan C ++ 11.

  • CXX_EXTENSIONS, boolean yang menentukan apakah ekstensi spesifik kompiler diminta. Menetapkan ini sebagai Offmenonaktifkan dukungan untuk ekstensi spesifik-kompiler.

Untuk menunjukkan, berikut adalah contoh kerja minimal dari 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
sumber
-5

Terkait OS X dan Homebrew LLVM:

Jangan lupa untuk memanggil cmake_minimum_required (VERSION 3.3) dan proyek () setelah itu!

Atau CMake akan memasukkan project()secara implisit sebelum baris 1, menyebabkan masalah dengan deteksi versi Dentang dan kemungkinan jenis masalah lainnya. Ini masalah terkait .

senz
sumber
2
Pertanyaannya tidak terkait OSX atau LVVM, khususnya. Juga, tidak ada alasan untuk meminta CMake v3.x untuk pengembangan C ++ 11. Adapun deteksi versi dentang - bukan itu yang ditanyakan OP.
einpoklum