Làm cách nào để kích hoạt C ++ 11 trong CMake?


356

Khi tôi cố chạy một tệp Makefile được tạo CMake để biên dịch chương trình của mình, tôi gặp lỗi

phạm vi dựa trên các vòng lặp không được hỗ trợ trong chế độ C ++ 98.

Tôi đã cố gắng thêm add_definitions(-std=c++0x)vàoCMakeLists.txt , nhưng không được.

Tôi cũng đã thử điều này:

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

Khi tôi làm g++ --version, tôi nhận được:

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

Tôi cũng đã thử SET(CMAKE_CXX_FLAGS "-std=c++0x") , mà cũng không hoạt động.

Tôi không hiểu làm thế nào tôi có thể kích hoạt các tính năng của C ++ 11 bằng CMake.


11
Công SET(CMAKE_CXX_FLAGS "-std=c++0x")việc này rất tốt đối với tôi, vì vậy có lẽ có vấn đề ở đâu đó trong tệp CMakeLists. Hãy chắc chắn rằng bạn không vô tình ghi đè lên nội dung của CMAKE_CXX_FLAGS sau này.
ComicSansMS

7
add_def định (-std = c ++ 11) hoạt động với tôi với CMake
2.8.8

@ComicSansMS: Bạn hoàn toàn đúng! Tôi ghi đè lên nó, đó là sai lầm của riêng tôi. Tôi đã sửa nó, và bây giờ nó đang hoạt động tốt! C ++ 11 thứ rất tuyệt! Tôi muốn lặp trên một vectơ cấu trúc, sẽ yêu cầu lặp và tiếng ồn mã hóa không cần thiết nếu tôi không có phạm vi dựa trên các vòng lặp. Tôi đoán rằng tôi có thể sử dụng BOOST_FOREACH, nhưng ồ ...
Subhamoy S.

32
Đối với CMake ≥3.1, set(CMAKE_CXX_STANDARD 11)(trước khi xác định mục tiêu) là cách tốt nhất.
emlai

@tuple_cat Bạn cũng có thể làm điều đó dựa trên mục tiêu. Nhưng hãy lưu ý rằng CXX_STANDARDkhông hoạt động trên MSVC, vì vậy về cơ bản, bạn phải quay lại target_compile_featuresnếu bạn muốn một cái gì đó hoạt động đa nền tảng.
Ela782

Câu trả lời:


395

CMake 3.1 đã giới thiệu biến CMAKE_CXX_STANDARD mà bạn có thể sử dụng. Nếu bạn biết rằng bạn sẽ luôn có sẵn CMake 3.1, bạn chỉ có thể viết phần này trong tệp CMakeLists.txt cấp cao nhất của bạn hoặc đặt nó ngay trước khi bất kỳ mục tiêu mới nào được xác định:

set (CMAKE_CXX_STANDARD 11)

Nếu bạn cần hỗ trợ các phiên bản cũ hơn của CMake, đây là một macro tôi nghĩ ra mà bạn có thể sử dụng:

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)

Macro chỉ hỗ trợ GCC ngay bây giờ, nhưng cần đơn giản để mở rộng nó sang các trình biên dịch khác.

Sau đó, bạn có thể viết use_cxx11()ở đầu bất kỳ tệp CMakeLists.txt nào xác định mục tiêu sử dụng C ++ 11.

Vấn đề CMake # 15943 cho người dùng clang nhắm mục tiêu macOS

Nếu bạn đang sử dụng CMake và clang để nhắm mục tiêu macOS, có một lỗi có thể khiến CMAKE_CXX_STANDARDtính năng đơn giản là không hoạt động (không thêm bất kỳ cờ biên dịch nào). Hãy chắc chắn rằng bạn làm một trong những điều sau đây:

  • Sử dụng cmake_minimum_Vquired để yêu cầu CMake 3.0 trở lên hoặc
  • Đặt chính sách CMP0025 thành MỚI với mã sau ở đầu tệp CMakeLists.txt của bạn trước projectlệnh:

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

12
Đây phải là câu trả lời được chấp nhận. Nó không yêu cầu chạm riêng từng thuộc tính của mục tiêu và hoạt động đa nền tảng.
DevSolar

4
Đồng ý, đây phải là câu trả lời được chấp nhận kể từ CMake 3.1+. Nó dường như không hoạt động đối với tôi trên mac. Bạn có thể buộc nó cung cấp cho bạn --std = c ++ 11 với --stdlib = libc ++, mặc định trên Mac. Thay vào đó, CMAKE_CXX_STANDARD luôn bao gồm các tiện ích mở rộng gnu nếu chúng được hỗ trợ và kết quả dường như không được xây dựng dựa trên --stdlib = libc ++. Thay vào đó, bạn phải chuyển sang gnu's --stdlib = libstdc ++. Mac là trường hợp đặc biệt mặc dù. Đối với Linux, chọn gnu ++ 11 với libstdc ++ là chuẩn mực. Tất nhiên, điều đó dễ dàng được sửa bằng một if (APPLE) add_compile_options () để giải quyết các cờ.
Atifm

2
Một vấn đề của phương pháp này gnu++11là được thi hành, ngay cả khi các biến này được xác định set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(CMAKE_ANDROID_STL_TYPE c++_static). Đối với tôi cách duy nhất khả thi là kinh điểnset (CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
Antonio

2
Không hoạt động với tôi trên macOS (CMake 3.9.4, homebrew-clang). Cứu người khác sự tuyệt vọng. Không chắc tại sao nó hoạt động cho @EvanMoran mà không phải cho tôi.
Unapiedra

2
@Unapiedra: Đó là một lỗi CMake nhưng bạn có thể khắc phục nó, xem gitlab.kitware.com/cmake/cmake/issues/15943
David Grayson

186

Lệnh CMake target_compile_features()được sử dụng để chỉ định tính năng C ++ cần thiết cxx_range_for. CMake sau đó sẽ tạo ra tiêu chuẩn C ++ sẽ được sử dụng.

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)

Không cần sử dụng add_definitions(-std=c++11)hoặc sửa đổi biến CMake CMAKE_CXX_FLAGS, vì CMake sẽ đảm bảo trình biên dịch C ++ được gọi với các cờ dòng lệnh thích hợp.

Có thể chương trình C ++ của bạn sử dụng các tính năng C ++ khác hơn cxx_range_for. Thuộc tính toàn cầu CMake CMAKE_CXX_KNOWN_FEATURESliệt kê các tính năng C ++ mà bạn có thể chọn.

Thay vì sử dụng, target_compile_features()bạn cũng có thể chỉ định rõ ràng tiêu chuẩn C ++ bằng cách đặt thuộc tính CMake CXX_STANDARDCXX_STANDARD_REQUIREDcho mục tiêu CMake của bạn.

Xem thêm câu trả lời chi tiết hơn của tôi .


4
Có vẻ như chỉnh sửa từ hôm nay là sai lệch. CMake 3.0.0 không chứa target_compile_features. Sửa tôi nếu tôi sai. Tôi nghĩ rằng lệnh này chỉ hiện diện trong các bản dựng hàng đêm của CMake.
Erik Sjölund

4
Tôi muốn nói đây là câu trả lời chính xác nhất
Michał Walenciak 7/1/2015

8
Tôi nghĩ rằng đây là cách nó phải làm. Các câu trả lời khác chỉ cần thêm cờ thủ công và do đó đưa ra sự không tương thích. Tuy nhiên, điều này dường như chỉ có trong CMake 3.1+
Uli Köhler

2
@ UliKöhler điều này thực sự vẫn chưa có, và có thể có thể bật lên cho một số trình biên dịch trong 3.2. Đừng sử dụng phương pháp này trong thời gian ngắn; Nó hoàn toàn không di động.
Doug

2
Bất kỳ ý tưởng làm thế nào để làm điều này trong CMake 2.6?
nuzzolilo

93

tôi đang dùng

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

Nhưng nếu bạn muốn chơi với C++11, g++ 4.6.1là khá cũ. Cố gắng để có được một g++phiên bản mới hơn .


4
Đối với tôi, đây là câu trả lời đúng và duy nhất cho câu hỏi này, với cmake hiện tại (đã được triển khai) trên Linux gần đây nhất bằng cách sử dụng g ++.
Patrick B.

1
Sao chép và dán này và nó hoạt động hoàn hảo. Tôi đang sử dụng Cygwin bằng cách sử dụng CMAKE 2.8.9. Tôi biết về hầu hết các cách tiếp cận mà tôi đang đọc ở đây vì tôi theo dõi danh sách gửi thư của CMAKE và tôi đã chuyển WebKit sang nhiều trình biên dịch khác nhau. Việc chúng tôi đã làm cho các cổng WebKit là cài đặt CMake 2.8.12. Tuy nhiên vì tôi biết CMAKE của Cygwin đã cũ, tôi muốn một cái gì đó áp dụng cho phiên bản đó. (Không chuyển WebKit sang Cygwin, xin lỗi)
người đàn ông không gian cardiff

