ros2_documentation
ros2_documentation copied to clipboard
[question] Exporting multiple libraries. (symlink-install)
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).
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?
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?
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.
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.
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.