Help wrapping external c++ library as ament package

asked 2022-01-22 15:19:03 -0500

RFRIEDM_Trimble gravatar image

updated 2022-01-22 15:21:13 -0500

Hello,

I am trying to follow the design recommendations as mentioned here. This is the same problem as this ROS1 thread. Can anyone help me get the external library's header files installed correctly?

For example, let's take a simple serial library here that builds with CMake. The source libraries are supposed to build without any ROS dependencies and cannot be changed unless they need to support modern CMake. This makes it easy to use them in other frameworks.

Now, I have multiple ros packages that need to use the headers in this serial port library.

As shown in the example below, I can place serial-port in src/ros-serial-port/serial-port and then add a package.xml and CMakeLists.txt

src/
  ros-serial-port/
     CMakeLists.txt
     package.xml
     serial-port/
        <contents of ericfont/serial-port library go here>
   gps-driver/
     include/
       gps-driver/
         gps_driver.hpp
   bluetooth-serial-driver/

The goal is for me to be able to use serial-port header files in gps_driver.hpp like so:

gps_driver.hpp

#include "serial-port/AsyncSerial.h"

What I tried in the CMakeLists.txt in ros-serial-port:

cmake_minimum_required(VERSION 3.5)

# Project name
project(ros-serial-port)

# Default to C99
if(NOT CMAKE_C_STANDARD)
  set(CMAKE_C_STANDARD 99)
endif()

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

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

find_package(ament_cmake REQUIRED)
find_package(ament_cmake_auto REQUIRED)

# add_subdirectory(serial-port)
ament_auto_add_library(${PROJECT_NAME}_lib
    DIRECTORY
        serial-port
)
target_include_directories(${PROJECT_NAME}_lib PUBLIC 
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/serial-port/include>
    $<INSTALL_INTERFACE:serial-port/include>
)

install(
 TARGETS ${PROJECT_NAME}_lib
 TARGETS
  ${PROJECT_NAME}_lib
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
  RUNTIME DESTINATION bin
  DESTINATION lib/${PROJECT_NAME}
)

install(
    DIRECTORY serial-port/include/
    DESTINATION include
)

ament_export_libraries(${PROJECT_NAME}_lib_export HAS_LIBRARY_TARGET)

ament_auto_package()

This appears to result in the headers installing correctly:

root@host:~# colcon build --packages-up-to ros-serial-port
Starting >>> ros-serial-port
Finished <<< ros-serial-port [0.52s]                     

Summary: 1 package finished [0.87s]
root@host:~# tree install/ros-serial-port/include/
install/ros-serial-port/include/
└── serial-port
    ├── AsyncSerial.h
    ├── BufferedAsyncSerial.h
    ├── SerialStream.h
    ├── SimpleSerial.h
    └── TimeoutSerial.h
1 directory, 5 files

However, I get include errors building the hardware driver after using find_package(), ament_auto_find_build_dependencies() and ament_auto_add_library() like normal.

root@host:~# colcon build --packages-up-to gps-driver
fatal error: serial-port/AsyncSerial.h: No such file or directory    
17 | #include "serial-port/AsyncSerial.h"

If anyone has any simpler examples of how to accomplish wrapping CMake packages in ROS2 ament and exposing their header files correctly, please share.

edit retag flag offensive close merge delete

Comments

1

I would take a step back and ask yourself whether you really need to make an Ament wrapper.

Colcon can build plain CMake packages just fine.

What would you gain by wrapping the CMake package with Ament?

(note: this is the same question as we had in ROS 1: if there is no ROS "in" the plain CMake package, don't add Catkin to the CMakeLists.txt).

gvdhoorn gravatar image gvdhoorn  ( 2022-01-24 02:55:06 -0500 )edit

The reason I thought we needed it was because then we can re-use the plain CMake package code, but in other ROS packages. Without ament_auto_package(), what exposes build dependencies, installs headers correctly in include/ and the other stuff to share/ that ROS needs without polluting the upstream package's CMakeLists?

RFRIEDM_Trimble gravatar image RFRIEDM_Trimble  ( 2022-01-24 10:21:11 -0500 )edit

Without ament_auto_package(), what exposes build dependencies, installs headers correctly in include/ and the other stuff to share/ [..]

regular CMake install(.. EXPORT ..) and install(..) statements?

Ament is just convenience infrastructure.

It's not required at all.

To give an example: ROS 2 packages can find Boost, PCL, OpenCV and other such non-ROS/non-Ament packages just fine. They're treated like system dependencies (ie: non-ROS packages providing a dependency).

The only thing needed to build a non-ROS package in a Colcon workspace would be to add a package.xml and/or a colcon.pkg file.

gvdhoorn gravatar image gvdhoorn  ( 2022-01-24 14:38:05 -0500 )edit