How to request C++11 or later on a CMake-target? - c++

(This question is really about the "or later"-part.)
I'm a aware of the other answers which are telling us out to activate C++11 on a target/project in cmake.
My question is really how do we express C++11 or later.
As of CMake 3.8 we have the cxx_std_11-feature which forces C++11 on compilers (-std=c++11) which even support later standards and may even default to C++14 (gcc-7) or even 17 (gcc-8, iiuc).
There is also the CXX_STANDARD-target-property, but this is not transitive and also force the exact standard and not the "or later"-option.
The only way I found until now is to require cxx_range_for (or a similar feature) which makes CMake keep the default C++-standard of the compiler if at least C++11 is supported. This is supported as of CMake 3.1.
What is the correct way to select C++11 or later of a CMake-target?

Unfortunately there's no way to ask for a range of standards in CMake.
Then only way (that I have used in the past) is to use e.g. check_cxx_compiler_flag to check for -std=c++20, -std=c++17, -std=c++14 and -std=c++11 (in that order) and use the highest with e.g. target_compile_options.
If none of the flags listed is supported, then error out.

As #Some programmer dude pointed out, only way to do so is to check for C++17, then C++14 then C++11. Looking into CMake sources itself gives interesting idea how to do it in platform-agnostic way. In here try_compile command is used with corresponding CMAKE_CXX_STANDARD passed, so CMake itself determines which compiler flag should be used. Thus to check for C++14:
try_compile(CMake_CXX14_WORKS
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_LIST_DIR}/cm_cxx14_check.cpp
CMAKE_FLAGS -DCMAKE_CXX_STANDARD=14
OUTPUT_VARIABLE OUTPUT
)
where cm_cxx14_check.cpp is dummy file with main.
This is key idea here, although full logic also checks if CMAKE_CXX_STANDARD wasn't already defined or if CMake knows CMAKE_CXX_STANDARD=17 (CMake >= 3.8). Also, CMake checks for newest standard only for GNU or Clang, but I believe it is because it is not needed in MSVC in non-library code. MSVC has always enabled the newest standard by default.
Unfortunately, here is some also a corner case with GNU 4.8: "The GNU 4.8 standard library's cstdio header is not aware that C++14 honors C11's removal of "gets" from stdio.h and results in an error"

Related

How to find default supported C++ standard by g++ compiler in cmake

I saw many threads regarding how to enable certain C++ standard e.g.
add_definitions("-std=c++14")
and
set (CMAKE_CXX_STANDARD 11)
But how to find which standard by default g++ compiler following while compiling code ?
add_definitions("-std=c++14") is not the correct way to enable C++14. The right way either the second one you mentioned: set(CMAKE_CXX_STANDARD 14), or set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14").
add_definitions is for macro definitions, equivalent to #define in your source code.
About your question, it's bad practice to depend on the default version of C++ in your compiler. Even Visual Studio now defines the standard you want to use, which is a new thing in VS. Standards are made to solve this problem by having them specified. So, in your project, you define the target standard, and you define it in your make file. You should not expect your code to work on all C++ standards.
If you're developing an application, then you should not adjust your code based on available compiler version, instead you should specify which compiler standard your code requires:
set (CMAKE_CXX_STANDARD 11)
If you're building a code library that is meant to be used in different contexts, use compiler feature detection and conditional compilation. For example:
write_compiler_detection_header(
FILE "${CMAKE_CURRENT_BINARY_DIR}/compiler_features.h"
PREFIX Foo
COMPILERS GNU
FEATURES
cxx_variadic_templates
)
And then:
#include "compiler_features.h"
#if Foo_COMPILER_CXX_VARIADIC_TEMPLATES
# include "with_variadics/interface.h"
#else
# include "no_variadics/interface.h"
#endif
This is especially useful with compilers like MSVC which have many features from C++17 while also lacking some basic features from C++11 (e.g. expression SFINAE).
CMake has built-in detectors for many popular C++ features.
PS. If you're really curious, G++ up to 5.0 uses by default gnu++98 standard, and from 6.0 gnu++14 (GNU dialect of -std=c++14).

What is the default C++ standard in an Eclipse CDT project?

I am using Eclipse CDT 3.8.1 with GCC Cross Compiler 8.6.0. I know how to change the C++ standard in the project properties, but I don't know what standard is used by default.
I know the default is not C++11 and the Eclipse language support page doesn't mention C++03, so I suspect the default is C++98. However, Eclipse CDT must support C++03 because adding the compiler flag -std=c++03 doesn't cause any errors.
https://www.eclipse.org/community/eclipse_newsletter/2017/april/article3.php
What is the default standard when I create a new project?
Eclipse's parser itself doesn't have a notion of a C++ standard mode. It will recognize all the C++ features that have been implemented in its parser (which, as of writing this, is all C++98 and C++11 features, some (but not all) C++14 features, and a handful of C++17 features).
However, standard library headers often contain sections that are conditional on macros denoting the C++ standard version (e.g. #if __cplusplus >= 201103 is a common check for "C++11 or later"). To determine the value of these macros, Eclipse invokes the compiler specified in the project's toolchain to discover built-in macros. The discovered value of e.g. the __cplusplus macro will depend on what standards mode the compiler runs in for this invocation.
The flags to this compiler invocation are specified in the project properties, as you mentioned. If you don't provide a flag there, the compiler will use whatever its default mode is. I believe GCC has been using -std=c++14 as the default from GCC 6 onwards. (Though I don't quite know what "GCC Cross Compiler 8.6.0" is. According to the GCC website, the latest version is 8.1.)

