Fast-DDS-Gen icon indicating copy to clipboard operation
Fast-DDS-Gen copied to clipboard

Maintain a CMake function similar to rosidl_generate_interfaces

Open Ryanf55 opened this issue 1 year ago • 0 comments

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

  1. Locate your IDL files from the ROS install:

     find /opt/ros/humble/ -name Header.idl
     >>> /opt/ros/humble/share/std_msgs/msg/Header.idl
    
  2. And, their dependencies (manually)

    >>> /opt/ros/humble/share/builtin_interfaces/msg/Time.idl
    
  3. Add #pragma once so 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"

  4. Using CMake, form the FastDDSGen command into something like execute_process or add_custom_target so it runs a variation of this

    fastddsgen -cs -typeros2 -replace -d /ws/build/builtin_interfaces/msg -I /ws/src/my_generation  /ws/src/my_generation/std_msgs/msg/Header.idl
    
  5. Deal with the fact that it generates builtin_interfaces/msg/Time.h in the std_msgs directory (There's a few ways to work around the limitations of FastDDSGen) - I really like the new --no-dependencies flag, but it requires CMake users to re-implement the dependency tree themselves.

  6. 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 ...

  7. 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)

Ryanf55 avatar Sep 18 '24 02:09 Ryanf55