Skip to content

add support for COMPONENTS in ament_export_dependencies #456

Open
@VRichardJP

Description

@VRichardJP

As a follow up of old closed issues:

Problem

Let's consider the following example:

  • Package A creates libA, which depends on PCL common and io components, and on Boost thread
  • Package B creates binB, which depends on libA

On Package A, we would have something like:

  • package.xml
<depend>libpcl-common</depend>
<depend>libpcl-io</depend>
<depend>libboost-thread</depend>
  • CMakeLists.txt
find_package(PCL REQUIRED COMPONENTS common io)
find_package(Boost REQUIRED COMPONENTS thread)

add_library(libA
  # ...
)

# include/link found PCL and Boost components
ament_target_dependencies(libA PCL Boost)

# ament_export_targets()
# install(TARGETS libA...)
# ...

# export components for downstream?
ament_export_dependencies(PCL Boost)

ament_package()

On package B, we would have:

  • package.xml:
<depend>packageA</depend>
  • CMakeLists.txt:
find_package(packageA REQUIRED)

add_executable(binB
  # ...
)

# link libA target to binB
ament_target_dependencies(binB packageA)

ament_package()

As reported in other issues, this does not work. Essentially, what ament_export_dependencies(PCL Boost) does is to add a find_package(PCL) and find_package(Boost) in downstream packages. find_package(PCL) includes all PCL components, so "it will work", even though it will also bloat downstream packages with useless PCL components. On the other hand, find_package(Boost) does not include the thread component, and the downstream package will be broken.

The alternative is not to use ament_export_dependencies() in packageA and instead fetch PCL and Boost components manually downstream, in such case package B would look like this:

  • package.xml:
<depend>packageA</depend>
<depend>libpcl-common</depend>
<depend>libpcl-io</depend>
<depend>libboost-thread</depend>
  • CMakeLists.txt:
find_package(packageA REQUIRED)
find_package(PCL REQUIRED COMPONENTS common io)
find_package(Boost REQUIRED COMPONENTS thread)

add_executable(binB
  # ...
)

# link libA target to binB
ament_target_dependencies(binB 
  packageA
  PCL
  Boost
)

ament_package()

Although this works and does exactly what is required, it makes no sense for downstream packages to have to fetch upstream dependency themselves.

Solution

The solution is to let the user export components. Previous issues have suggested a new ament_export_dependency_with_components() macro, but I think the functionality can be added to the existing ament_export_dependencies() macro.

For example:

ament_export_dependencies(PCL COMPONENTS common io)
ament_export_dependencies(Boost COMPONENTS thread)

Example implementation

Current implementation accepts syntax ament_export_dependencies(depA depB depC...). The macro call appends all these dependencies to _AMENT_CMAKE_EXPORT_DEPENDENCIES (e.g. "prevDepX;depA;depB;depC"). Later, when the package B calls find_package(PackageA), find_package() is called on each listed dependency.

There could be a new syntax ament_export_dependencies(depA COMPONENTS compA compB...). When COMPONENTS keyword is used, the dependency components would be packed and appended to _AMENT_CMAKE_EXPORT_DEPENDENCIES using a special separator character (e.g. :). For example: prevDepX;depA:compA:compB. Then, when someone calls find_package(PackageA), the list of components would be unpacked into a find_package(depA QUIET REQUIRED COMPONENTS compA compB).

Note that when the COMPONENTS keyword is used, only 1 dependency would be allowed per call. The 2 syntaxes would remain valid:

# legacy export
ament_export_dependencies(depA depB depC)
# new component export
ament_export_dependencies(PCL COMPONENTS common io)
ament_export_dependencies(Boost COMPONENTS thread)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions