ROS Resources: Documentation | Support | Discussion Forum | Service Status | Q&A

Make Ament work with another build system (for cross-compilation)

Hello !

Here is my problem : I’m porting ROS2 to microcontrollers with RIOT, but I can’t use the Ament build system for managing the cross-compilation. Indeed, RIOT has it’s own build system, and needs to compile all the sources (to manage flags, linking, etc…).

Since I still need Ament to generate rosidl things, I think it would be great to make the two work together.

Is there a way to tell Ament to only export sources/headers (generated or not), and not compile it ?
Is there a way to call the RIOT makefiles from Ament ?
Is there a way to export the path where Ament have “copied” the sources to an other build system ?
How to manage the target hardware ? Is Ament able to switch between different rosidl, rmw, build systems when the final ROS node is supposed to be cross-compiled ?

Cheers !

ament_cmake is only providing some additional features on top of CMake. Therefore you should be able to do any kind of cross compilation which is possible with CMake (if not that would be a bug and should be fixed). If you clarify why you think you can’t use it for cross-compilation someone might be able to suggest / help with it.

The build system ament_cmake is not related to the rosidl message generation. Each message generator has a command line interface which you can call from anywhere else. Thee generators have a significant amount of parameters though. The CMake provided by rosidl_cmake only helps you with the invocation of these command line tools.

No, CMake can not be used like that.

You can call arbitrary external commands from within CMake. I think ExternalProjects would be appropriate for this which you will find in the CMake docs.

I don’t understand these questions. Maybe you can elaborate what you mean.

Thank you for your answer !

I will still have problems to make work CMake and RIOT’s Makefiles together (I already tried in an other project), but it seems more doable.

For the last questions, let me explain a little :
RIOT cannot be compiled as-is. It needs to handle the whole application’s build. To do so, it provides a template Makefile (example) that will compile the application and all the modules needed, and then link them. To transform any source into a RIOT modules, you may just add a simple Makefile in the same directory (and add a reference to this directory in the user application’s Makefile). Once this is done, you can compile your application for any microcontroller that is supported by RIOT.

That being said, you can do some workaround. A dummy user application that require the needed RIOT modules can be compiled, and the object/archive files can be extracted to be integrated in an other build system (CMake). But this raise a lot of question on how “information” (compilation/linking flags, target microcontroller, needed modules) is passed between the two build systems. I already tried this approach, and ended with an application compiling and linking well, but not working for obscure reasons (one RIOT modules could not communicate with one of mine).

But there is an other workaround. Let’s say that if RIOT needs to compile everything to work well, you can transform everything in a RIOT module. Since you only need to add small Makefiles to a project to make it a module, it may be worth exploring this solution. But this raise questions on how to tell RIOT where are the modules. This approach also solved my “obscure reasons” in the former project.

I’m not sure if I’m really clear, tell me if it’s not the case. It’s a bit complicated because it is not designed to work like that. My questions explored the two possibilities, to determine which one is the best or even possible. I was more confident with the second approach because it’s the one I currently use, but considering what you said, it seems not possible to use it in a clean and compatible way with Ament/CMake.

I don’t know anything about RIOT. So I can’t give any more advice, sorry.

Is there any documentation about CMake variables *_INCLUDE_DIRS / *_DEPENDS / *_WHATEVER
that are exported by ament ?

I can’t find any documentation.

I am only able to retrieve these variables with imported packages, not the current one.

Many of the variables are common in CMake, e.g. *_INCLUDE_DIRS, *_LIBRARIES, etc. There is no ament specific documentation for those.

Other variables are commonly not being used by users and are therefore not mentioned anywhere.

In general there is not much documentation beyond the API docs (this is ticketed in ament/ament_cmake#2). If there is a specific variable you would like to know more about please don’t hesitate to ask. I am happy to provide feedback.

Let’s see with an example :

cmake_minimum_required(VERSION 3.5)

find_package(ament_cmake REQUIRED)
find_package(rclc REQUIRED)
find_package(std_msgs REQUIRED)

find_package(rosidl_typesupport_test REQUIRED)

  FILES main.c


If I understand well, it’s the ament_package() call that fills the variables, isn’t it ?

As you can see, there is 4 dependencies (ament_cmake, rclc, std_msgs, rosidl_typesupport_test). How can I extract these 4 dependencies from a variable ? I want something like ${talker_c_DEPENDENCIES} that gives me the list of dependencies of the project (extracted from the package.xml or anything) on which I could iterate with “foreach”.

I don’t want to get rid of the find_package(...) calls, I just want to be able to display the list just after ament_package.

ament_package() internally calls ament_package_xml() which is responsible to parse the package.xml file and defined CMake variables for various parts. You can either access the variables after the ament_package() call or manually invoke ament_package_xml() anytime before to get the information earlier.

The script is responsible to extract the majority of the information. You can also look at the generated CMake code for a specific folder - in each package build folder you find a file name ament_cmake_core/package.cmake. It contains all the CMake variables defined for the package, e.g. variable for the package name, version, maintainer, all the dependency types, version, export tags, etc.

As an example the generated package.cmake file for the ament_index_cpp package looks like this:

set(_AMENT_PACKAGE_NAME "ament_index_cpp")
set(ament_index_cpp_VERSION "0.0.2")
set(ament_index_cpp_MAINTAINER "Dirk Thomas <>")
set(ament_index_cpp_BUILD_DEPENDS )
set(ament_index_cpp_BUILDTOOL_DEPENDS "ament_cmake")
set(ament_index_cpp_BUILD_EXPORT_DEPENDS )
set(ament_index_cpp_BUILDTOOL_EXPORT_DEPENDS )
set(ament_index_cpp_EXEC_DEPENDS )
set(ament_index_cpp_TEST_DEPENDS "ament_cmake_gtest" "ament_lint_auto" "ament_lint_common")
set(ament_index_cpp_DEPRECATED "")
list(APPEND ament_index_cpp_EXPORT_TAGS "<build_type>ament_cmake</build_type>")
1 Like

Thanks for your help !
I can go forward for now.
I may come back later if I have further questions.