What is the recommended/correct value of `IMPORTED_LOCATION` for IMPORTED library targets?

After some experiments, I found that it is FINE with the abovementioned situations. Therefore, I have some conclusions about this topic.

Conclusions

  • $<TARGET_RUNTIME_DLLS:tgt> will be evaluated by IMPORTED_LOCATION_<CONFIG>, as well.

  • If there exist IMPORTED_LOCATION and IMPORTED_LOCATION_<CONFIG> simultaneously, then $<TARGET_RUNTIME_DLLS:tgt> will be evaluated by IMPORTED_LOCATION_<CONFIG> corresponding to the current configuration, priorly.

Experiments with Qt

The following is the example CMakeLists.txt code using Qt6.

Click to expand the example CMakeLists.txt code
cmake_minimum_required(VERSION 3.21)
get_filename_component(folder_name "${CMAKE_CURRENT_SOURCE_DIR}" NAME)
project(${folder_name} LANGUAGES C CXX)

include(CMakePrintHelpers)

list(APPEND CMAKE_MODULE_PATH "C:/Qt/6.3.1/msvc2019_64")
list(APPEND CMAKE_PREFIX_PATH "C:/Qt/6.3.1/msvc2019_64")

find_package(Qt6 CONFIG REQUIRED
  COMPONENTS Core Widgets)

cmake_print_properties(
  TARGETS     Qt6::Core
              Qt6::Widgets
  PROPERTIES  IMPORTED_LOCATION
              IMPORTED_LOCATION_DEBUG
              IMPORTED_LOCATION_RELEASE)

add_executable(main "main.cpp")

target_link_libraries(main 
  PRIVATE 
    Qt6::Core 
    Qt6::Widgets)

add_custom_command(
  TARGET  main POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E copy 
          "$<TARGET_RUNTIME_DLLS:main>"
          "$<TARGET_FILE_DIR:main>"
  COMMAND_EXPAND_LISTS)

add_custom_target(echo-TARGET_RUNTIME_DLLS
  COMMAND ${CMAKE_COMMAND} -E echo
          "$<TARGET_RUNTIME_DLLS:main>")

After configuring the projects, as we can see, BOTH IMPORTED_LOCATION and IMPORTED_LOCATION_<CONFIG> of IMPORTED targets are populated.

Click to expand output results of configuring projects
[proc] Executing command: "C:\Program Files\CMake\bin\cmake.EXE" --no-warn-unused-cli -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=d:/cmake-find_package-qt/install -Sd:/cmake-find_package-qt -Bd:/cmake-find_package-qt/build/win32-MSVC-x64-Debug -G Ninja
[cmake] Not searching for unused variables given on the command line.
[cmake] -- Could NOT find WrapVulkanHeaders (missing: Vulkan_INCLUDE_DIR) 
[cmake] -- 
[cmake]  Properties for TARGET Qt6::Core:
[cmake]    Qt6::Core.IMPORTED_LOCATION = "C:/Qt/6.3.1/msvc2019_64/bin/Qt6Core.dll"
[cmake]    Qt6::Core.IMPORTED_LOCATION_DEBUG = "C:/Qt/6.3.1/msvc2019_64/bin/Qt6Cored.dll"
[cmake]    Qt6::Core.IMPORTED_LOCATION_RELEASE = "C:/Qt/6.3.1/msvc2019_64/bin/Qt6Core.dll"
[cmake]  Properties for TARGET Qt6::Widgets:
[cmake]    Qt6::Widgets.IMPORTED_LOCATION = "C:/Qt/6.3.1/msvc2019_64/bin/Qt6Widgets.dll"
[cmake]    Qt6::Widgets.IMPORTED_LOCATION_DEBUG = "C:/Qt/6.3.1/msvc2019_64/bin/Qt6Widgetsd.dll"
[cmake]    Qt6::Widgets.IMPORTED_LOCATION_RELEASE = "C:/Qt/6.3.1/msvc2019_64/bin/Qt6Widgets.dll"
[cmake] 
[cmake] -- Configuring done
[cmake] -- Generating done
[cmake] -- Build files have been written to: D:/cmake-find_package-qt/build/win32-MSVC-x64-Debug

