在CMake

时间:2018-01-08 10:21:07

标签: c++ c++11 cmake

CMake有一个nice framework用于设置和定义C ++标准的显式值,通常是:

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)

然而,这显然不符合我的需要,我宁愿说明我至少需要 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)

,其中

$ cat foobar.cxx 
int main()
{
  char * p = nullptr;
}

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

$ c++ -dumpversion
6.3.0

导致:

$ 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

有没有办法说:"用至少C ++ 11标准版建立这个项目"在CMake?

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

更新:以下内容超出了问题的范围,但由于我收到了来自@ComicSansMS的冗长答案,我觉得我需要澄清对此的需求。

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

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

  1. 为正在构建的库的接口定义c ++标准版本
  2. 为正在构建的库的实现细节定义c ++标准版本。
  3. 从Debian维护者角度设置显式地,C ++标准版本使得在更新库SONAME时很难重建包存档的一部分。让我们考虑GDCM正在使用Poppler库的情况。虽然GDCM的实现细节是使用C ++ 98编写的,但是使用默认(隐式)标准版本的gcc-6构建Poppler库的事实使得它突然成为GDCM的编译失败,因为显式{{1}正在通过。

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

2 个答案:

答案 0 :(得分:2)

您可以随时自行测试特定标准标志的存在。

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

可以使用the CheckCXXCompilerFlag module轻松检查标志。

这些天你可能应该从-std=c++17开始。您可能还希望为预发布标准版本添加检查,例如c++1z(对于C ++ 17)和c++1y(对于C ++ 14)。

从最高版本开始,然后以最低要求版本向下工作。当它没有失败时停止。

答案 1 :(得分:2)

  

有没有办法说:"用至少C ++ 11标准版建立这个项目"在CMake?

不,这可能不合理。

没有任何理由要求比您尝试构建的代码更新的标准版本,因为您的代码无论如何都不会使用这些功能。

另一个大问题是新标准不是旧标准的严格超集。在最近的版本中,C ++标准一直非常热衷于弃用甚至删除已经失效的功能。

您拥有的是一段特定的代码,需要一组特定的语言功能。这正是你应该告诉构建系统的东西。如果您的代码希望C ++ 11功能可用,请将CMAKE_CXX_STANDARD设置为11并完成。它将保证所有必需的功能都可用,并保护您(在合理的范围内)以防止将来的任何弃用。

现在,有一种情况是指定精确的标准是不够的:您可能在代码中有不同的实现,然后根据可用的编译器功能在实现之间切换。也就是说,您的代码可能是C ++ 14感知的,并且您希望它在C ++ 14模式下编译(如果可用),但仍然将C ++ 11模式作为后备。

这正是default behaviour of CMAKE_CXX_STANDARD

  

这意味着使用:

set_property(TARGET tgt PROPERTY CXX_STANDARD 11)
     

使用编译器   不支持-std=gnu++11或等效标志的不会   导致错误或警告,但会添加-std=gnu++98   如果支持则标记。这种“衰变”行为可以用   CXX_STANDARD_REQUIRED目标财产。

简而言之,请始终指定您的代码所知道的最新标准,而不是更新。

相关问题