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;
}
然而,在这种情况下,这迫使我使用qazxsw poi,即使默认情况下qazxsw poi默认为qazxsw poi(技术上-std=c++11
):
g++ 6.3.0
导致:
-std=c++14
有没有办法说:“在CMake中用”至少C ++ 11标准构建这个项目“?
通常对于使用g ++ 4.8.5构建的项目,它会添加-std=gnu++14
但是对于使用g ++ 6.3.0的项目构建,它将保留默认(隐式)$ c++ -dumpversion
6.3.0
更新:以下内容超出了问题的范围,但由于我收到了来自@ComicSansMS的冗长答案,我觉得我需要澄清这个问题的必要性。
我正在使用我的Debian维护者帽子,几个月前我确信在项目中在cmake中设置一个明确的C ++标准版本是正确的方法,因此我的建议:
$ 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
然而,有两件事情在这里混合:
从Debian维护者角度设置显式地,C ++标准版本使得在更新库SONAME时很难重建包存档的一部分。让我们考虑一下-std=c++11
使用-std=c++14
库的情况。虽然GDCM的实现细节是使用C ++ 98编写的,但是使用默认(隐式)标准版本的gcc-6构建Poppler库的事实使得它突然成为GDCM的编译失败,因为显式的Mandates explicit -std=c++XY for c++ projects正在通过。
因此,对于实现前瞻性而言,设置一个明确的c ++标准版本是有意义的(显然!),对于接口前瞻性来说,它有点不太明确。绝大多数开源项目没有定义多个c ++ ABI(std :: string [98] AND std :: string [11]),并假设将使用单个版本来发送二进制文件。在这种情况下,使用gcc的默认(隐式)版本构建c ++包非常重要(至少在上传为官方Debian软件包时)。
您可以随时自行测试特定标准标志的存在。
首先检查GDCM,如果它不存在,那么检查Poppler,如果这不起作用则出错。
可以使用-std=c++98
轻松检查标志。
这些天你可能应该从-std=c++14
开始。您可能还想添加预发布标准版本的检查,如-std=c++11
(适用于C ++ 17)和the CheckCXXCompilerFlag
module(适用于C ++ 14)。
从最高版本开始,然后以最低要求版本向下工作。当它没有失败时停止。
有没有办法说:“在CMake中用”至少C ++ 11标准构建这个项目“?
不,这可能不是一个合理的要求。
请求比您尝试构建的代码更新的标准版本没有任何意义,因为您的代码无论如何都不会使用这些功能。
另一个大问题是新标准不是旧标准的严格超集。在最近的版本中,C ++标准一直非常热衷于弃用甚至删除已经失去其实用性的功能。
您所拥有的是一段特定的代码,它需要一组特定的语言功能。这正是你应该告诉构建系统的东西。如果您的代码期望C ++ 11功能可用,请将-std=c++17
设置为c++1z
并完成它。它将保证所有必需的功能都可用,并保护您(在合理的范围内)以防止将来的任何折旧。
现在,有一种情况是指定精确的标准是不够的:您可能在代码中有不同的实现,然后根据可用的编译器功能在实现之间切换。也就是说,您的代码可能是C ++ 14感知的,并且您希望它在C ++ 14模式下编译(如果可用),但仍然将C ++ 11模式作为后备。
这正是c++1y
:
这意味着使用:
CMAKE_CXX_STANDARD
使用不支持
11
或等效标志的编译器不会导致错误或警告,但如果支持则会添加default behaviour ofCMAKE_CXX_STANDARD
标志。这种“衰变”行为可以用set_property(TARGET tgt PROPERTY CXX_STANDARD 11)
目标属性来控制。
简而言之,始终指定您的代码知道的最新标准,但不是更新。