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 ++标准版本是正确的方法,因此我的建议:
然而,有两件事情在这里混合:
从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软件包时)。
答案 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
目标财产。
简而言之,请始终指定您的代码所知道的最新标准,而不是更新。