Як активувати C ++ 11 в CMake?


356

Коли я намагаюся запустити створений CMake makefile для компіляції своєї програми, я отримую помилку в цьому

діапазон на основі циклів не підтримується в режимі C ++ 98.

Я спробував додати add_definitions(-std=c++0x)до свого CMakeLists.txt, але це не допомогло.

Я також спробував це:

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

Коли я це роблю g++ --version, я отримую:

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

Я також спробував SET(CMAKE_CXX_FLAGS "-std=c++0x"), що теж не працює.

Я не розумію, як я можу активувати функції C ++ 11 за допомогою CMake.


11
Для SET(CMAKE_CXX_FLAGS "-std=c++0x")мене добре працює, тому, ймовірно, є проблема десь у файлі CMakeLists. Переконайтеся, що згодом ви випадково не перезаписуєте вміст CMAKE_CXX_FLAGS.
ComicSansMS

7
add_definitions (-std = c ++ 11) працює для мене з CMake 2.8.8
kyku

@ComicSansMS: Ви абсолютно праві! Я це перекреслив, що було моєю власною помилкою. Я це виправив, і зараз він працює чудово! C ++ 11 речей дуже круто! Я хотів зациклитися на векторі структур, який потребував би ітератора та непотрібного шуму кодування, якби у мене не було діапазону на основі циклів. Напевно, я міг би використовувати BOOST_FOREACH, але добре ...
Subhamoy S.

32
Для CMake ≥3,1 set(CMAKE_CXX_STANDARD 11)(до визначення цілі) - найкращий спосіб.
emlai

@tuple_cat Ви також можете це зробити на основі цілі. Але майте на увазі, що CXX_STANDARDце не працює на MSVC, тому в основному вам доведеться відмовитися, target_compile_featuresякщо ви хочете щось, що працює на крос-платформі.
Ela782

Відповіді:


395

CMake 3.1 представив змінну CMAKE_CXX_STANDARD, яку ви можете використовувати. Якщо ви знаєте, що у вас завжди буде доступний CMake 3.1, ви можете просто записати це у свій файл CMakeLists.txt верхнього рівня або поставити його прямо до того, як буде визначено будь-яку нову ціль:

set (CMAKE_CXX_STANDARD 11)

Якщо вам потрібно підтримувати старіші версії CMake, ось макрос, який я придумав, який ви можете використовувати:

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)

Макрос підтримує GCC лише зараз, але слід розширити його на інші компілятори.

Тоді ви можете написати use_cxx11()вгорі будь-який файл CMakeLists.txt, який визначає ціль, яка використовує C ++ 11.

Випуск CMake № 15943 для кланг-користувачів, орієнтованих на macOS

Якщо ви використовуєте CMake та clang для націлювання на macOS, є помилка, яка може призвести до того, що CMAKE_CXX_STANDARDфункція просто не працює (не додайте жодних прапорів компілятора). Переконайтеся, що ви робите одну з таких дій:

  • Використовуйте cmake_minimum_required, щоб вимагати CMake 3.0 або новішої версії, або
  • Встановіть політику CMP0025 на NEW із наступним кодом у верхній частині файла CMakeLists.txt перед projectкомандою:

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

12
Це має бути прийнятою відповіддю. Він не вимагає торкання властивостей кожної цілі окремо, і працює міжплатформенним.
DevSolar

4
Погоджено, це має бути прийнятою відповіддю CMake 3.1+. Це, здається, не працює для мене на Mac, хоча. Ви можете змусити вас дати --std = c ++ 11 за допомогою --stdlib = libc ++, за замовчуванням на Mac. Натомість CMAKE_CXX_STANDARD завжди включає розширення gnu, якщо вони підтримуються, а результат, здається, не створюється на основі --stdlib = libc ++. Натомість вам потрібно перейти на gnu's --stdlib = libstdc ++. Однак Mac є особливим випадком. Для Linux вибір норми gnu ++ 11 з libstdc ++ є нормою. Звичайно, це легко виправити за допомогою if (APPLE) add_compile_options (), щоб застосувати прапори.
Atifm

2
Одна з проблем такого підходу полягає в тому, що gnu++11це застосовується, навіть коли ці змінні визначені set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(CMAKE_ANDROID_STL_TYPE c++_static). Для мене єдиним життєздатним способом був класикset (CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
Антоніо

2
Не працює для мене на macOS (CMake 3.9.4, homebrew-clang). Рятуючи інших відчай. Не впевнений, чому це працює для @EvanMoran, але не для мене.
Унапіедра

2
@Unapiedra: Це помилка CMake , але ви можете обійти це, см gitlab.kitware.com/cmake/cmake/issues/15943
Девід Грейсон

186

Команда CMake target_compile_features()використовується для визначення необхідної функції C ++ cxx_range_for. Потім CMake спонукає використовувати стандарт C ++.

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)

