Skip to content
Snippets Groups Projects

[CMake] Rewrite C++ standard detection

Merged Steffen Müthing requested to merge feature/cmake-rewrite-c++-standard-detection into master

This is a complete rewrite of the existing C++ standard version test that tries the various -std=c++xy flags and tries to figure out which version of the standard to enable.

The existing version has a few problems:

  • it is not really extensible to newer standards, those will just lead to a deeper and deeper nesting of if statements.

  • More importantly, there is no way to say: I want C++11, but not C++14 (or, in the future, I want C++14, but not C++17). Being able to do so is important for testing and compatibility reason.

  • There is no easy way for downstream modules to require a newer version of the standard than the core modules.

Test logic

The new version of the test separates the logic from the data (versions, flag names, compiler test sources) and just iterates over lists of that data, in descending order to make sure the newest available standard gets picked. The numerical value of that standard is stored in the variable CXX_MAX_SUPPORTED_STANDARD and the test stops. If the test fails to find a working combination, it issues a warning to the user and only records support for C++03.

The test can be influenced by two CMake variables:

  • DISABLE_CXX_VERSION_CHECK already existed in the old version of the test. It completely disables all testing and requires the user to manually set CXX_MAX_SUPPORTED_STANDARD to the correct value. Moreover, any required compiler command line switches have to be manually added to CMAKE_CXX_FLAGS.

  • CXX_MAX_STANDARD defines the maximum version of the standard that the build system will try to enable. With this new switch, it becomes possible to limit the compiler to an older version of the standard than what it could theoretically support. For now, this defaults to C++14.

Requirements check with a new CMake function

In order to allow module authors to easily state their minimum version requirements, there is a new CMake function dune_require_cxx_standard() that any Dune module can call to require support for at least a given C++ standard:

dune_require_cxx_standard(MODULE "dune-functions" VERSION 14)

If the compiler doesn't meet the requirements, the function will report the required and the actually available standard versions and abort with a fatal error.

Moreover, it knows about CXX_MAX_STANDARD and will tell the user if the value of that variable is below the requirements. This avoids desperate users that have a shiny beta of GCC 6 with C++17 support wondering why their own module using shiny C++17 concepts stubbornly fails to build...

Backporting

I would very much like to backport this to 2.4.1 as it would get rid of the dirty hackery currently required in dune-functions and PDELab. For the backported version, I'm not sure about the best value for CXX_MAX_STANDARD: 11 or 14?

This fixes #16 (closed), and a backport to 2.4 would also be a fix for #15 (closed).

Merge request reports

Loading
Loading

Activity

Filter activity
  • Approvals
  • Assignees & reviewers
  • Comments (from bots)
  • Comments (from users)
  • Commits & branches
  • Edits
  • Labels
  • Lock status
  • Mentions
  • Merge request status
  • Tracking
  • Steffen Müthing Added 1 commit:

    Added 1 commit:

    • 0b825996 - [CMake] It's -std=c++0x, of course
  • mentioned in issue #17 (closed)

    • Probably you want to use the stuff CMake already provides, at least in the case CMake is recent enough. Since CMake 3.1 CMAKE_CXX_STANDARD can be set to 98, 11 or 14 and it will error out if the required version is not met. CMake has a list for a lot of compilers with the right flags.
      Documentation: https://cmake.org/cmake/help/v3.4/prop_tgt/CXX_STANDARD.html

    • Unfortunately, that isn't enough for some of our use cases. We have some weird situations that CMake doesn't typically assume, like the issue that first cropped up when you added C++14 detection support and Marian's build broke because he had installed a recent Clang (which had C++14 support) into his home directory that was using the libstdc++ from his system (which didn't). Kaboom!

      So we really need to make sure that the compiler is paired with a matching library, because there are quite a few people with weird compiler setups to work around their old Linux distribution etc. And AFAIK CMake just uses a pre-built table for this which won't catch problems with those oddball configurations.

      PS: And I want to be able to specify C++17 :wink:

    • Please register or sign in to reply
  • mentioned in issue #16 (closed)

  • Added 1 commit:

    • 9e7bdaba - [CMake] Remove spurious character in C++14 test
  • Whoops, thanks for spotting that one... That was in there intentionally to cause the test to fail, and I forgot to take it out again.

  • To the CMake people: Are there any concerns about merging this? And do you have an opinion about the default C++ standard mode for the 2.4 branch? 11 or 14? I would prefer 14, but I can understand if there are concerns about changing behaviour like that in a release branch.

  • If there are no big buts, I will merge this later today. Sorry for rushing, but I want this in the release branch so that I can make a first RC.

  • I tested it and it works for me. The code is ok. I don't mind whether we should use C++11 or C++14 by default.

  • Elias Pipping
    Elias Pipping @pipping started a thread on commit daa2e9f4
68 74
69 endfunction()
75 int main() {
76 // this checks both the compiler (by using auto) and the library (by using
77 // std::make_shared() for C++11 compliance at GCC 4.4 level.
78 auto v = std::make_shared<int>(0);
79 return *v;
80 }
81 ")
82
83 # build a list out of the pre-escaped tests
84 set(CXX_VERSIONS_TEST "${cxx_17_test}" "${cxx_14_test}" "${cxx_11_test}")
85
86 # these are appended to "-std=c++" and tried in this order
87 # note the escaped semicolons; that's necessary to create a nested list
88 set(CXX_VERSIONS_FLAGS "17\;1z" "14\;1y" "11\;1x")
  • OK, I'll backport this with C++14 as default mode then. It shouldn't really break anything, but release managers for 2.4 point releases will have to make sure to limit their compiler to C++11 during testing. But there's not a lot of release managers, so I don't think that is going to be a problem.

  • mentioned in commit 31252385

  • Steffen Müthing Status changed to merged

    Status changed to merged

  • mentioned in commit c293cf77

  • It might be worth pointing out that even libstdc++ 4.9 has gaps in C++11 support. Here's a taste:

    /usr/include/c++/4.9/type_traits:  // is_trivially_copyable (still unimplemented)
    /usr/include/c++/4.9/type_traits:  /// is_trivially_constructible (still unimplemented)
    /usr/include/c++/4.9/type_traits:  /// is_trivially_default_constructible (still unimplemented)
    /usr/include/c++/4.9/type_traits:  /// is_trivially_copy_constructible (still unimplemented)
    /usr/include/c++/4.9/type_traits:  /// is_trivially_move_constructible (still unimplemented)
    /usr/include/c++/4.9/type_traits:  /// is_trivially_assignable (still unimplemented)
    /usr/include/c++/4.9/type_traits:  /// is_trivially_copy_assignable (still unimplemented)
    /usr/include/c++/4.9/type_traits:  /// is_trivially_move_assignable (still unimplemented)
    /usr/include/c++/4.9/type_traits:  /// is_trivially_destructible
  • Yes, but that's not really much of a problem - those are really for special-casing optimized algorithms, and as any 2.4 release will need testing against GCC 4.4, the release manager probably has bigger fish to fry... :sunglasses:

  • Mentioned in commit 31252385

  • Please register or sign in to reply
    Loading