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

[ROS2] rclcpp linking error and correct way to handle dependencies

asked 2019-10-15 03:29:45 -0600

hdino gravatar image

Hi, I'm trying to migrate my ROS 1 libraries to ROS 2 and have some trouble with setting up the packages.

I read the ament CMake documentation and this thread, but I'm still not sure what the recommended way to deal with dependencies is. It would be great if someone could give feedback on the CMake files, e.g. if there are missing or superfluous lines or something should be done differently.

At the moment, colcon build fails with the following error:

Starting >>> bridge
--- stderr: bridge                             
/usr/bin/ld: -lrclcpp not found
collect2: error: ld returned 1 exit status

CMakeLists.txt of package bridge:

cmake_minimum_required(VERSION 3.5)
project(bridge)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rl2_com REQUIRED)
find_package(bridge_support REQUIRED)

add_executable(bridge src/main.cpp)
target_link_libraries(bridge rl2_com::rl2_com)
ament_target_dependencies(bridge rclcpp rl2_com bridge_support)

install(TARGETS
  bridge
  DESTINATION lib/${PROJECT_NAME}/
)

ament_package()

CMakeLists.txt of package bridge_support (header-only library):

cmake_minimum_required(VERSION 3.5)
project(bridge_support)
find_package(ament_cmake REQUIRED)

install(
  DIRECTORY include/
  DESTINATION include
)

ament_export_include_directories(include)
ament_package()

CMakeLists.txt of package rl2_com:

cmake_minimum_required(VERSION 3.5)
project(rl2_com)

find_package(ament_cmake REQUIRED)
find_package(rl2_logging REQUIRED)

include_directories(include)

add_library(rl2_com src/com.cpp)
target_link_libraries(rl2_com rl2_logging::rl2_logging)
ament_target_dependencies(rl2_com rl2_logging)
ament_export_dependencies(rl2_logging)
ament_export_interfaces(export_rl2_com HAS_LIBRARY_TARGET)

install(
  DIRECTORY include/
  DESTINATION include
)

install(
  TARGETS rl2_com
  EXPORT export_rl2_com
  LIBRARY DESTINATION lib
  ARCHIVE DESTINATION lib
  RUNTIME DESTINATION bin
  INCLUDES DESTINATION include
)

ament_package()

CMakeLists.txt of package rl2_logging:

cmake_minimum_required(VERSION 3.5)
project(rl2_logging)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)

include_directories(include)

add_library(rl2_logging src/log.cpp)
target_link_libraries(rl2_logging rclcpp)
ament_target_dependencies(rl2_logging rclcpp)
ament_export_dependencies(rclcpp)
ament_export_interfaces(export_rl2_logging HAS_LIBRARY_TARGET)

install(
  DIRECTORY include/
  DESTINATION include
)

install(
  TARGETS rl2_logging
  EXPORT export_rl2_logging
  LIBRARY DESTINATION lib
  ARCHIVE DESTINATION lib
  RUNTIME DESTINATION bin
  INCLUDES DESTINATION include
)

ament_package()

The package.xml files contain <depend>XXXXXX</depend> directives for the required packages.

Please note: For better readability, I omitted the following lines in each CMakeLists.txt:

# 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()
edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
2

answered 2019-10-15 15:11:44 -0600

jschornak gravatar image

(I should preface this by saying that I stick with more of a vanilla CMake approach instead of using the ament CMake macros.)

I think the main problem is that rclcpp isn't a valid library name for target_link_libraries. You'll have to use ${rclcpp_LIBRARIES} instead, which gets evaluated to the names of the libraries exported by the rclcpp package.

You might also run into issues finding the correct headers for each package. As written, include_directories(include) just finds the headers in the current package but not the headers in the packages you get through find_package(). I think that the preferred "modern CMake" way to do this is to use target_include directories for each library and executable. This also lets you use generator expressions to find the correct include directory in different build and install configurations.

As a side note, the header files for your package should be in a sub-directory of the include directory with a name matching the package name. For example, include/rl2_logging/some_header.h.

For your rl2_logging example, these tweaks would look like this:

cmake_minimum_required(VERSION 3.5)
project(rl2_logging)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)

add_library(rl2_logging src/log.cpp)

target_link_libraries(rl2_logging ${rclcpp_LIBRARIES})

target_include_directories(rl2_logging PUBLIC
  "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
  "$<INSTALL_INTERFACE:include>"
  ${rclcpp_INCLUDE_DIRS}
)

ament_target_dependencies(rl2_logging rclcpp)
ament_export_dependencies(rclcpp)
ament_export_interfaces(export_rl2_logging HAS_LIBRARY_TARGET)

install(
  DIRECTORY include/${PROJECT_NAME}/
  DESTINATION include/${PROJECT_NAME}/
)

install(
  TARGETS rl2_logging
  EXPORT export_rl2_logging
  LIBRARY DESTINATION lib
  ARCHIVE DESTINATION lib
  RUNTIME DESTINATION bin
  INCLUDES DESTINATION include
)

ament_package()
edit flag offensive delete link more

Comments

Thanks! That did the trick.

I see that this approach allows finer control over what is linked against what (compared to catkin), but I can imagine that it's more difficult to understand for researchers who are not very familiar with CMake.

hdino gravatar image hdino  ( 2019-10-16 02:20:56 -0600 )edit

Question Tools

2 followers

Stats

Asked: 2019-10-15 03:29:45 -0600

Seen: 18,273 times

Last updated: Oct 15 '19