Tuyệt vời, đây là một phần bổ sung cho CMake cũ và g ++ 4.6 (và bằng chứng trong tương lai). Tôi cũng nêu lên các CXX_STANDARDcâu trả lời dựa trên, nhưng đây là câu trả lời duy nhất hữu ích trong tình huống của tôi.
Tomasz Gandor

Đây chính xác là những gì tôi đang tìm kiếm, tuy nhiên không rõ phiên bản cmake tối thiểu cần thiết để sử dụng mô-đun đó là gì. cmake --help-module không giúp được gì nhiều về nó.
Jan Segre

1
@JanSegre mô-đun xuất hiện lần đầu tiên trong 2.4, cmake.org/
KoKuToru

57

Cách dễ nhất để đặt tiêu chuẩn Cxx là:

 set_property(TARGET tgt PROPERTY CXX_STANDARD 11)

Xem tài liệu CMake để biết thêm chi tiết.


2
Vâng, điều này chắc chắn trông giống như một trong những cách tốt nhất để làm điều đó trong CMake hiện đại (3.1+)
Erbureth nói Phục hồi lại

14
Hoặc bạn chỉ có thể set(CMAKE_CXX_STANDARD 11)xác định thuộc tính mặc định cho tất cả các mục tiêu được tạo sau đó.
emlai

1
Đây cũng là giải pháp bạn cần nếu bạn muốn đặt các tiêu chuẩn C ++ khác nhau cho các mục tiêu khác nhau, bởi vì setlệnh được đề xuất bởi @emlai là toàn cầu và ảnh hưởng đến tất cả các mục tiêu tiếp theo.
Elliott tàn sát

40

Hóa ra, SET(CMAKE_CXX_FLAGS "-std=c++0x")không kích hoạt nhiều tính năng C ++ 11. Lý do nó không hoạt động là vì tuyên bố trông như thế này:

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

Theo cách tiếp cận này, bằng cách nào đó -std=c++0xlá cờ đã bị ghi đè và nó không hoạt động. Đặt các cờ lần lượt hoặc sử dụng phương thức danh sách đang hoạt động.

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

36
Tôi luôn chỉ sử dụng: SET (CMAKE_CXX_FLAGS "$ {CMAKE_CXX_FLAGS} -std = c ++ 11") # cho gcc> = 4.7 hoặc c ++ 0x cho 4.6
David Doria

Tôi đã từng làm một kịch bản nhỏ cho điều đó (mặc dù chưa hoàn thành): github.com/Morwenn/POLDER/blob/master/cmake/set_cxx_norm.cmake
Morwenn

9
-1. Nếu bạn chỉ định bất kỳ CMAKE_CXX_FLAGS nào từ dòng lệnh, phương thức thứ hai sẽ tạo ra một dấu chấm phẩy trong lệnh xây dựng (và lặp lại CMAKE_CXX_FLAGS ban đầu hai lần).
Nikolai

thay vì thêm cờ -g theo cách thủ công, bạn nên đặt biến CMAKE_BUILD_TYPE thành gỡ lỗi: voices.canonical.com/jussi.pakkanen/2013/03/26/ ám
bames53

1
Các CXX_STANDARDtài sản là tốt hơn vì nó là trình biên dịch bất khả tri.
jaskmar


19

Đối với CMake 3.8 trở lên, bạn có thể sử dụng

target_compile_features(target PUBLIC cxx_std_11)

1
đây là cách được đề xuất cho phiên bản mới nhất của CMake
camino

Chức năng của PUBLICđây là gì?
Rotsiser Mho

2
@RotsiserMho PUBLICcó nghĩa là các mục tiêu khác phụ thuộc vào mục tiêu của bạn cũng sẽ sử dụng C ++ 11. Ví dụ: nếu mục tiêu của bạn là một thư viện thì tất cả các mục tiêu liên kết với thư viện của bạn target_link_librariessẽ được biên dịch với sự hỗ trợ của C ++ 11.
lông mi

17

Đây là một cách khác để hỗ trợ C ++ 11,

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

Tôi đã gặp các trường hợp chỉ có phương pháp này hoạt động và các phương pháp khác không thành công. Có lẽ nó có liên quan đến phiên bản mới nhất của CMake.


9
Điều đó sẽ chỉ hoạt động nếu bạn CHỈ sử dụng trình biên dịch C ++. Nếu bạn cũng đang sử dụng trình biên dịch CC thì nó sẽ thất bại.
Emmanuel

5
add_definitionschỉ được sử dụng để thêm ĐỊNH NGH DEA, tức là -D SOMETHING. Và như @Emmanuel đã nói, nó không hoạt động trong nhiều trường hợp.
xuhdev

