ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
1

How do you use a header-only library package in ROS2?

asked 2021-03-24 20:43:08 -0600

M@t gravatar image

updated 2021-03-24 21:17:14 -0600

The Problem (in short)

I'm trying to create and use a header-only library package in ROS2 Foxy. However the compilation fails with a vague error message about not being able to find the library file, and it does seem like the library object is not being created. How do I correctly structure my library and client package CMakeList files to get this working?

The Problem (in full)

I have three ROS2 Foxy packages: a library package that contains source and header files, a library package of ONLY header files, and a client library that wants to use both. E.g:

workspace/
    library_package/
        src/
            ... lots of.cpp files ....
        include/
            ... lots of .hpp files ....
        CMakeLists.txt
        package.xml
    header_only_library_package/
        # (no src folder here)
        include/
            ... lots of **.h** files ....
        CMakeLists.txt
        package.xml
    client_package/
        src/
        includes/
        ... etc ...

The Error

My normal library package compiles and works with the client package just fine. No problems there. But the header only library package fails compilation with this error:

--- stderr: client_package_executable
/usr/bin/ld: cannot find -lheader_only_library_package
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/client_package.dir/build.make:326: client_package_executable] Error 1
make[1]: *** [CMakeFiles/Makefile2:84: CMakeFiles/client_package_executable.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....

This seems to be saying that ld cannot find a library object. Compiling with debug output (colcon --level-log debug build) shows that (what I think is the correct) library path is:

LD_LIBRARY_PATH=/workspaces/install/header_only_library_package/lib:/workspaces/install/library_package/lib:${LD_LIBRARY_PATH}

However the lib folder doesn't exist for the header only package. So from that I am inferring that something in the header-only package CMakeLists file is wrong, and the library object is not being created.

The Code

My header_only_library_package CMakeLists file looks like this:

# In header_only_library_package:CMakeLists.txt

project(header_only_library_package)
add_library(header_only_library_package INTERFACE)
target_include_directories(header_only_library_package INTERFACE
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
ament_export_targets(export_header_only_library_package HAS_LIBRARY_TARGET)
install(
    DIRECTORY include/ 
    DESTINATION include/)
install(
    TARGETS header_only_library_package
    EXPORT export_header_only_library_package
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
    RUNTIME DESTINATION bin
    INCLUDES DESTINATION include
)
ament_export_include_directories(include)
ament_package()

These commands are a hoge-podge taken from the various bits of tutorials/documentation and SO threads I've been reading. Most of it comes from the Ament CMake Documentation. The docs do an OK job of explaining what command does what, but don't really explain what commands you actually need and for which applications.

And my client_package CMakelists file looks like this:

# In client_package:CMakeLists.txt

find_package(library_package REQUIRED)
find_package(header_only_library_package REQUIRED)

... usual ROS2 library and executable building stuff ...

ament_target_dependencies(client_package_executable
    library_package 
    header_only_library_package)
ament_target_dependencies(client_package_executable 
    library_package 
    header_only_library_package)
target_link_libraries(client_package_executable 
    library_package 
    header_only_library_package)

... usual ROS2 executable install stuff ...

And of course, my package.xml has the <depend> tags for both the normal and header-only library packages.

I've ready my way through a lot of the Ament, CMake and ROS2 documentation, but either I missed the correct syntax I need, or haven't found it yet.

Is anyone able to tell me what the correct syntax for this is?

edit retag flag offensive close merge delete

Comments

Actually I asked myself the same question, so I started digging a bit. Please find my MWE here. It at least works on ROS2 rolling...

gleichdick gravatar image gleichdick  ( 2021-05-28 10:57:01 -0600 )edit

1 Answer

Sort by ยป oldest newest most voted
1

answered 2022-06-06 06:20:12 -0600

MAB Jakub gravatar image

Not sure if this will be 1:1 applicable to your application, but in my project I've used to have a header-only commons library. What did the trick was to declare all functions in header-only lib as inline such as:

    inline Eigen::Matrix3f rotMatFromQuat(Eigen::Quaternionf quat)
    {
        return quat.toRotationMatrix();
    }

in the external package that you want to use your header-only lib in, put

<depend>header-only_package</depend>

in package.xml, and

find_package(header-only_package REQUIRED)
include_directories("./../header-only_package/include")

in CMakeLists.txt. I know this approach is not the best practice (as it refers to relative path to include dir) but it should work as long as your tree looks something like

- workspace/
--- src/
------- client_package/
------- library_package/
------- header-only_package/
edit flag offensive delete link more

Question Tools

2 followers

Stats

Asked: 2021-03-24 20:43:08 -0600

Seen: 1,278 times

Last updated: Jun 06 '22