Maintain a CMake function similar to rosidl_generate_interfaces
Purpose
As a user of FastDDSGen who is using this to generate ROS 2 compliant messages, it is quite difficult to call FastDDSGen from a CMake build system. It would be great if eProsima could distribute a CMake script that performs similar function to rosidl_generate_interfaces that makes this task a lot easier. People use FastDDS directly instead of ROS 2 for various reasons, but CMake is very common when consuming DDS. Developers expect when they compile a large piece of software, they do not need to call fastddsgen in CLI or run some random bash script - instead, they want CMake to generate the C++ implemententation files.
Use case
- Generate a CMake target that links to std_msgs/Header and it's dependencies
How this works today
-
Locate your IDL files from the ROS install:
find /opt/ros/humble/ -name Header.idl >>> /opt/ros/humble/share/std_msgs/msg/Header.idl -
And, their dependencies (manually)
>>> /opt/ros/humble/share/builtin_interfaces/msg/Time.idl -
Add
#pragma onceso they don't conflict - I copy the files locally into a work tree so I don't need root permissions.find IDL -name *.idl | xargs grep -L "#pragma once" | xargs sed -i -e "1i #pragma once" -
Using CMake, form the FastDDSGen command into something like
execute_processoradd_custom_targetso it runs a variation of thisfastddsgen -cs -typeros2 -replace -d /ws/build/builtin_interfaces/msg -I /ws/src/my_generation /ws/src/my_generation/std_msgs/msg/Header.idl -
Deal with the fact that it generates
builtin_interfaces/msg/Time.hin thestd_msgsdirectory (There's a few ways to work around the limitations of FastDDSGen) - I really like the new--no-dependenciesflag, but it requires CMake users to re-implement the dependency tree themselves. -
Add a new target and set the sources to all the generated *.h, *.cxx files (including the dependent ones)
add_library(std_msgs_fastdds SHARED ${CMAKE_CURRENT_BINARY_DIR}/std_msgs/msg/header.h ... -
LInk dependencies manually
target_link_libraries(std_msgs_fastdds PUBLIC builtin_interfaces_fastdds)
Complexities
- If you don't change the .idl files, it shouldn't call fastddsgen again
- If you only edit dependent IDL files, it shouldn't call fastddsgen again
- If you have multiple messages that depend on
Header.idl, then fastddsgen runs many times on the same file - If you call fastddsgen, there does not seem to be way to get the list of generated files for all the dependent targets
- If you have multiple targets being created, Ninja can parallelize the build, and call fastddsgen from multiple threads, which can corrupt the generated files and cause funky build errors.
Notes
I've now seen my 3rd internal implementation of this functionality in CMake. All of them have issues, suffer from caching problems or require changing include paths in your source code, and are trying to work around limitations in fastddsgen. If I can get approval, I can open source some of these implementations for your reference and work with the open source community to supply and maintain a better version to solve this use case.
Dockerfile
To get started, here's just the start without any CMake.
FROM ros:humble
RUN apt update
RUN apt -y install openjdk-11-jdk git
WORKDIR /root
RUN mkdir -p Fast-DDS/src
WORKDIR /root/Fast-DDS/src
RUN git clone --recursive https://github.com/eProsima/Fast-DDS-Gen.git fastddsgen
WORKDIR /root/Fast-DDS/src/fastddsgen
RUN ./gradlew assemble
ENV PATH=$PATH:/root/Fast-DDS/src/fastddsgen/scripts
WORKDIR /ws
RUN mkdir /ws/build/
RUN fastddsgen -cs -typeros2 -replace -d /ws/build/ -I /opt/ros/humble/share /opt/ros/humble/share/std_msgs/msg/Header.idl
Build the dockerfile
docker build . -t fastddsgen-docker-example
Note - with current master, there is an unrelated failure:
> [12/12] RUN fastddsgen -cs -typeros2 -replace -d /ws/build/ -I /opt/ros/humble/share /opt/ros/humble/share/std_msgs/msg/Header.idl:
0.212 openjdk version "11.0.24" 2024-07-16
0.212 OpenJDK Runtime Environment (build 11.0.24+8-post-Ubuntu-1ubuntu322.04)
0.212 OpenJDK 64-Bit Server VM (build 11.0.24+8-post-Ubuntu-1ubuntu322.04, mixed mode, sharing)
0.234 Processing the file /opt/ros/humble/share/std_msgs/msg/Header.idl...
0.505 ERROR: context [/struct_type /complete_type_detail /type_annotations /_sub36 /applied_verbatim_annotation] 14:18 attribute annotation_name isn't defined
The v2.1.2 branch of FastDDSGen does not have this error. I would like to use the latest FastDDSGen if possible.
If you do that, you can see it generated everything in the same folder. The CMake script must work around this and move files back into folders.
$ docker run -it fastddsgen-docker-example bash
# cd build/
root@73214:/ws/build# ls
Header.cxx Header.h HeaderPubSubTypes.cxx HeaderPubSubTypes.h Time.cxx Time.h TimePubSubTypes.cxx TimePubSubTypes.h
Desired API
In CMake, I can call a function:
fastddsgen_interfaces(${PROJECT_NAME} /opt/ros/humble/share/std_msgs/msg/Header.idl)