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

Request for assistance on ament/cargo interop plugin

As part of the effort to get Rust working with ROS 2, I’ve been trying to design a package that will allow things generated by Cargo to get written to the Ament index (see the ament_cargo_plugin project). Unfortunately, I’m getting stymied by both by not knowing exactly how Ament operates and wants everything organized, and also by Cargo’s opinions on the order everythign should be done during a build process.

From what I understand, Ament wants empty files placed at certain areas of a directory in order to indicate package availability? And I think it wants it done after compilation has been done? This would come into slight conflict with how Cargo build scripts work, since the build script is executed before compilation.

Would any Ament and/oror Cargo/Rust enthusiasts be willing to work with me on this project? I feel like it’s one of the missing components for getting Rust support for Ros 2. Being able to trigger Rust builds via Colcon would be very important, I feel.

And I apologize if this should have been on Ros Answers instead. I put it here so that a discussion could be formed. And so that other people might be able to wander by here and see the nitty-gritty of Ament and Cargo.

2 Likes

Hello,
We are using rust and ros2 extensively in our research and tools. We have written rust bindings GitHub - sequenceplanner/r2r: Minimal ROS 2 Rust bindings, that you can use both standalone without colcon (only cargo) or with colcon. We are using cmake to help with the colcon - cargo integration, instead of writing a plugin. You can see an example here: dorna_example/src/dorna_example/control_box/control_box_simulator at master · sequenceplanner/dorna_example · GitHub.

For us this works great and we are not so dependent on ament/colcon. Hope that helps

From the readme on the sequenceplanner/r2r project, it says that this is for " Minimal bindings for ROS2 that do not require hooking in to the ROS2 build infrastructure. If you want a more ROS-oriented approach, see https://github.com/ros2-rust/ros2_rust." The project that I’m working on above is being developed to help ros2_rust interoperate with Colcon in a slightly more “Rust-y” way. But thank you for your suggestion! I’ll still be taking a look at your examples!

We are using ament-cmake to integrate with colcon, like in the example in my reply. We should probably update the readme to higlight that also, since that is how we usually do it now.

1 Like

If you want to understand why these files exist, there is a pretty decent design document here:

I don’t think it necessarily has to be done after compilation, but there might be a period of time after the build script was run, but before the build has been preformed, where the files in the index might point to resources that do not exist yet (maybe executables or libraries).


I haven’t looked at it at all, but I would have thought the bigger issue was that you typically do not mix cargo with FHS style install targets, but I could be wrong about that. I am no expert with cargo.

Sorry, I’m sort of new to this, but what is an FHS install target?

Sorry, it’s a standard that defines the layout that things like Linux use and where files should go into the layout:

It’s what you’re implicitly following most times when you do make install.

Ah, okay. It doesn’t look like something Cargo would have a problem with, but I may not be reading into this correctly. Cargo’s structure for packages looks like this.

The tricky thing I’ve been running into is that Cargo really doesn’t like working outside of the package. Meaning, that if I want to write a file to some external directory, it’s going to be painful to get Cargo to do it. Not necessarily impossible, but painful. However, while digging through the Cargo documentation, I noticed that you can actually put metadata in a table in the manifest. See here for details.

Perhaps we can leverage this in some way? Perhaps I’m looking at this incorrectly? Maybe we don’t need Cargo to create the Ament files during/before compilation. Perhaps this plugin should be the thing that calls Cargo, and then takes care of the filesystem stuff it doesn’t want to handle? Am I making sense?

Sounds logical to me, but I don’t have time to investigate further. There is also this:

Which sounds kind of like what you described, but I haven’t used it, so I’m not sure.

The purpose of ament_cargo_plugin is not to call Cargo (that’s what ament_cargo does), but get any ROS-specific variables passed by ament_cargo to Cargo.

For example, Cargo does not know anything about ROS dependencies that are in package.xml, so it needs to be told what those dependencies are, and in that case, it’s ament_cargo the one responsible for passing any info from the ROS world to the Cargo world.

The workflow once everything is set up would be:

  • colcon detects that a package is of type ament_cargo (e.g. like ament_cmake, ament_python, ament_gradle, etc.)
  • ament builds the ROS dependency graph for the current package
  • ament_cargo passes any ROS metadata to Cargo by setting cargo:rustc-env=VAR=VALUE or cargo:rustc-link-search=[KIND=]PATH to set the search path for dependencies
  • ament_cargo_plugin is a Rust crate that runs as a Cargo build script and gathers environment variables that were set by ament_cargo

Why is all this necessary? Because some ROS packages (namely messages), need to be exported to downstream Rust projects so that the latter can import them. For example, a ros2-rust application that uses std_msgs, needs to know where the .rs files are in the colcon workspace, but also how to link against the native libraries built by colcon.

ament_cargo_plugin and the ament_cargo build type are only needed for ros2-rust applications, rclrs itself needs to be built by CMake (and thus declared as an ament_cmake build type), like rclpy, rcljava, etc. to have access to the full ament infrastructure.

4 Likes