ros2_documentation icon indicating copy to clipboard operation
ros2_documentation copied to clipboard

[question] Exporting multiple libraries. (symlink-install)

Open tylerjw opened this issue 4 years ago • 5 comments

This is on Foxy with cmake version 3.16.3 doing a colon build with --symlink-install. The documentation here: https://github.com/ros2/ros2_documentation/blob/master/source/Tutorials/Ament-CMake-Documentation.rst#building-a-library

covers building and installing a library target.

What I'm confused by is the EXPORT section of the install cmake function and the related ament functions.

If I wanted to export two libraries how would I go about it? Here is my idea (and the error it is producing):

cmake_minimum_required(VERSION 3.5)
project(project_name)

find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_components REQUIRED)
find_package(std_msgs REQUIRED)

set(THIS_PACKAGE_INCLUDE_DEPENDS
  rclcpp
  rclcpp_components
  std_msgs
)

include_directories(include)

add_library(node_a SHARED src/node_a.cpp)
set_target_properties(node_a PROPERTIES VERSION "${${PROJECT_NAME}_VERSION}")
ament_target_dependencies(node_a ${THIS_PACKAGE_INCLUDE_DEPENDS})
rclcpp_components_register_nodes(node_a "project_name::node_a")

add_library(node_b SHARED src/node_b.cpp)
set_target_properties(node_b PROPERTIES VERSION "${${PROJECT_NAME}_VERSION}")
ament_target_dependencies(node_b ${THIS_PACKAGE_INCLUDE_DEPENDS})
rclcpp_components_register_nodes(node_b "project_name::node_b")

ament_export_include_directories(include)
ament_export_libraries(node_a node_b)
ament_export_dependencies(${THIS_PACKAGE_INCLUDE_DEPENDS})

# Install include, launch, config directories
install(DIRECTORY include/ DESTINATION include)
install(DIRECTORY launch DESTINATION share/${PROJECT_NAME})
install(DIRECTORY config DESTINATION share/${PROJECT_NAME})

# Install Libraries
install(
  TARGETS node_a node_b
  EXPORT node_a node_b
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
  RUNTIME DESTINATION bin
  INCLUDES DESTINATION include
)

ament_package()

This produces this error:

CMake Error at /opt/ros/foxy/share/ament_cmake_core/cmake/symlink_install/ament_cmake_symlin
k_install_targets.cmake:50 (_install):
  _install TARGETS given unknown argument "node_b".
Call Stack (most recent call first):
  /opt/ros/foxy/share/ament_cmake_core/cmake/symlink_install/install.cmake:37 (ament_cmake_symlink_install_targets)

I'm asking here (and not on ros-answers) because I believe the documentation is not clear (to me).

tylerjw avatar Feb 09 '21 21:02 tylerjw

After reading the cmake documentation on installing exports I now am even more confused.

Should something like this be recommended:

install(
  TARGETS node_a node_b
  EXPORT export_${PROJECT_NAME}
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
  RUNTIME DESTINATION bin
  INCLUDES DESTINATION include
)
install(EXPORT export_${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME})

If so what do I pass to the call to ament_export_libraries method?

tylerjw avatar Feb 09 '21 21:02 tylerjw

I changed the cmake above to be this and it seems to work. Please clarify if this is the correct approach:

cmake_minimum_required(VERSION 3.5)
project(project_name)

find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_components REQUIRED)
find_package(std_msgs REQUIRED)

set(THIS_PACKAGE_INCLUDE_DEPENDS
  rclcpp
  rclcpp_components
  std_msgs
)

include_directories(include)

add_library(node_a SHARED src/node_a.cpp)
set_target_properties(node_a PROPERTIES VERSION "${${PROJECT_NAME}_VERSION}")
ament_target_dependencies(node_a ${THIS_PACKAGE_INCLUDE_DEPENDS})
rclcpp_components_register_nodes(node_a "project_name::node_a")

add_library(node_b SHARED src/node_b.cpp)
set_target_properties(node_b PROPERTIES VERSION "${${PROJECT_NAME}_VERSION}")
ament_target_dependencies(node_b ${THIS_PACKAGE_INCLUDE_DEPENDS})
rclcpp_components_register_nodes(node_b "project_name::node_b")

# Install include, launch, config directories
install(DIRECTORY include/ DESTINATION include)
install(DIRECTORY launch DESTINATION share/${PROJECT_NAME})
install(DIRECTORY config DESTINATION share/${PROJECT_NAME})

# Install Libraries
install(
  TARGETS node_a node_b
  EXPORT export_${PROJECT_NAME}
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
  RUNTIME DESTINATION bin
  INCLUDES DESTINATION include
)
ament_export_targets(export_${PROJECT_NAME} HAS_LIBRARY_TARGET)
ament_export_dependencies(${THIS_PACKAGE_INCLUDE_DEPENDS})

ament_package()

I think my confusion stems from the line in the documentation around the name used in the EXPORT argument and the ament_export_targets function. In those cases, I think it should be made clear that the name you use here is actually a package/project-level name and has nothing to do with the library names.

That being, said I'm confused about the export_ name prefix. Does this mean that if another package depends on this package they'll need to depend on export_project_name in their call to ament_export_dependencies and ament_target_dependencies?

tylerjw avatar Feb 09 '21 22:02 tylerjw

This repository hosts the documentation and best for discussions of the tutorial and documentation content. The best place for asking questions about the ament_cmake API will be on https://answers.ros.org with the tag ament_cmake or if you think there's something to be resolved in the interface please open an issue on the code repository: https://github.com/ament/ament_cmake

Once the technical discussion is resolved coming back here to update the documentation makes sense. But this is not the right place for a technical discussion of the API specifics.

tfoote avatar Feb 10 '21 00:02 tfoote

I did ask a question on ros-answers here regarding this confusion: https://answers.ros.org/question/370266/export-multiple-libraries-ros2/

I created this here because I believe the tutorial is unclear on this point. This issue is to hopefully clear up the confusion from the tutorial and then hopefully I or someone can make a PR to the tutorial to make it less confusing.

tylerjw avatar Feb 10 '21 16:02 tylerjw

I posted an issue against ament_cmake here: https://github.com/ament/ament_cmake/issues/317 to ask about the proper use of the interface. I included what I think would be a clearer example for the tutorials. I posted there because I am hoping the authors/maintainers of the ament_cmake interface can help correct my understanding so I can come back here and create a PR that makes the interface usage clearer.

tylerjw avatar Feb 10 '21 17:02 tylerjw