Should I use find_package for INTERFACE_LINK_LIBRARIES LINK_ONLY target?


I’m working on a shared dll library project called resource_retriever, it has exported cmake like this:

set_target_properties(resource_retriever::resource_retriever PROPERTIES
  INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/resource_retriever"
  INTERFACE_LINK_LIBRARIES "\$<LINK_ONLY:ament_index_cpp::ament_index_cpp>;\$<LINK_ONLY:CURL::libcurl>"

please note the LINK_ONLY inside, and it is from the source cmake code:

target_link_libraries(${PROJECT_NAME} PRIVATE

Please note the PRIVATE usage.

Then in project of rviz_rendering, it uses resource_retriever like this:

find_package(ament_index_cpp REQUIRED)
find_package(resource_retriever REQUIRED)

please note that there is no find_package for CURL.

Then when I compile rviz_rendering, I have this error:

— stderr: rviz_rendering
CMake Error at C:/ros/jazzy/install/share/resource_retriever/cmake/resource_retrieverExport.cmake:61 (set_target_properties):
The link interface of target “resource_retriever::resource_retriever”
but the target was not found. Possible reasons include:
* There is a typo in the target name.
* A find_package call is missing for an IMPORTED target.
* An ALIAS target is missing.

Please note that the error message is only for CURL but not ament_index_cpp. I guess it’s because find_package(ament_index_cpp is already used.

So here comes the question:

it seems that I need to use find_package for INTERFACE_LINK_LIBRARIES LINK_ONLY? Here in my case, for both CURL and ament_index_cpp. If it’s correct, then what is LINK_ONLY for?

The linking interface of resource_retriever::resource_retriever (its INTERFACE_LINK_LIBRARIES property) contains CURL::libcurl, which means that anyone linking against resource_retriever::resource_retriever must link against CURL::libcurl too. So they must have access to that target, which is normally done by calling find_package() for it. (However, since resource_retriever depends on CURL, it might also be expected for its package config file to internally do find_dependency(CURL) and remove the need for the consumer to do so).

As for the role of $<LINK_ONLY:X>, it prevents the usage requirements of X from transitively applying to whoever is consuming it. Let’s imagine this CMake excerpt:

target_link_libraries(MyLib INTERFACE DepLib1 $<LINK_ONLY:DepLib2>)

target_link_libraries(MyExe PRIVATE MyLib)

With this, MyExe will link against all of MyLib, DepLib1, and DepLib2. However, usage requirements (interface include directories, macro definitions, compile features etc.) will only be propagated from MyLib and DepLib1. DepLib2 will be linked into MyExe, but MyExe will not get its include directories added to its include search paths (and similarly for other usage requirements).