Help wrapping external c++ library as ament package
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.
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
).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?
regular CMake
install(.. EXPORT ..)
andinstall(..)
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 acolcon.pkg
file.