'CMake - How to handle dependencies of imported library targets with TARGET_RUNTIME_DLLS

In my project I rely on some third party shared library named foo.

foo itself is relying on some other third party dll (let's call it bar.dll), which is however neither used by my project nor exposed in the headers of foo.

The foo target is created and linked to my project as follows

add_library(foo SHARED IMPORTED)
set_target_properties(foo PROPERTIES
  IMPORTED_LOCATION "${foo_dll_path}"
  IMPORTED_IMPLIB   "${foo_lib_path}"
)

target_link_libraries(my_project PUBLIC foo)

Later on a post build event is triggered to create hard links to all dependent 3rd party libraries via $<TARGET_RUNTIME_DLLS:my_project> generator expression.

How can bar.dll be introduced in this setup to be visible in $<TARGET_RUNTIME_DLLS:my_project>?

So far I tried to add bar.dll as yet another imported target via add_library(bar UNKNOWN IMPORTED) and add_library(bar SHARED IMPORTED) and setting IMPORTED_LOCATION on bar accordingly, which however does create linker errors. Example:

add_library(bar UNKNOWN IMPORTED)
set_target_properties(bar PROPERTIES
  IMPORTED_LOCATION "${bar_dll_path}"
)
target_link_libraries(foo INTERFACE bar)

In case of UNKNOWN the linker will use bar.dll as linker input, which of course fails, in case of SHARED IMPORTED CMake demands that IMPORTED_IMPLIB is set, but neither do I have the import library for bar.dll nor do I want to link my_project against it.

Any other suggestions how to deal with this?



Solution 1:[1]

Since there seems to be no proper solution to this issue I came up with a (possibly fragile) workaround involving a meta target:

# same as before
add_library(foo_real SHARED IMPORTED)
set_target_properties(foo_real PROPERTIES
  IMPORTED_LOCATION "${foo_dll_path}"
  IMPORTED_IMPLIB   "${foo_lib_path}"
)

# add SHARED IMPORTED target with the importlib pointing to foo_reals importlib location
add_library(bar SHARED IMPORTED)
set_target_properties(bar PROPERTIES
  IMPORTED_LOCATION "${bar_dll_path}"
  IMPORTED_IMPLIB   "${foo_lib_path}" # same lib path as for imported target foo
)

# add meta target to combine both
add_library(foo INTERFACE IMPORTED)
target_link_libraries(foo INTERFACE foo_real bar)

# finally link the meta target to the final project
target_link_libraries(my_project PUBLIC foo)

This workaround will cause CMake to generate a build script passing foo.lib multiple times to the linker which does not seem to cause problems with the current MSVC Toolset. Also bar.dll will now be part of TARGET_RUNTIME_DLLS as intended.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Quxflux