Install IMPORTED_RUNTIME_ARTIFACTS does nothing

Hi, I’ve been trying to find a simple way to copy an imported libs runtime artifacts into an installation directory. In my project, I have a final executable that is built, as well as a static/shared libraries (plural) that are built depending on configuration.

NOTE: I am using 3.23.0 RC2

For the executable, I can copy the runtime dependencies easily with:

function(COPY_RUNTIME_DEPS TARGET)
    add_custom_command(TARGET ${TARGET} POST_BUILD 
            COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:${TARGET}> $<TARGET_FILE_DIR:${TARGET}>
            COMMAND_EXPAND_LISTS
            )
endfunction()

But this doesn’t work for imported targets. My “libraries” are also mostly INTERFACE libraries, and the few that do compile into .dll/.so or statics, don’t depend on this imported library directly. As such, the above method just does not work.

I’ve tried to use IMPORTED_RUNTIME_ARTIFACTS with the imported library, and although there are no CMake errors, it does absolutely nothing.

I’m just trying to copy over libsodium’s libraries, depending on build configuration, to a lib directory in subfolder of the installation directory.

The CMake code looks like this:

# libsodium

if (WIN32)
    # https://cmake.org/cmake/help/latest/prop_tgt/MAP_IMPORTED_CONFIG_CONFIG.html#prop_tgt:MAP_IMPORTED_CONFIG_%3CCONFIG%3E
    
    add_library(libsodium SHARED IMPORTED GLOBAL)
    
    target_include_directories(libsodium INTERFACE include)
    
    #SET(LIB_PATH $<IF:$<STREQUAL:$<TARGET_PROPERTY:libsodium,TYPE>,SHARED_LIBRARY>,dynamic/libsodium.dll,static/libsodium.lib>)
    
    set_property(TARGET libsodium APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
    
    set_target_properties(libsodium PROPERTIES 
            IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" 
            IMPORTED_LOCATION_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/x64/Debug/v143/dynamic/libsodium.dll
            IMPORTED_IMPLIB_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/x64/Debug/v143/dynamic/libsodium.lib
            )
    
    set_property(TARGET libsodium APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
    
    set_target_properties(libsodium PROPERTIES 
            IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" 
            IMPORTED_LOCATION_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/x64/Release/v143/dynamic/libsodium.dll
            IMPORTED_IMPLIB_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/x64/Release/v143/dynamic/libsodium.lib
            )
    
    set_target_properties(libsodium PROPERTIES 
            MAP_IMPORTED_CONFIG_MINSIZEREL Release 
            MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release
            )
    
    install(IMPORTED_RUNTIME_ARTIFACTS libsodium
        LIBRARY DESTINATION ${CLIENT_INSTALL_SUBDIR}/lib
        RUNTIME DESTINATION ${CLIENT_INSTALL_SUBDIR}/lib
        )
    
else()
    find_library(libsodium)
endif()

I thought simply calling: install(TARGETS libsodium ...) would work, but install does not work in imported targets, and I really don’t know why that limitation exists.

Any help is appreciated, thanks.

I would suggest that you use file(GET_RUNTIME_DEPENDENCIES) or the new install(RUNTIME_DEPENDENCY_SET) to install your required DLLs.

Using install(FILES file(GET_RUNTIME_DEPENDENCIES LIBRARIES libsodium) DESTINATION ${CLIENT_INSTALL_SUBDIR}/lib) does not work either. I get the error:

CMake Error at src/kn/encryption/cmake_install.cmake:36 (file):
  file Failed to run dumpbin on:

    libsodium
Call Stack (most recent call first):
  src/kn/cmake_install.cmake:57 (include)
  src/cmake_install.cmake:57 (include)
  cmake_install.cmake:42 (include)


FAILED: CMakeFiles/install.util 

The library that depends on libsodium in this case, is header only and also an interface, ie:

add_library(encryption INTERFACE)
target_link_libraries(encryption INTERFACE libsodium)

install(CODE "file(GET_RUNTIME_DEPENDENCIES LIBRARIES encryption)" DESTINATION ${CLIENT_INSTALL_SUBDIR}/lib)

also results in:

CMake Error at src/kn/encryption/cmake_install.cmake:36 (file):
  file Failed to run dumpbin on:

    encryption
Call Stack (most recent call first):
  src/kn/cmake_install.cmake:57 (include)
  src/cmake_install.cmake:57 (include)
  cmake_install.cmake:42 (include)

I don’t understand why dumpbin has to be run in the first place. CMake should know about linked dependencies internally from configuration time, why is a library/executable attempting to be analyzed?

Because POST_BUILD exists and it’s also possible to inject libraries through #pragma comment on MSVC or raw linker flags in a usage requirement. /DELAYLOAD can also change things. On non-Windows, knowing that libfoo.so ends up adding a DT_NEEDED of libfoo.so.2 or whatever (if it adds a one; linker scripts can do other things too). It’s easier to just ask what the resulting artifact actually needs instead of internalizing all of the targets (which still misses transitive dependencies too).

That is why this won’t work for INTERFACE libraries. You’ll need to run the analysis on $<TARGET_FILE:libsodium> or something like that.