Не потрібно використовувати add_definitions(-std=c++11)або змінювати змінну CMake CMAKE_CXX_FLAGS, оскільки CMake переконається, що компілятор C ++ викликається відповідними прапорами командного рядка.

Можливо, ваша програма C ++ використовує інші функції, ніж C ++ cxx_range_for. Глобальна властивість CMake CMAKE_CXX_KNOWN_FEATURESмістить перелік функцій C ++, які ви можете вибрати.

Замість використання target_compile_features()ви також можете чітко вказати стандарт C ++, встановивши властивості CMake CXX_STANDARD та CXX_STANDARD_REQUIREDдля своєї цілі CMake.

Дивіться також мою більш детальну відповідь .


4
Здається, редагування від сьогодні вводить в оману. CMake 3.0.0 не містить target_compile_features. Виправте мене, якщо я помиляюся. Я думаю, що команда присутня лише в нічних складах CMake.
Ерік Шьолунд

4
Я б сказав, що це найточніша відповідь
Michał Walenciak

8
Я думаю, що саме так слід робити. Інші відповіді просто вручну додають прапори і, таким чином, вносять несумісність. Однак, здається, це доступно лише у CMake 3.1+
Uli Köhler

2
@ UliKöhler це насправді все ще не доступно, і можливо, можливо, воно з’явиться для деяких компіляторів у 3.2. Не використовуйте цей метод у короткий термін; його повністю не портативний.
Дуг

2
Будь-яка ідея, як це зробити в CMake 2.6?
nuzzolilo

93

я використовую

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

Але якщо ви хочете пограти з C++11, g++ 4.6.1досить старе. Спробуйте отримати більш нову g++версію.


4
Це для мене єдина правильна і приємна відповідь на це запитання з поточним (розгорнутим) cmake на останніх Linux 'за допомогою g ++.
Патрік Б.

1
Скопіювали та вставили це, і воно спрацювало чудово. Я на Cygwin використовую CMAKE 2.8.9. Я знаю про більшість підходів, які я читаю тут, оскільки я дотримуюся списку розсилки CMAKE і переніс WebKit до різних компіляторів. Ми зробили для портів WebKit - встановити CMake 2.8.12. Однак, оскільки я знаю, що CMGE Cygwin старий, я хотів чогось застосувати до цієї версії. (Не переносить WebKit на Cygwin, вибачте)
людина з космосу Cardiff

Чудово, це випадок для старого CMake та g ++ 4.6 (і не підтверджує майбутнє). Я також схвалив CXX_STANDARDвідповіді на основі, але це була єдина відповідь, корисна в моїй ситуації.
Томаш Гандор

Це саме те, що я шукав, проте не ясно, яка мінімальна версія cmake необхідна для використання цього модуля. cmake --help-модуль не дуже допомагає в цьому.
Ян Сегре

1
@JanSegre модуль вперше з'явився в 2.4, cmake.org/…
KoKuToru

57

Найпростіший спосіб встановити стандарт Cxx:

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

Детальнішу інформацію див. У документації CMake .


2
Так, це, безумовно, схоже на один з найкращих способів зробити це в сучасному CMake (3.1+)
Ербурет говорить, що відновить Моніку

14
Або ви можете просто set(CMAKE_CXX_STANDARD 11)визначити властивість за замовчуванням для всіх цілей, створених після цього.
emlai

1
Це також потрібне вам рішення, якщо ви хочете встановити різні стандарти C ++ для різних цілей, оскільки setкоманда, запропонована @emlai, є глобальною і впливає на всі наступні цілі.
Забій Елліотта

40

Як виявляється, SET(CMAKE_CXX_FLAGS "-std=c++0x")активує багато функцій C ++ 11. Причина не спрацювала в тому, що заява виглядала так:

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

Дотримуючись такого підходу, якось -std=c++0xпрапор був перезаписаний, і він не працював. Встановлення прапорців один за одним або використання методу списку працює.

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

36
Я завжди просто використовую: SET (CMAKE_CXX_FLAGS "$ {CMAKE_CXX_FLAGS} -std = c ++ 11") # для gcc> = 4.7, або c ++ 0x для 4.6
Девід Дорія

Я колись зробив для цього невеликий сценарій (не повний): github.com/Morwenn/POLDER/blob/master/cmake/set_cxx_norm.cmake
Morwenn

9
-1. Якщо ви вказали будь-який CMAKE_CXX_FLAGS з командного рядка, другий метод створить крапку з комою в команді build (і повторіть початковий CMAKE_CXX_FLAGS двічі).
Микола

замість того, щоб вручну додавати прапор -g, слід встановити змінну CMAKE_BUILD_TYPE для налагодження: voices.canonical.com/jussi.pakkanen/2013/03/26/…
bames53

