ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | Q&A answers.ros.org

# How do you "colcon build" with a specific C++ version?

## Problem (TL;DR)

How do I run colcon build with the C++ version set specifically to 17, and without having to manually edit every CMakeList file in my system?

## Problem (in detail)

I am currently encountering a problem whilst compiling on a Ubuntu 20 system, with ROS Galactic and ROS2 Foxy both installed. I want to compile my ROS2 code using Galactic (not Foxy) so I have made sure that I have sourced only the setup file for that distro. But when I run colcon build I get a nebulous error that suggests the problem is that a pre-C++17 standard is being used:

/opt/ros/galactic/include/rclcpp/any_subscription_callback.hpp:81:29: error: ‘variant’ in namespace ‘std’ does not name a
template type
81 |   using variant_type = std::variant<
|                             ^~~~~~~
/opt/ros/galactic/include/rclcpp/any_subscription_callback.hpp:81:24: note: ‘std::variant’ is only available from C++17 onwards
81 |   using variant_type = std::variant<
|                        ^~~


This error doesn't reference any of my code directly, and seems to indicate that the rclcpp package in Galactic is failing to compile because C++17 isn't being used. I'm surprised by this as there are a a few posts around the place suggesting that Galactic requires C++17 (see here) but I couldn't find any reference to this on the Galactic release page. This also doesn't appear to be a known issue with rclcpp (see the issue tracker)

I couldn't find any reference to "CXX" or "C++" versions in the colcon documentation either, but through colcon build help figured out that the following command should in _theory_ set the C++ version:

\$ colcon build --cmake-args -DCMAKE_CXX_FLAGS='-std=c++17'


However this doesn't appear to work as I get the same error. I know that I _can_ force individual packages to compile with a specific version using this code snippet in the CMakeList file:

if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()


However, I would rather not have to change the CMakeList files of all the packages in my codebase, and I'm pretty sure that changing the version via colcon build should have worked. So my questions are:

1. How do you force colcon to use a specific C++ standard?
2. Why didn't setting it via -DCMAKE_CXX_FLAGS='-std=c++17' work?
3. If this isn't the solution to the std::variant build error, can someone please point me in the direction of the solution?

I suspect that the cause of the std::variant build error has something to do with the fact that I have Foxy installed on the same system. But I haven't worked out why yet.

edit retag close merge delete

a Ubuntu 20 system, with ROS Galactic and ROS2 Foxy both installed

how did you install ROS?

( 2021-08-10 01:44:54 -0500 )edit

Docker container with an image pulled from osrf/ros:foxy-desktop or osrf/ros:galactic-desktop.

( 2021-08-12 00:05:15 -0500 )edit

Sort by » oldest newest most voted

As you already know, asking multiple questions in a single post is not really a good idea, so:

If this isn't the solution to the std::variant build error, can someone please point me in the direction of the solution?

this would seem to be the actual question.

With the information in your current post I can't say what is causing your problem.

rclcpp on Galactic already sets the C++ version to 17 (from here):

# Default to C++17
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
endif()


You should not need to change anything there.

To see what's happening, you could try to see what Colcon CMake is actually executing with:

colcon build \
--event-handlers console_direct+ \
--cmake-args \
-DCMAKE_VERBOSE_MAKEFILE=ON


(and perhaps a --packages-up-to or --packages-select to avoid trying to build everything)

That could give you a clue as to which exact commands are being executed.

Having written that: overriding the specific C++ standard for a CMake project isn't really anything specific to Colcon, but more a CMake "thing".

You don't set CMAKE_CXX_FLAGS to -std=c++17, but set CMAKE_CXX_STANDARD to 17 directly.

I would expect the command you show to work with that one change (I like to split things across multiple lines for readability, this is still just a single command):

colcon build \
--cmake-args \
-DCMAKE_CXX_STANDARD=17


(make sure to remove the build directory from your workspace to avoid CMake caching things)

If it still doesn't work, that would imply something else is wrong.

PS: note that if you'd like to build only specific packages with specific cmake-args, you'd use a Colcon meta file. The command line as proposed by you will apply to all packages built by that specific Colcon invocation.

I'm surprised by this as there are a a few posts around the place suggesting that Galactic requires C++17 (see here) but I couldn't find any reference to this on the Galactic release page.

Minimum language requirements:

• C++17

as well as on the Galactic version of the Code style and language versions page:

Standard

Galactic targets C++17.

more

Thanks for the help gvdhoorn! You're right, I probably should have separated this into two questions. I was in a rush and got lazy. Building with C++17 did solve the problem though!

( 2021-08-11 23:59:53 -0500 )edit

So are you enabling C++17 in your own package(s)?

( 2021-08-12 00:49:53 -0500 )edit

Not initially, as my own packages only require C++11 or 14.

( 2021-08-12 01:07:10 -0500 )edit

Then how would you #include a header which does require C++17?

( 2021-08-12 02:00:04 -0500 )edit

Well, the contents of my packages don't require C++17, but many have use a similar snippet of code to what you posted in your answer in their CMakeLists file to set CMAKE_CXX_STANDARD to C++14.

When I posted this question I didn't understand how this error could be occurring. But looking back through my code and your answer, what I think has happened is those code snippets have set the CMAKE_CXX_STANDARD to 14. I assume that this is a global flag, so when those packages include various rclcpp headers from (in this case) Galactic, that C++ standard is applied to the compilation of those Galactic headers (which need C++17 minimum). My CMake knowledge is pretty patchy in this area, so please correct me if any of this is wrong.

( 2021-08-12 02:15:57 -0500 )edit

I assume that this is a global flag

no, it's per-package, local only.

CMake projects can export that requirement using target_compile_features(..), but you must link to such projects / libraries using target_link_libraries(..) and I'm not exactly sure (any more) whether Ament doesn't interfere there.

( 2021-08-12 03:02:26 -0500 )edit

Ah, there goes my theory then. Ament causing extra complication is entirely possible, since I've been using ament_auto a lot to try and simplify my CMakeList files.

( 2021-08-12 03:08:23 -0500 )edit

Just to clarify: it's local in the sense it's not automatically exported to other packages.

But if you set a specific standard for your package, and then include headers from other projects, those headers will be #included by the compiler under the standard you've set for your package.

So this:

when those packages include various rclcpp headers from (in this case) Galactic, that C++ standard is applied to the compilation of those Galactic headers (which need C++17 minimum)

is essentially correct (ie: C++17-requiring headers are interpreted as C++14 due to your local standard selection).

That was also why I asked:

Then how would you #include a header which does require C++17?

However, if a CMake project uses target_compile_features(..) and exports that target, your local C++14 would be overridden by the C++17 of the target you target_link_libraries(..) against.

But again, that ...(more)

( 2021-08-12 03:29:24 -0500 )edit