After building the custom target echo-TARGET_RUNTIME_DLLS with Debug and Release configurations respectively, I found that $<TARGET_RUNTIME_DLLS:tgt> would be populated with its corresponding IMPORTED_LOCATION_<CONFIG>.

Click to expand output results with Debug config
[proc] Executing command: "C:\Program Files\CMake\bin\cmake.EXE" --build d:/cmake-find_package-qt/build/win32-MSVC-x64-Debug --config Debug --target echo-TARGET_RUNTIME_DLLS --
[build] [1/1 100% :: 0.038] cmd.exe /C "cd /D D:\cmake-find_package-qt\build\win32-MSVC-x64-Debug && "C:\Program Files\CMake\bin\cmake.exe" -E echo C:/Qt/6.3.1/msvc2019_64/bin/Qt6Widgetsd.dll;C:/Qt/6.3.1/msvc2019_64/bin/Qt6Guid.dll;C:/Qt/6.3.1/msvc2019_64/bin/Qt6Cored.dll"
[build] C:/Qt/6.3.1/msvc2019_64/bin/Qt6Widgetsd.dll;C:/Qt/6.3.1/msvc2019_64/bin/Qt6Guid.dll;C:/Qt/6.3.1/msvc2019_64/bin/Qt6Cored.dll
Click to expand output results with Release config
[proc] Executing command: "C:\Program Files\CMake\bin\cmake.EXE" --build d:/cmake-find_package-qt/build/win32-MSVC-x64-Release --config Release --target echo-TARGET_RUNTIME_DLLS --
[build] [1/1 100% :: 0.041] cmd.exe /C "cd /D D:\cmake-find_package-qt\build\win32-MSVC-x64-Release && "C:\Program Files\CMake\bin\cmake.exe" -E echo C:/Qt/6.3.1/msvc2019_64/bin/Qt6Widgets.dll;C:/Qt/6.3.1/msvc2019_64/bin/Qt6Gui.dll;C:/Qt/6.3.1/msvc2019_64/bin/Qt6Core.dll"
[build] C:/Qt/6.3.1/msvc2019_64/bin/Qt6Widgets.dll;C:/Qt/6.3.1/msvc2019_64/bin/Qt6Gui.dll;C:/Qt/6.3.1/msvc2019_64/bin/Qt6Core.dll

Experiments with OpenCV

The following is the example CMakeLists.txt code using OpenCV.

Click to expand the example CMakeLists.txt code
cmake_minimum_required(VERSION 3.21)
get_filename_component(folder_name "${CMAKE_CURRENT_SOURCE_DIR}" NAME)
project(${folder_name} LANGUAGES C CXX)

include(CMakePrintHelpers)

list(APPEND CMAKE_MODULE_PATH "C:/ccxxpkgs/install")
list(APPEND CMAKE_PREFIX_PATH "C:/ccxxpkgs/install")

find_package(OpenCV CONFIG REQUIRED)

cmake_print_properties(
  TARGETS     opencv_core
              opencv_imgproc
  PROPERTIES  IMPORTED_LOCATION
              IMPORTED_LOCATION_DEBUG
              IMPORTED_LOCATION_RELEASE)

add_executable(main "main.cpp")

target_link_libraries(main 
  PRIVATE 
    opencv_core 
    opencv_imgproc)

add_custom_command(
  TARGET  main POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E copy 
          "$<TARGET_RUNTIME_DLLS:main>"
          "$<TARGET_FILE_DIR:main>"
  COMMAND_EXPAND_LISTS)

add_custom_target(echo-TARGET_RUNTIME_DLLS
  COMMAND ${CMAKE_COMMAND} -E echo
          "$<TARGET_RUNTIME_DLLS:main>")

After configuring the projects, as we can see, ONLY IMPORTED_LOCATION_<CONFIG> of IMPORTED targets are populated. While IMPORTED_LOCATION is empty.