Tôi đã sử dụng nó trước đây nhưng có vấn đề khi tôi bao gồm một tệp C vì add_definitionskhông được tạo để thiết lập cờ.
Jan Segre

17

Trên CMake hiện đại (> = 3.1), cách tốt nhất để đặt yêu cầu toàn cầu là:

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

Nó dịch thành "Tôi muốn C ++ 11 cho tất cả các mục tiêu, nó không phải là tùy chọn, tôi không muốn sử dụng bất kỳ tiện ích mở rộng GNU hoặc Microsoft nào." Kể từ C ++ 17, đây vẫn là IMHO cách tốt nhất.

Nguồn: Kích hoạt C ++ 11 và sau đó trong CMake


1
Cách này không lý tưởng cho các phiên bản C ++ mới nhất nếu bạn không có CMake mới nhất. Ví dụ: bạn không thể bật C ++ 2a theo cách này cho đến khi CMake 3.12.
Ruslan

6

Điều làm việc cho tôi là đặt dòng sau trong CMakeLists.txt của bạn:

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

Đặt lệnh này sẽ kích hoạt các tính năng C ++ 11 cho trình biên dịch và sau khi thực hiện cmake ..lệnh, bạn sẽ có thể sử dụng range based for loopsmã của mình và biên dịch nó mà không có bất kỳ lỗi nào.


Đây là câu trả lời cuối cùng tốt nhất nếu bạn muốn chính xác -std=c++11, như set (CMAKE_CXX_STANDARD 11)sẽ sử dụng cờ -std=gnu++11, điều này có thể không mong muốn.
Antonio

1
@Antonioset (CMAKE_CXX_EXTENSIONS OFF)
mloskot

3

Tôi nghĩ chỉ cần hai dòng này là đủ.

set(CMAKE_CXX_STANDARD 11)

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

1
Điều này có ý nghĩa khi tất cả các mục tiêu trong một dự án sử dụng cùng một tiêu chuẩn C ++ (tất cả các thư viện được biên dịch và các tệp thực thi đều sử dụng C ++ 11 chẳng hạn). Mặt khác target_compile_features, hàm Cmake , được áp dụng cho từng mục tiêu riêng lẻ, như thể hiện trong các câu trả lời khác, là một cách tiếp cận được khuyến nghị hơn.
Allan

3

Trong trường hợp bạn muốn luôn kích hoạt tiêu chuẩn C ++ mới nhất, đây là phần mở rộng câu trả lời của David Grayson , ngoài các bổ sung gần đây (CMake 3.8 và CMake 3.11) cho các giá trị 17 và 20 cho 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)

(Sử dụng mã đó thay set (CMAKE_CXX_STANDARD 11)cho câu trả lời được liên kết.)


1

Cmake hiện đại cung cấp các cách đơn giản hơn để định cấu hình trình biên dịch để sử dụng phiên bản cụ thể của C ++. Điều duy nhất bất cứ ai cần làm là thiết lập các thuộc tính mục tiêu có liên quan. Trong số các thuộc tính được cmake hỗ trợ , các thuộc tính được sử dụng để xác định cách định cấu hình trình biên dịch để hỗ trợ phiên bản cụ thể của C ++ như sau:

  • CXX_STANDARDthiết lập tiêu chuẩn C ++ có các tính năng được yêu cầu để xây dựng mục tiêu. Đặt 11mục tiêu này là nhắm mục tiêu C ++ 11.

  • CXX_EXTENSIONS, một boolean chỉ định xem các phần mở rộng cụ thể của trình biên dịch có được yêu cầu hay không. Đặt điều này là Offvô hiệu hóa hỗ trợ cho bất kỳ tiện ích mở rộng dành riêng cho trình biên dịch.

Để chứng minh, đây là một ví dụ làm việc tối thiểu của 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
    )

-5

Liên quan đến OS X và Homebrew LLVM:

Đừng quên gọi cmake_minimum_Vquired (VERSION 3.3) và dự án () sau nó!

Hoặc CMake sẽ chèn project()ngầm trước dòng 1, gây rắc rối với phát hiện phiên bản Clang và có thể các loại rắc rối khác. Đây là một vấn đề liên quan .


2
Câu hỏi không liên quan đến OSX hoặc LVVM. Ngoài ra, không có lý do gì để yêu cầu CMake v3.x để phát triển C ++ 11. Đối với phát hiện phiên bản clang - đó không phải là những gì OP yêu cầu.
einpoklum
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.