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

using ament_cmake to build and use a shared library

asked 2020-04-29 08:54:37 -0600

broomstick gravatar image

updated 2021-08-27 14:29:17 -0600

Mike Scheutzow gravatar image

I am building a shared library for use in another package. I'm using ROS2 dashing.

I followed the instructions of the ament_cmake user documentation, but the client project could not find my library's header files unless I added the ament_export_include_directories(include) and ament_export_libraries(my_library) functions, which the documentation says are superfluous.

Here is the CMakeList.txt for my library:

cmake_minimum_required(VERSION 3.5)
project(macaroons)

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

find_package(ament_cmake REQUIRED)

add_library(macaroons SHARED
            src/macaroons.cpp
            )

target_include_directories(macaroons PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)

ament_export_interfaces(export_macaroons HAS_LIBRARY_TARGET)   # <-- documentation prepends export_

install(
  DIRECTORY include/
  DESTINATION include
)

install(
  TARGETS macaroons
  EXPORT export_macaroons     # <-- documentation prepends export_
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
  RUNTIME DESTINATION bin
  INCLUDES DESTINATION include
)

ament_export_include_directories(include)     # <-- superfluous?
ament_export_libraries(macaroons)             # <-- superfluous?

ament_package()

This places the library in <prefix>/install/macaroons/lib/libmacaroons.so and the API header files in <prefix>/install/macaroons/include/macaroons/macaroons.hpp, which is where I would expect them to be.

If I do not include the "superfluous" commands, then when try to find_packag() and use ament_target_dependencies(), I get fatal error: macaroons/macaroons.hpp: No such file or directory. If I do include them, it builds just fine.

Here is the client project's CMakeList.txt file:

cmake_minimum_required(VERSION 3.5)
project(macaroon_demo)

# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
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(rclcpp REQUIRED)
find_package(rclcpp_components REQUIRED)
find_package(std_msgs REQUIRED)
find_package(macaroons REQUIRED)

add_executable(macaroon_demo
              src/macaroon_demo.cpp
              src/talker_node.cpp
              src/listener_node.cpp)
target_include_directories(macaroon_demo PRIVATE
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)
ament_target_dependencies(macaroon_demo rclcpp rclcpp_components std_msgs macaroons)

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

ament_package()

I'm grateful that it builds, but I would also be grateful for an explanation of where my library's CMakeList.txt file is incorrect.

edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
2

answered 2020-04-29 13:03:09 -0600

Dirk Thomas gravatar image

It depends how the downstream package is using your package:

With "modern" CMake your package exports a target (using ament_export_target [as of Foxy] or ament_export_interfaces [deprecated as of Foxy]) and downstream packages use the interface targets from the CMake variable <pkgname>_EXPORTS.

Or with "classic" CMake your package exports include directories (ament_export_include_directories), libraries (ament_export_libraries), definitions, link flags, etc. and downstream packages use the various CMake variables like <pkgname>_INCLUDE_DIRS, <pkgname>_LIBRARIES, etc.

Your package can export information with both approaches to support either style in downstream packages.

If downstream packages use ament_target_dependencies() it doesn't matter if you package uses the modern, classic or boths approaches.

Note that the upcoming Foxy release contains improvements and fixes around the modern CMake approach which might not have been backported to Eloquent and Dashing yet.

edit flag offensive delete link more

Comments

For the modern CMake case, how would a downstream package use the <pkgname>_EXPORTS variable? Is it something like the following (for including headers)

ament_target_dependencies(downstream upstream)
target_include_directories(downstream PUBLIC upstream_EXPORTS)

?

Rufus gravatar image Rufus  ( 2020-06-23 05:17:53 -0600 )edit
1

Only with the first line - it already makes sure that all information of exported targets from upstream is being used - include directories, libraries, definitions. The second one is not necessary (and in your example actually incorrect since upstream_EXPORTS is a literal string).

Dirk Thomas gravatar image Dirk Thomas  ( 2020-06-23 09:18:35 -0600 )edit

Question Tools

2 followers

Stats

Asked: 2020-04-29 08:54:37 -0600

Seen: 2,609 times

Last updated: Apr 29 '20