Ask Your Question
4

The Good (C++11/14), the Bad (CMAKE_CXX_FLAGS) and the Ugly (cmake)

asked 2016-10-25 03:59:08 -0500

alextoind gravatar image

updated 2016-10-25 04:01:41 -0500

I have tried to find an updated answer with the best practices when dealing with ROS and C++11/14, but everything is messy or out of date...

0 - Setting the C++ standard directly [DEPRECATED]

I know that the quicker way to enable C++11/14 is to add in the CMakeLists.txt one of the following macros

cmake_minimum_required(VERSION 2.8.3 FATAL_ERROR)
...
set(CMAKE_CXX_FLAGS "-std=c++11")
set(CMAKE_CXX_FLAGS "-std=c++14")

even with all the possible checks (see the many answers on SO or this one). Nonetheless it is written everywhere - apparently not enough though - NOT to set CMAKE_CXX_FLAGS (e.g. catkin docs).


So I have searched a bit more to find some updated guidelines for cmake and C++11/14 like the followings: [1], [2], [3], [4]. It comes out that since cmake v3.1/3.2 there are two main methods which overcome the CMAKE_CXX_FLAGS manual setup.

1 - Setting the C++ standard directly

The standard C++11/14 can be specified directly and the *_REQUIRED protects the building from potential compiler errors if the standard is not supported.

cmake_minimum_required(VERSION 3.2.0 FATAL_ERROR)
...
set_property(TARGET target1 target2 ... PROPERTY CXX_STANDARD 11)  # 98, 11 or 14
set_property(TARGET target1 target2 ... PROPERTY CXX_STANDARD_REQUIRED ON)

References: [5], [6], [7].

Otherwise the CMAKE_* variables specify the properties for all the targets in the CMakeLists.txt ([8], [9]).

2 - Setting the C++ standard based on features

If a finer tuning or a higher control is required, the right C++ standard can be set from the features which are really used in the code. This is surely more accurate, but it requires time to be properly set (lots of features) and can be fragile if not supported correctly over time.

cmake_minimum_required(VERSION 3.2.0 FATAL_ERROR)
...
target_compile_features(myTarget
  PUBLIC
    cxx_variadic_templates
    cxx_nullptr
    ...
  PRIVATE
    cxx_lambdas
    ...
)

References: [10], [11].


Note

In every docs regarding ROS you always find cmake_minimum_required(VERSION 2.8.3) which is fine to guarantee that our code could be compiled even with older cmake version, and everybody seems happy.

The current version of cmake shipped with Ubuntu 16.04 and ROS Kinetic (both LTS, and hoping the new standard for at least a couple of years) is the 3.5.1. The drawback of allowing such an old cmake compatibility is the unkown behaviour in not tested old systems (which is the case of almost every small project). Indeed another best practice for cmake usage is to set the minimum required version to the lower testable one.

The question is: what is ROS waiting for to increase the minimum requirements to at least cmake v3.2 and to improve docs with updated best practices?

edit retag flag offensive close merge delete

Comments

re: what are we waiting for: the EOL of Trusty, which is still 2.5 years away (see wiki/Distributions)? (note: this is a question, not a statement)

gvdhoorn gravatar imagegvdhoorn ( 2016-10-25 04:34:54 -0500 )edit

Also: IIRC, CMake 2.8.3 should support setting target-specific properties via SET_TARGET_PROPERTIES and COMPILE_FLAGS. Doesn't that circumvent the problem you are implicitly describing (setting C++ standard for the entire workspace)?

gvdhoorn gravatar imagegvdhoorn ( 2016-10-25 04:38:43 -0500 )edit

Other 2.5 years of backward compatibility of cmake 2.8.3? I could understand this for Indigo and Jade, but at least Kinetic should try to use up-to-date standards in my opinion.

alextoind gravatar imagealextoind ( 2016-10-25 05:02:05 -0500 )edit

I think you could use the COMPILE_FLAGS, but I was wondering about best practices, not workaround. If I get the point from the overall references, you should never manually set compiler flags in the CMakeLists.txt.

alextoind gravatar imagealextoind ( 2016-10-25 05:08:35 -0500 )edit

Indigo and Kinetic are the two LTS releases right now. From a maintenance point of view, it makes sense to standardise on a single build infra. I'm not the OSRF, but I can imagine moving to CMake 3+ has not been high on the agenda. ROS2 has migrated to C++11/CMake 3.5+ though.

gvdhoorn gravatar imagegvdhoorn ( 2016-10-25 05:39:33 -0500 )edit
1

Perhaps this is more a discussion thing, not so much a question. Not sure, but perhaps the discourse.ros.org site might be more suited for that.

gvdhoorn gravatar imagegvdhoorn ( 2016-10-25 05:40:30 -0500 )edit

I was wondering about best practices, not workaround.

Merely trying to be pragmatic. Using set_target_properties(..) with COMPILE_FLAGS would allow you to do what you want, right now, in Indigo, even with ancient CMake.

gvdhoorn gravatar imagegvdhoorn ( 2016-10-25 05:41:55 -0500 )edit
1

Btw, Kinetic has standardised on CMake 3.0.2, see REP-3 - Platforms by Distribution - Kinetic Kame.

gvdhoorn gravatar imagegvdhoorn ( 2016-10-25 05:42:43 -0500 )edit

1 Answer

Sort by ยป oldest newest most voted
3

answered 2016-10-25 10:01:52 -0500

Dirk Thomas gravatar image

Option 0 is not recommended in catkin because if you use catkin_make which builds all packages in a single CMake context one package would override the global flags for all others. Different packages could even set different global flags. Also setting the flags should not overwrite other flags - therefore you should always extend the flags.

Option 1 sets the flags on a per-target base which is good. As long as you code only needs C++11/14 during compilation but doesn't require a C++11/14 compiler in the headers that is perfect.

But as soon as your package headers require a newer C++ compiler your package needs to "export" that information to downstream packages so that when they are being built can make sure to use the right flags. And then you again run into the same problem that multiple packages might require different compilers.

Because of these issues a Linux distribution usually picks one specific version of the compiler to build all packages of the distribution. That makes it more predictable what features are available across all package compilations. But they resolve the compiler flags necessary to build a specific package manually and don't rely on each package to export its requirements to downstream packages.

edit flag offensive delete link more

Comments

@Dirk Thomas, your answer is insightful, but it is still a bit unclear to me what is the "recommended" approach for ROS Kinetic packages that need C++11 to compile. Is there a clean way to "compile whole workspace with C++11" for compilers that don't default to it (e.g. OS X)? https://bit.ly/2HRcaJn

demmeln gravatar imagedemmeln ( 2018-04-26 03:27:20 -0500 )edit

If you want to force a specific version you can set it in an environment variable like CMAKE_CXX_FLAGS before invoking the build tool.

Dirk Thomas gravatar imageDirk Thomas ( 2018-04-27 13:54:31 -0500 )edit

Thanks. For the record, I've had success with passing additionally -DCMAKE_CXX_STANDARD=14 in catkin config to compile lunar on macos Sierra (10.12). See also related discussion: https://github.com/ros/catkin/issues/936

demmeln gravatar imagedemmeln ( 2018-05-04 06:16:59 -0500 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower

Stats

Asked: 2016-10-25 03:59:08 -0500

Seen: 4,446 times

Last updated: Oct 25 '16