Click to expand output results of configuring projects
[proc] Executing command: "C:\Program Files\CMake\bin\cmake.EXE" --no-warn-unused-cli -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=d:/cmake-find_package-opencv/install -Sd:/cmake-find_package-opencv -Bd:/cmake-find_package-opencv/build/win32-MSVC-x64-Debug -G Ninja
[cmake] Not searching for unused variables given on the command line.
[cmake] -- OpenCV ARCH: x64
[cmake] -- OpenCV RUNTIME: vc16
[cmake] -- OpenCV STATIC: OFF
[cmake] -- Found OpenCV 4.5.5 in C:/ccxxpkgs/install/opencv-4.5.5/x64/vc16/lib
[cmake] -- You might need to add C:\ccxxpkgs\install\opencv-4.5.5\x64\vc16\bin to your PATH to be able to run your applications.
[cmake] -- 
[cmake]  Properties for TARGET opencv_core:
[cmake]    opencv_core.IMPORTED_LOCATION = <NOTFOUND>
[cmake]    opencv_core.IMPORTED_LOCATION_DEBUG = "C:/ccxxpkgs/install/opencv-4.5.5/x64/vc16/bin/opencv_core455d.dll"
[cmake]    opencv_core.IMPORTED_LOCATION_RELEASE = "C:/ccxxpkgs/install/opencv-4.5.5/x64/vc16/bin/opencv_core455.dll"
[cmake]  Properties for TARGET opencv_imgproc:
[cmake]    opencv_imgproc.IMPORTED_LOCATION = <NOTFOUND>
[cmake]    opencv_imgproc.IMPORTED_LOCATION_DEBUG = "C:/ccxxpkgs/install/opencv-4.5.5/x64/vc16/bin/opencv_imgproc455d.dll"
[cmake]    opencv_imgproc.IMPORTED_LOCATION_RELEASE = "C:/ccxxpkgs/install/opencv-4.5.5/x64/vc16/bin/opencv_imgproc455.dll"
[cmake] 
[cmake] -- Configuring done
[cmake] -- Generating done
[cmake] -- Build files have been written to: D:/cmake-find_package-opencv/build/win32-MSVC-x64-Debug

After building the custom target echo-TARGET_RUNTIME_DLLS with Debug and Release configurations respectively, I found that $<TARGET_RUNTIME_DLLS:tgt> would be populated with its corresponding IMPORTED_LOCATION_<CONFIG>.

Click to expand output results with Debug config
[proc] Executing command: "C:\Program Files\CMake\bin\cmake.EXE" --build d:/cmake-find_package-opencv/build/win32-MSVC-x64-Debug --config Debug --target echo-TARGET_RUNTIME_DLLS --
[build] [1/1 100% :: 0.039] cmd.exe /C "cd /D D:\cmake-find_package-opencv\build\win32-MSVC-x64-Debug && "C:\Program Files\CMake\bin\cmake.exe" -E echo C:/ccxxpkgs/install/opencv-4.5.5/x64/vc16/bin/opencv_imgproc455d.dll;C:/ccxxpkgs/install/opencv-4.5.5/x64/vc16/bin/opencv_core455d.dll"
[build] C:/ccxxpkgs/install/opencv-4.5.5/x64/vc16/bin/opencv_imgproc455d.dll;C:/ccxxpkgs/install/opencv-4.5.5/x64/vc16/bin/opencv_core455d.dll
Click to expand output results with Release config
[proc] Executing command: "C:\Program Files\CMake\bin\cmake.EXE" --build d:/cmake-find_package-opencv/build/win32-MSVC-x64-Release --config Release --target echo-TARGET_RUNTIME_DLLS --
[build] [1/1 100% :: 0.042] cmd.exe /C "cd /D D:\cmake-find_package-opencv\build\win32-MSVC-x64-Release && "C:\Program Files\CMake\bin\cmake.exe" -E echo C:/ccxxpkgs/install/opencv-4.5.5/x64/vc16/bin/opencv_imgproc455.dll;C:/ccxxpkgs/install/opencv-4.5.5/x64/vc16/bin/opencv_core455.dll"
[build] C:/ccxxpkgs/install/opencv-4.5.5/x64/vc16/bin/opencv_imgproc455.dll;C:/ccxxpkgs/install/opencv-4.5.5/x64/vc16/bin/opencv_core455.dll

Suggestions

Because $<TARGET_RUNTIME_DLLS:tgt> doesn’t mention IMPORTED_LOCATION_<CONFIG> in its documentation, I suggest that CMake add some NOTES to describe this mechanism.