1
CXX_STANDARDВластивість краще , так як це компілятор агностик.
jaskmar


19

Для CMake 3.8 та новіших ви можете використовувати

target_compile_features(target PUBLIC cxx_std_11)

1
саме так рекомендується остання версія CMake
camino

Яка тут функція PUBLIC?
Rotsiser Mho

2
@RotsiserMho PUBLICозначає, що інші цілі, які залежать від вашої цілі, також використовуватимуть C ++ 11. Наприклад, якщо ваша мета - бібліотека, всі цілі, які посилаються на вашу бібліотеку, target_link_librariesбудуть зібрані з підтримкою C ++ 11.
вії

17

Це ще один спосіб увімкнути підтримку C ++ 11,

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

Я стикався з випадками, коли працює лише цей метод, а інші методи виходять з ладу. Можливо, це має щось спільне з останньою версією CMake.


9
Це буде працювати лише в тому випадку, якщо ви ТИЛЬКО використовуєте компілятор C ++. Якщо ви також використовуєте компілятор CC, він вийде з ладу.
Еммануїл

5
add_definitionsпередбачається використовувати лише для додавання ВИЗНАЧЕННЯ, тобто -D SOMETHING. І як сказав @Emmanuel, це не спрацьовує у багатьох випадках.
xuhdev

Я використовував це раніше, але виникли проблеми, коли я включив файл C, оскільки add_definitionsвін не був створений для встановлення прапорів.
Ян Сегре

17

У сучасних CMake (> = 3.1) найкращим способом встановлення глобальних вимог є:

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

Це означає "Я хочу C ++ 11 для всіх цілей. Це не є обов'язковим. Я не хочу використовувати будь-які розширення GNU чи Microsoft". Що стосується C ++ 17, це все-таки найкращий спосіб IMHO.

Джерело: Увімкнення C ++ 11 і пізніше в CMake


1
Цей спосіб не є ідеальним для новітніх версій C ++, якщо у вас немає останньої версії CMake. Наприклад, ви не можете ввімкнути C ++ 2a таким чином, поки CMake 3.12.
Руслан

6

Що для мене працює - це встановити наступний рядок у своєму CMakeLists.txt:

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

Встановлення цієї команди активує функції C ++ 11 для компілятора, і після виконання cmake ..команди ви повинні мати можливість використовувати range based for loopsу своєму коді та компілювати його без будь-яких помилок.


Це, зрештою, найкраща відповідь, якщо ви хочете саме -std=c++11, як set (CMAKE_CXX_STANDARD 11)використовувати прапор -std=gnu++11, що може бути небажаним.
Антоніо

1
@Antonioset (CMAKE_CXX_EXTENSIONS OFF)
mloskot

3

Я думаю, що цих двох рядків достатньо.

set(CMAKE_CXX_STANDARD 11)

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

1
Це має сенс, коли всі цілі в проекті використовують один і той же стандарт C ++ (наприклад, всі складені бібліотеки та виконувані файли використовують C ++ 11). В іншому випадку target_compile_featuresфункція Cmake , застосована до кожної окремої цілі, як показано в інших відповідях, є більш рекомендованим підходом.
Аллан

3

Якщо ви хочете завжди активувати останній стандарт C ++, ось моє розширення відповіді Девіда Грейсона , зважаючи на недавні доповнення (CMake 3.8 та CMake 3.11) значень 17 та 20 для 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)

(Використовуйте цей код замість set (CMAKE_CXX_STANDARD 11)пов'язаної відповіді.)


1

Сучасний cmake пропонує більш прості способи налаштування компіляторів для використання конкретної версії C ++. Єдине, що кому потрібно зробити, - це встановити відповідні цільові властивості. Серед властивостей, що підтримуються cmake , такі, які використовуються для визначення способу налаштування компіляторів для підтримки певної версії C ++, є наступними:

  • CXX_STANDARDвстановлює стандарт C ++, функції якого вимагаються для створення цілі. Встановіть це як 11орієнтацію на C ++ 11.

  • CXX_EXTENSIONS, булева інформація, яка визначає, чи потрібні розширення для компілятора. Встановлюючи це як Offвідключає підтримку будь-якого розширення, що стосується компілятора.

Щоб продемонструвати, ось мінімальний робочий приклад а 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

ОС X і Homebrew LLVM пов'язані:

Не забудьте зателефонувати cmake_minimum_required (VERSION 3.3) та project () після цього!

Або CMake буде вставлено project()неявно перед рядком 1, викликаючи проблеми з виявленням версії Clang і, можливо, іншими видами неполадок. Ось пов'язане питання .


2
Питання, зокрема, не стосується OSX або LVVM. Крім того, немає ніяких причин вимагати CMake v3.x для розробки C ++ 11. Щодо виявлення кланг-версії - це не те, про що запитували ОП.
einpoklum
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.