【问题标题】:cmake will not compile to C++ 11 standardcmake 不会编译为 C++ 11 标准
【发布时间】:2016-06-03 18:38:58
【问题描述】:

我是 C++ 的新手,一直在努力编译/制作/链接/构建/任何东西,让我们看看是否有人可以帮助我。我做了一些搜索,发现其他人有类似的问题,但我尝试了他们的解决方案,但没有运气,所以这里是:

使用统一初始化、线程、to_string 等 C++ 11 功能的简单 c++ 程序会生成 "xxx" 未在范围内声明的错误。具体来说,现在我想使用to_string,并在std 命名空间或特别是std::to_string 中使用它会产生错误“to_string”不是STD 的成员。很明显它不是用 C++ 11 编译的。

这是我的制作文件:

#####################################
cmake_minimum_required (VERSION 2.8)
project (raspicam_test)
find_package(raspicam REQUIRED)
find_package(OpenCV)

IF  ( OpenCV_FOUND AND raspicam_CV_FOUND)
        MESSAGE(STATUS "COMPILING OPENCV TESTS")
        add_executable (main main.cpp)
        #target_compile_features(main PRIVATE cxx_range_for)
        set_property(TARGET main PROPERTY CXX_STANDARD 11)
        target_link_libraries (main ${raspicam_CV_LIBS})
ELSE()
        MESSAGE(FATAL_ERROR "OPENCV NOT FOUND IN YOUR SYSTEM")
ENDIF()
#####################################

如您所见,我正在树莓派上使用 OpenCV。但是没有 C++11 函数,程序编译和运行没有问题。但我想从 C++11 添加线程和其他好东西。我根据CMAKE文档添加了set_property(TARGET main PROPERTY CXX_STANDARD_REQUIRED 11)这一行:

https://cmake.org/cmake/help/v3.1/prop_tgt/CXX_STANDARD.html

这对生成的错误没有影响。我首先在没有_REQUIRED 的情况下完成了它,然后再使用它。我也尝试了target_compile_features(),但 CMAKE 返回了“未知的 CMAKE 命令”。

其他细节: - 在运行 debian jessie 的树莓派 3 上编译 -CXX 编译器是 GNU 4.9.2 -CMAKE 3.0.2

【问题讨论】:

  • 我意识到我只有 CMAKE 3.0.2 并且我链接的文档是针对 CMAKE 3.1,也许它不支持 CXX_STANDARD 属性?我最终使用的是 "set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")" ,它对我有用。更高版本的 CMAKE 是否可以使用 set_property 方法?一个比另一个有优势吗?
  • CXX_STANDARD 是 3.1 中的新功能 cmake.org/cmake/help/v3.1/release/3.1.0.html#properties
  • 仅供参考,部分困难在于 C++03 是 GCC 4.x 的默认值,而 4.7 是第一个支持 C++11 的版本。当您拥有 GCC 5.x 时,C++11 将是默认值,而 GCC 6.x C++14 将是默认值。
  • @MattSchuchard GCC5 仍然默认使用 gnu++03 用于 C++,但 gnu11 用于 C。GCC6 切换到 gnu++14 作为默认 C++ 模式。

标签: c++ c++11 cmake


【解决方案1】:

早于 3.1 的 CMake 版本中,我们使用

 add_compile_options(-std=c++11) # CMake 2.8.12 or newer

按照CMake Docs 中的描述将编译选项添加到编译器调用。

这可能不像 Alvaro 的答案那样便携,但它更具可读性,而且由于您使用的是 RasPi,我猜,GCC 和 Clang 作为目标编译器可以做到。

编辑:为了完整起见:在 CMake 版本 3.1 及更新版本中,如果要强制 C++11,则需要以下几行: p>

set(CMAKE_CXX_STANDARD 11) # C++11...
set(CMAKE_CXX_STANDARD_REQUIRED ON) #...is required...
set(CMAKE_CXX_EXTENSIONS OFF) #...without compiler extensions like gnu++11

这会在编译期间启用此声明之后的所有目标的选项。如果您想更细粒度地控制它,请参阅 Alvaro 的答案或 set_taget_properties() 的 CMake Docs,然后看起来像这样:

set_target_properties(myTarget PROPERTIES
    CXX_STANDARD 11
    CXX_STANDARD_REQUIRED ON
    CXX_EXTENSIONS OFF
)

