Как активировать C ++ 11 в CMake?

356

Когда я пытаюсь запустить созданный CMake make-файл для компиляции моей программы, я получаю сообщение об ошибке

Диапазон, основанный на циклах, не поддерживается в режиме 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 для пользователей clang, ориентированных на 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 --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
Я бы сказал, что это самый точный ответ
Михал Валенчак
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++версию.

KoKuToru
источник
4
Для меня это единственный правильный и хороший ответ на этот вопрос, с текущим (развернутым) cmake на самой последней Linux, использующей g ++.
Патрик Б.
1
Скопировал и вставил это, и это сработало отлично. Я на Cygwin использую CMAKE 2.8.9. Я знаю о большинстве подходов, которые я читаю здесь, потому что я следую за списком рассылки CMAKE и портировал WebKit на различные компиляторы. То, что мы сделали для портов WebKit, это установили CMake 2.8.12. Однако, поскольку я знаю, что CMAKE Cygwin устарела, я хотел что-то, что применимо к этой версии. (Не портирую WebKit на Cygwin, извините)
кардифф космонавт
Отлично, это дополнение для старых CMake и g ++ 4.6 (и перспективных). Я также проголосовал против CXX_STANDARDответов на основе, но это был единственный ответ, полезный в моей ситуации.
Томаш Гандор
Это именно то, что я искал, однако не ясно, какая минимальная версия cmake необходима для использования этого модуля. cmake --help-module не очень помогает в этом.
Ян Сегре
1
@JanSegre модуль впервые появился в 2.4, cmake.org/…
KoKuToru
57

Самый простой способ установить стандарт Cxx:

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

Смотрите документацию CMake для более подробной информации.

Luckyrand
источник
2
Да, это определенно выглядит как один из лучших способов сделать это в современном CMake (3.1+)
Эрбурет говорит восстановить Monica
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
Дэвид Дориа
Однажды я
написал
9
-1. Если вы укажете какой-либо CMAKE_CXX_FLAGS из командной строки, второй метод создаст точку с запятой в команде построения (и дважды повторите исходный CMAKE_CXX_FLAGS).
Николай
вместо того, чтобы вручную добавлять флаг -g, вы должны установить для отладки переменную CMAKE_BUILD_TYPE
bames53
1
CXX_STANDARDСвойство лучше , так как это компилятор агностик.
jaskmar
23

Самый простой способ:

add_compile_options(-std=c++11)

Альварес
источник
5
Доступно только с cmake 3.0
Рауль Салинас-Монтеагудо
4
Это вызывает предупреждение и ошибки при компиляции файлов C в том же проекте.
Розовая вода
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 ЧТО-ТО. И, как сказал @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, это ИМХО лучший способ.

Источник: Включение C ++ 11 и позже в CMake

MateuszL
источник
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)связанного ответа.)

codeling
источник
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

OS X и Homebrew LLVM связаны с:

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

Или CMake вставит project()неявно перед строкой 1, вызывая проблемы с обнаружением версии Clang и, возможно, другие виды проблем. Вот связанная проблема .

Senz
источник
2
Вопрос, в частности, не связан с OSX или LVVM. Кроме того, нет причин требовать CMake v3.x для разработки на C ++ 11. Что касается определения версии clang - это не то, о чем спрашивал OP.
einpoklum