在 CMake 中引入最小的 C++ 标准版本

mal*_*lat 5 c++ cmake c++11

CMake 有一个很好的框架,用于为 C++ 标准设置和定义显式值,通常:

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
Run Code Online (Sandbox Code Playgroud)

然而,这显然不符合我的需求,我宁愿声明我至少需要c++11。我想我可以这样做:

$ cat CMakeLists.txt 
cmake_minimum_required(VERSION 3.7)
project(p CXX)
set(CMAKE_CXX_EXTENSIONS OFF)
add_executable(foobar foobar.cxx)
target_compile_features(foobar PRIVATE cxx_nullptr)
Run Code Online (Sandbox Code Playgroud)

在哪里

$ cat foobar.cxx 
int main()
{
  char * p = nullptr;
}
Run Code Online (Sandbox Code Playgroud)

然而,在这种情况下,这再次迫使我使用-std=c++11即使默认情况下g++ 6.3.0默认为-std=c++14(技术上-std=gnu++14):

$ c++ -dumpversion
6.3.0
Run Code Online (Sandbox Code Playgroud)

导致:

$ make VERBOSE=1
[...]
make[2]: Entering directory '/tmp/p'
[ 50%] Building CXX object CMakeFiles/foobar.dir/foobar.cxx.o
/usr/bin/c++     -std=c++11 -o CMakeFiles/foobar.dir/foobar.cxx.o -c /tmp/p/foobar.cxx
[100%] Linking CXX executable foobar
/usr/bin/cmake -E cmake_link_script CMakeFiles/foobar.dir/link.txt --verbose=1
Run Code Online (Sandbox Code Playgroud)

有没有办法在 CMake 中说:“至少使用 C++11 标准构建此项目”?

通常,对于使用 g++ 4.8.5 构建的项目,它会添加-std=c++11,但对于使用 g++ 6.3.0 构建的项目,它将保留默认值(隐式)-std=c++14


更新:以下内容超出了问题的范围,但由于我收到了 @ComicSansMS 的冗长答案,我觉得我需要澄清这一点的必要性。

我正在使用我的 Debian 维护者帽子,几个月前我确信在项目中的 cmake 中设置显式 C++ 标准版本是正确的方法,因此我的建议是:

然而,这里有两件事混合在一起:

  1. 为正在构建的库的接口定义 C++ 标准版本
  2. 为正在构建的库的实现细节定义 C++ 标准版本。

从 Debian 维护者的角度来看,明确设置 C++ 标准版本使得在更新库 SONAME 时很难重建包存档的一部分。让我们考虑GDCM使用Poppler库的情况。虽然 GDCM 的实现细节是使用 C++98 编写的,但 Poppler 库是使用默认(隐式)标准版本的 gcc-6 构建的,这使得 GDCM 突然编译失败,因为正在-std=c++98传递显式的内容。

因此,虽然对于实现前景来说,设置显式的 C++ 标准版本是有意义的(显然!),但对于接口前景来说就不太清楚了。绝大多数开源项目没有定义多个 C++ ABI(std::string[98] 和 std::string[11]),并假设将使用单个版本来传送二进制文件。在这种情况下,使用 gcc 的默认(隐式)版本构建 c++ 包非常重要(至少在作为官方 Debian 包上传时)。

Som*_*ude 1

您始终可以自己测试编译器对特定标准标志的支持。

首先检查-std=c++14,如果不存在则检查-std=c++11,如果不起作用则出错。

使用该CheckCXXCompilerFlag模块可以轻松检查标志。


现在你可能应该开始了-std=c++17。您可能还想添加对预发布标准版本的检查,例如c++1z(对于 C++17)和c++1y(对于 C++14)。

从最高版本开始,然后逐步降低所需的最低版本。当它没有失败时停止。


对于较新版本的 CMake,您可以使用target_compile_features指定目标编译器应该能够提供的功能。

这样,如果(例如)您的项目使用auto类型推导,您可以告诉 CMake 编译器需要支持该cxx_auto_type功能。然后CMake将确保编译器确实可以支持C++11和auto类型推导。