Reputation: 12510
CMake has a nice framework for setting and defining an explicit value for the C++ standard, typically:
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
However this does not clearly fit my needs, I'd rather states that I need at least c++11. I thought that I could just do instead:
$ 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)
where
$ cat foobar.cxx
int main()
{
char * p = nullptr;
}
However again in this case this forces me to use -std=c++11
eventhough by default g++ 6.3.0 default to -std=c++14
(technically -std=gnu++14
):
$ c++ -dumpversion
6.3.0
leads to:
$ 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
Is there a way to say: "Build this project with at least C++11 Standard" in CMake ?
Typically for a project built using g++ 4.8.5 it would add -std=c++11
but for a project build with g++ 6.3.0 it would leave the default (implicit) -std=c++14
Update: The following is out of the scope for the question, but since I received a lengthy answer from @ComicSansMS, I feel I need to clarify the need for this.
I am working with my Debian Maintainer hat on, and I was convinced a couple of months back that setting an explicit C++ standard version in cmake within a project was the right way to do, hence my proposal:
However there are two things that get mixed here:
From a Debian Maintainer perspective setting explicitly a C++ standard version makes it hard to rebuild a portion of the package archive when a library SONAME is being updated. Let's consider the case where GDCM is using the Poppler library. While the implementation details of GDCM are written using C++98, the fact that Poppler library has been build using the default (implicit) standard version of gcc-6 makes it suddenly a compilation failure for GDCM, since an explicit -std=c++98
is being passed.
So while for an implementation prospective, setting an explicit c++ standard version make sense (obviously!), it is a little less clear for an interface prospective. The vast majority of open-source projects do not define multiple c++ ABI (std::string[98] AND std::string[11]) and assume a single version will be used to ship the binary. In this case it makes it important for a c++ package to be build using the default (implicit) version of gcc (at least when uploaded as official Debian package).
Upvotes: 7
Views: 6465
Reputation: 409472
You can always test for compilers support of the specific standard flags yourself.
First check for -std=c++14
, and if it doesn't exist then check for -std=c++11
, and if that doesn't work then error out.
Flags can easily be checked with the CheckCXXCompilerFlag
module.
These days you should probably start with -std=c++17
though. You might also want to add checks for the pre-release standard versions like c++1z
(for C++17) and c++1y
(for C++14).
Start with the highest version, then work your way downward the minimum required version. Stop when it doesn't fail.
For newer versions of CMake you could use target_compile_features
to specify features that the target compiler should be able to provide for.
This way, if (for example) your project uses auto
type deduction you could tell CMake that the compiler need to suport the cxx_auto_type
feature. Then CMake will make sure that the compiler can indeed support C++11 and the auto
type deduction.
Upvotes: 2
Reputation: 54737
Is there a way to say: "Build this project with at least C++11 Standard" in CMake ?
No, and this is probably not a reasonable thing to request.
It does not make any sense to request a standards version that is newer than the code you are trying to build, as your code will not make any use of those features anyway.
The other big problem here is that newer standards are not strict supersets of older standards. In recent versions, the C++ standard has been quite keen on deprecating and even removing features that have outlived its usefulness.
What you have is a specific piece of code that expects a specific set of language features to be available. And that is exactly what you should tell the buildsystem. If your code expects the C++11 features to be available, set CMAKE_CXX_STANDARD
to 11
and be done with it. It will guarantee that all of the required features are available and safeguard you (within reasonable bounds) against any future deprecations.
Now, there is one scenario where specifying an exact standard is not enough: You might have different implementations in your code and then want to switch between implementations depending on the available compiler capabilities. That is, your code might be C++14 aware and you want it to compile in C++14 mode if available, but still leave the C++11 mode as a fallback.
This is exactly the default behaviour of CMAKE_CXX_STANDARD
:
This means that using:
set_property(TARGET tgt PROPERTY CXX_STANDARD 11)
with a compiler which does not support
-std=gnu++11
or an equivalent flag will not result in an error or warning, but will instead add the-std=gnu++98
flag if supported. This “decay” behavior may be controlled with theCXX_STANDARD_REQUIRED
target property.
So in a nutshell, always specify the latest standard that your code is aware of, but not newer.
Upvotes: 2