Issue
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:
- 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).
Solution
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.
Answered By - Some programmer dude Answer Checked By - Willingham (WPSolving Volunteer)