C++标准与CMake的冲突

6

我在使用CMake构建项目时遇到了关于设置C++标准的一些问题。代码需要大量使用C++11特性,因此到目前为止,我一直这样做:

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

最近GCC版本默认使用C++14,因此我需要链接与C++14构建的库才能满足公共要求,但在尝试使用严格的C++11进行构建时会发生冲突。

因此,目标是要求至少使用C++11标准,但如果默认编译器版本更高,则使用它。

我已经尝试过:

target_compile_features(myLib PUBLIC cxx_std_11)

但是CMake最终会添加-std=c++11标志,这很令人困惑,因为文档明确表示:

CMake将确保以了解C++ 11(或更高版本)的模式调用编译器,必要时添加标志,如-std=gnu++11。

我也尝试使用CMAKE_CXX_STANDARD_COMPUTED_DEFAULT内部变量,但由于"98"大于"11",所以这很麻烦。

当然,可以使用该变量或使用check_cxx_compiler_flag()函数,并测试不同的情况来使其正常工作,但在新标准每三年出现一次的今天,希望有一种更简单的方法来实现这一点...


1
我认为现代的方式是不指定标准,而是列举出你使用的每个功能(没错,就是这样)。幸运的是,CMake会推断出你想要的最低标准,并允许使用更高的标准,如果它们也支持你使用的功能。 - nwp
@nwp 这实际上更像是一种恐龙式的方法。看起来就像是在autotools中的特性检查宏一样令人噩梦... - user7860670
1
@nwp 对,那可能是最“正确”的方法,但对于已经存在的项目来说显然不切实际...由于代码大量使用了C++11特性,逐个检查将会很麻烦。 - swertz
你可以只使用lambda表达式,这样就可以使用C++11而不必列出每个特性。这可能会对使用VS2010的人造成问题,因为它具有lambda表达式但不是所有的C++11特性,但如果你不支持该编译器,那么这可能没问题。 - nwp
这实际上听起来像是一个XY问题:"在尝试使用严格的C++11构建时存在冲突":你的编译器工具链出了问题,而你正在绕过这个错误进行hack。也许你应该修复你的工具链,以便它可以编译你正在使用的标准。 - nwp
显示剩余5条评论
1个回答

5
我知道这是一个老问题,但无论如何:你正在走对的路,只需在CMakeLists项目中为你声明的库使用target_compile_features。如果你使用相同的GCC版本(不管你在每个库上放什么-std = ...),链接c++14库和c++11库应该没有问题。
所以,如果你有libA、libB和libC,你可以这样做:
target_compile_features(libA PUBLIC cxx_std_11)
target_compile_features(libB PUBLIC cxx_std_14)
target_compile_features(libC PUBLIC cxx_std_17)

如果由于某种原因需要使用不同的编译器版本,那么我想如果您可以构建共享库而不是静态库,那么应该能够将它们链接起来。
关于cxx扩展和标准的进一步澄清: 如果要避免扩展(即使用c++11而不是gnu++11编译),则可以设置CMAKE_CXX_EXTENSIONS OFF。
set(CMAKE_CXX_EXTENSIONS OFF)

默认情况下,C++ 扩展已启用。您需要在创建目标之前设置此选项。
没有允许扩展的简单示例:
cmake_minimum_required(VERSION 3.16)

project(test-poc)
set(CMAKE_CXX_EXTENSIONS OFF)

add_executable(main main.cpp)

target_compile_features(main PRIVATE cxx_std_17)

在创建目标之前,我们添加了CMAKE_CXX_EXTENSIONS OFF,这样CMake将选择-std=c++17而不是-std=gnu++17。如果我们删除那行代码,CMake会选择-std=gnu++17。

See: https://cmake.org/cmake/help/latest/prop_tgt/CXX_EXTENSIONS.html#prop_tgt:CXX_EXTENSIONS


请澄清答案,cxx_std_11 是否意味着 C++ 扩展 (gnu++11 vs c++11 gcc 标志)。 - malat
1
如果cmake正在使用gnu编译器(即gcc),它将默认使用扩展(gnu+11 gnu++14等)。如果您想限制仅使用标准,则需要在创建目标之前指定set(CMAKE_CXX_EXTENSIONS OFF)。 - Dredok

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接