Inducing minimal C++ standard version in CMake

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:
Mandates explicit -std=c++XY for c++ projects
However there are two things that get mixed here:
Defining a c++ standard version for the interface of the library being built
Defining a c++ standard version for the implementation detail of the library being built.
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).
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.
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 the
CXX_STANDARD_REQUIRED target property.
So in a nutshell, always specify the latest standard that your code is aware of, but not newer.

Checking for C++11 library features

What is a good way of checking for the presence of specific C++11 features of the standard library.
For compiler features I just went by the way of checking the compiler version for the (IMHO) major compilers (VC++, gcc, clang at the moment, maybe Intel) Although this is not the best and most flexible approach, I don't know of anything better yet, except for clang which has the really nice __has_feature macros.
But it's even worse for library features, which are not coupled that rigidly to the compiler. At the moment I want to use the same approach of checking the compiler version for VC++ (where it's pretty easy, assuming it uses its own library). For clang I can at least use __has_include for large-scale header-based queries. Other than that I guess checking __GLIBCXX__'s value if defined might be a good idea, but then again I cannot find any information of what specific libstdc++ versions introduced which features, other than what the current version supports.
The methods should be kept to preprocessor checks and the like, since I want to use it in a header-only library without any sophisiticated configure procedure and without using any third-party libraries (and yes, boost is third-party).
So what are my possibilities of checking for specific C++11 library features under those (pretty narrow) conditions. Maybe even on the scale of particular functions or types being declared?
If checking for the compiler or library version is still the best approach, where can I find detailed information about the particular C++11 features supported by a specific version of libstdc++ (and maybe other important ones, libc++ perhaps)?
FWIW at the moment I'm interrested in <cstdint>, C++11 <cmath> functions and std::hash, but this may change and is probably not of importance for the general approach.
There is really nothing nice you can do here besides knowing which compiler in which version implements what and have the proper defines in place.
gcc has a special table for library functionality. The main problem of __has_include are of course additions to the standard that live in old includes. libstdc++ also has the necessary includes, but that doesn't mean the necessary define to enable the content of those files. It also wont tell you anything about the actual amount of available implementation (which sometimes is incomplete).
As you have a header-only library this doesn't apply to you, but is still important: binary incompatibility between C++11 and C++03 can come back and bite you.
I seriously wouldn't approach any of that on my own and rather use Boost.Config. Originally it only described language features but has now expanded to standard library headers.
You could write autoconf macros to check, and if you do, submit them to http://www.gnu.org/software/autoconf-archive/
The only relevant one so far checks for complete coverage, not for individual features: http://www.gnu.org/software/autoconf-archive/ax_cxx_header_stdcxx_0x.html#ax_cxx_header_stdcxx_0x
But that fails the requirement for no complicated configure checks.
Other than that I guess checking __GLIBCXX__'s value if defined might be a good idea,
Looking at the value of __GLIBCXX__ is not useful, it contains the date the version was released which tells you almost nothing about the version (e.g. 4.6.3 is released after 4.7.0 so has a later date in __GLIBCXX__ but has fewer C++11 features.) When using libstdc++ with GCC you want to use the general GCC version numbers in __GLIBC__ and __GLIBC_MINOR__ for checking versions (in general you can only use a given version of libstdc++ with the GCC release it came with.)
Edit: Starting with GCC 7 there is a new macro defined by the libstdc++ headers, _GLIBCXX_RELEASE, which is defined to the same value as GCC's __GNUC__, but is still usable even when using the libstdc++ headers with non-GCC compilers.
but then again I cannot find any information of what specific libstdc++ versions introduced which features, other than what the current version supports.
The libstdc++ C++11 status tables for previous releases are available online where all GCC docs live: http://gcc.gnu.org/onlinedocs/
For 4.7 it's at http://gcc.gnu.org/onlinedocs/gcc-4.7.1/libstdc++/manual/manual/status.html#status.iso.2011 and for 4.6 it's at http://gcc.gnu.org/onlinedocs/gcc-4.6.3/libstdc++/manual/manual/status.html#status.iso.200x and for previous releases is included with the source (but the coverage in pre-4.6 releases is pretty patchy anyway.)
Some added features are listed in the release notes for each version, e.g. http://gcc.gnu.org/gcc-4.7/changes.html (in the libstdc++ section)
Edit: For C++17 library support we now list which version first added the feature, so you only need to look at the latest docs: https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.201z
FWIW at the moment I'm interrested in <cstdint>, C++11 <cmath> functions and std::hash
They should be present in all versions of libstdc++ that have any C++0x/C++11 support.

C++11 feature checking

How do I check for presence of individual C++0x/C++11 language features? I know Clang has a nice system for this. What about GCC, Visual Studio or Boost? I guess one way to do it is to detect the compiler version and relate that to the features introduced in that version. But that is cumbersome. Has someone already done that?
boost config comes with a script to check for some but not all C++11 features.
It generates a config-file with macros for each feature.
Your build-tool may be able to help with this.
CMake has the try_compile command which allows you to test whether a code sample will compile and set a variable based on the result of compilation.
At the moment I've just been using the more commonly supported features such as auto typing.
You can often use Boost to replace the missing library features, and this may be the best option for a few year while compilers and libraries are updated and bugs fixed.
The C++11 feature compatibility list for GCC is here: http://gcc.gnu.org/projects/cxx0x.html
Note the warning:
Important: GCC's support for C++11 is still experimental. Some features were implemented based on early proposals, and no attempt will be made to maintain backward compatibility when they are updated to match the final C++11 standard.