编辑:但请注意,GCC 4 中的 C++11 支持并不完整,并且可能存在与定义的标准不同的行为。

【讨论】:

  • 还有一个更现代的设施:cmake.org/cmake/help/v3.1/manual/cmake-compile-features.7.html 您可以请求特定的功能,cmake 会自动为您的编译器提供标志。
  • @IlyaPopov:感谢您的提示。不过,不确定它是否更现代。它肯定更细粒度,但它是与CMAKE_CXX_STANDARD 和朋友同时推出的。 ...此外,我试图为这种特定情况找到一个功能关键字(用于使用to_string),但找不到。我错过了吗?我想将此添加到答案中,但前提是我可以输入一些具体的内容。
  • 过时了?它不适用于具有本机 c++ 代码的 android gradle 项目。 CMake 的最新版本现在是 3.15。
  • @zwcloud 不知道 Android 或 Gradle,但 CXX_STANDARDCMAKE_CXX_STANDARD 仍然适用于 CMake 3.15。
【解决方案2】:

CMake 在 3.1 版本上添加了对 CXX_STANDARDCXX_STANDARD_REQUIRED 属性的支持。 CXX_STANDARD:取CMAKE_CXX_STANDARD 值之一,它们是98, 11 and 14。 如果您通过 CXX_STANDARD 11 并且您的编译器不支持 c++11 CXX_STANDARD 自动变成 98 并且 cmake 不给你任何 如果 CXX_STANDARD_REQUIREDOFF 或未设置,则会出错。 如果您设置的 CXX_STANDARD_REQUIRED "ON" CXX_STANDARD 特定值成为构建和 cmake 处理此所需的属性。

为了使用CHECK_CXX_COMPILER_FLAG,您需要包含 CheckCXXCompilerFlag 模块:

include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
if(COMPILER_SUPPORTS_CXX11)
    message(STATUS "${COMPILER_SUPPORTS_CXX11}")
else(COMPILER_SUPPORTS_CXX11)
    message(FATAL_ERROR "${COMPILER_SUPPORTS_CXX11}")
endif(COMPILER_SUPPORTS_CXX11)

如果你有一个旧的 cmake,你需要处理复杂而不是可移植的标志 来自编译器的 sush 为:

function(suported_compilers)
  if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
    execute_process(
      COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
    if(NOT(GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7))
      message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.")
    endif(NOT(GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7))
  elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
  else()
    message(FATAL_ERROR "Your compiler is supported in the build set?, please "
                  "contact the maintainer.")
  endif()
endfunction(suported_compilers)
function(set_targets_compilers_flags target_list)
  suported_compilers()
  foreach(tg ${target_list})
    if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
      set_target_properties(${tg} PROPERTIES COMPILE_FLAGS "-g -std=c++14 -Wall -Wextra -Werror")
    elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
      set_target_properties(${tg} PROPERTIES COMPILE_FLAGS "/W4 /WX /EHsc")
    endif()
  endforeach()
endfunction(set_targets_compilers_flags)

【讨论】:

    【解决方案3】:

    由于当前的 cmake 版本是 3.10,我认为识别较新的方法可能是合适的。虽然建议使用 add_compiler_

    对于任何在这里查看更现代版本的 cmake (3.1+) 的人来说,最合适的答案不是确定给定编译器的版本,而是让 CMAKE 知道哪些功能需要可用。

    target_compile_features(engine
        PRIVATE cxx_range_for
        )
    

    【讨论】:

      【解决方案4】:

      我总是以这种方式在我的代码中使用 CMake 启用 c++11:

      set(CMAKE_CXX_FLAGS "-std=c++11")
      

      我的编译器是 gcc (Debian 4.9.2-10) 4.9.2,但是在我的工作场所我也使用其他版本,这种方法总是有效的。

      编辑(避免变量覆盖):

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

      【讨论】:

      • 这会覆盖用户可能已经在他的 shell 中设置为某个自定义值的变量。如果您想使用它,请这样做:set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} "-std=c++11") ... 但一般来说,更喜欢add_compile_option()CXX_STANDARD 变量等更“现代”的方法。 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-16
      • 2016-05-31
      • 2014-02-01
      • 1970-01-01
      • 2017-03-09
      • 1970-01-01
      • 2012-01-14
      相关资源
      最近更新 更多