0

Preliminary information: I'm stuck on CMake 3.19!

I have a project with many subprojects that build DLLs and excutables. I want all DLL and EXE files to end up in the build directory. I could already realize this by:

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

DLLs from external libraries should also be copied. I have four ways I include 3rdparty libraries:

  1. Header Only libraries via:
    add_library(Eigen3 INTERFACE)
    target_include_directories(Eigen3 INTERFACE "/path/to/include")
    add_library(Eigen3::Eigen3 ALIAS Eigen3)
    
  2. Binary DLL/LIB Files plus headers:
    add_library(FreeImage SHARED IMPORTED)
    target_include_directories(FreeImage INTERFACE "/path/to/include")
    set_property(TARGET FreeImage PROPERTY IMPORTED_LOCATION "/path/to/FreeImage.dll")
    set_property(TARGET FreeImage PROPERTY IMPORTED_IMPLIB "/path/to/FreeImage.lib")
    add_library(FreeImage::FreeImage ALIAS FreeImage)
    
  3. Standard find_package with targets as result:
    find_package(Qt5 COMPONENTS Core REQUIRED)
    
  4. Direct specification of the DLL name in target_link_library.

I link my project via target_link_library to the targets of the libraries:

add_executable(my_binary main.cpp)
target_link_libraries(my_binary
    Eigen3::Eigen3
    FreeImage::FreeImage
    Qt5::Core
    version) # version.dll from windows/system32

I want all DLL files of the direct dependencies of my_binary to be copied to ${CMAKE_BINARY_DIR} after the build.


What I tried:

function(update_dependencies PROJECT_NAME)
    get_target_property(LINK_LIBRARIES ${PROJECT_NAME} LINK_LIBRARIES)
    foreach(LINK_LIBRARY IN ITEMS ${LINK_LIBRARIES})
        if(NOT TARGET ${LINK_LIBRARY})
            continue()
        endif()

        get_target_property(TARGET_FILE ${LINK_LIBRARY} IMPORTED_LOCATION)
        if(NOT TARGET_FILE)
            continue()
        endif()

        message(STATUS "TARGET_FILE: ${TARGET_FILE}")
    endforeach()
endfunction()

update_dependencies(my_binary)

Output:

TARGET_FILE: /path/to/FreeImage.dll

This approach works only for IMPORTED libraries. The Qt core DLL included via find_package is not printed.

Because of CMP0026, it seems I cannot simply query LOCATION instead of IMPORTED_LOCATION. When I enable the old behavior, it works the way I want in release mode. In the debug build it links against the Qt debug DLL, but it copies the Qt release DLL.

I also tried to work with add_custom_command and $<TARGET_FILE:${LINK_LIBRARY}>. The problem is that I seem to be able to query TARGET_FILE only if there is also a TARGET_FILE. Also, of course, I only want to execute the command if a TARGET_FILE exists.

Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
  • 1
    Have you checked [that answer](https://stackoverflow.com/a/69736197/3440745), which suggests to use `$` generator expression? – Tsyvarev Apr 12 '23 at 12:57
  • @Tsyvarev Forgot to mention, I'm stuck on CMake 3.19. – Benjamin Buch Apr 12 '23 at 13:06
  • @Tsyvarev Nevertheless, that seems to be the right solution. I now have a workaround that works with 3.19 and relies on the old policy. As soon as we update CMake we can switch to this solution. Thank you! – Benjamin Buch Apr 12 '23 at 13:11

1 Answers1

0

If your CMake is at lease 3.21, check out this answer. (Thanks to commentator tsyvarev.)

I was able to find a workaround for CMake 3.19 by enableling the old CMP0026 behavior and using $<TARGET_FILE:${LINK_LIBRARY}> instead of ${TARGET_FILE}.

cmake_policy(SET CMP0026 OLD)
function(update_dependencies PROJECT_NAME)
    get_target_property(LINK_LIBRARIES ${PROJECT_NAME} LINK_LIBRARIES)
    foreach(LINK_LIBRARY IN ITEMS ${LINK_LIBRARIES})
        if(NOT TARGET ${LINK_LIBRARY})
            continue()
        endif()

        get_target_property(TARGET_FILE ${LINK_LIBRARY} LOCATION)
        if(NOT TARGET_FILE)
            continue()
        endif()

        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E
            copy_if_different
                "$<TARGET_FILE:${LINK_LIBRARY}>"
                "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
            VERBATIM)
    endforeach()
endfunction()
Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51