# What is the recommended/correct value of \`IMPORTED\_LOCATION\` for IMPORTED library targets?

**URL:** <https://discourse.cmake.org/t/what-is-the-recommended-correct-value-of-imported-location-for-imported-library-targets/6081>\
**Category:** Code\
**Tags:** os:windows\
**Created:** [July 14, 2022, 9:39am UTC](https://discourse.cmake.org/t/what-is-the-recommended-correct-value-of-imported-location-for-imported-library-targets/6081 "2022-07-14T09:39:30Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![hwhsu1231](https://discourse.cmake.org/user_avatar/discourse.cmake.org/hwhsu1231/32/5358_2.png) [@hwhsu1231](https://discourse.cmake.org/u/hwhsu1231)\
**Post date:** [July 14, 2022, 9:39am UTC](https://discourse.cmake.org/t/what-is-the-recommended-correct-value-of-imported-location-for-imported-library-targets/6081/1 "2022-07-14T09:39:30Z")

</div>

This topic is related to this issue: [https://gitlab.kitware.com/cmake/cmake/-/issues/23696](https://gitlab.kitware.com/cmake/cmake/-/issues/23696)

## Description

I want to verify what is the recommended/correct value of [`IMPORETED_LOCATION`](https://cmake.org/cmake/help/latest/prop_tgt/IMPORTED_LOCATION.html) when there exist **MULTIPLE** configurations (e.g. `Debug` and `Release`)?

1. **One value of a specific configuration.**
2. **A list of multiple values corresponding to each configuration with `$<CONFIG:cfg>`.**

In my opinion, I prefer the **2nd** way. Take `Qt6::Core` IMPORTED target for example. The value of it would be like:

```auto
$<$<CONFIG:Debug>:C:/Qt/6.2.0/msvc2019_64/bin/Qt6Cored.dll>;
$<$<CONFIG:Release>:C:/Qt/6.2.0/msvc2019_64/bin/Qt6Core.dll>

```

However, **Qt** official currently takes the **1st** way. And other libraries don’t even provide this property, for example **OpenCV**.

- **Qt6::Core:** `C:/Qt/6.2.0/msvc2019_64/bin/Qt6Core.dll` (Release version)
- **opencv\_core:** `<variable>-NOTFOUND` (Empty)

## Reason

CMake provides this genex [`TARGET_RUNTIME_DLLS`](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#genex:TARGET_RUNTIME_DLLS) to let us copy DLLs with [`add_custom_command()`](https://cmake.org/cmake/help/latest/command/add_custom_command.html) more conveniently. However, which DLL should be copied depends on which configuration we are using (`Debug` or `Release`). Take `Qt6::Core` IMPORTED target for example:

- If we choose `Debug` configuration, then we need to copy `Qt6Cored.dll`.
- If we choose `Release` configuration, then we need to copy `Qt6Core.dll`.

Therefore, the **2nd** way would be more suitable.

## Further More

If lots of people and CMake official are identified with the **2nd** way, I think we should suggest those C/C++ libraries to follow it. That way, we can use `TARGET_RUNTIME_DLLS` genex for every libraries.

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [July 15, 2022, 2:28pm UTC](https://discourse.cmake.org/t/what-is-the-recommended-correct-value-of-imported-location-for-imported-library-targets/6081/2 "2022-07-15T14:28:16Z")

</div>

If you have multiple configs, use `IMPORTED_LOCATION_<CONFIG>` properties.

---

<div class="post-metadata">

**Author:** ![brad.king](https://discourse.cmake.org/user_avatar/discourse.cmake.org/brad.king/32/11_2.png) [@brad.king](https://discourse.cmake.org/u/brad.king)\
**Post date:** [July 18, 2022, 7:42pm UTC](https://discourse.cmake.org/t/what-is-the-recommended-correct-value-of-imported-location-for-imported-library-targets/6081/3 "2022-07-18T19:42:39Z")

</div>

Along with `IMPORTED_CONFIGURATIONS` to list the available configs whose locations are populated.

In order to reference runtime `.dll` files, CMake needs to know that the imported targets are shared libraries, so type `SHARED` should be used. In that case, populate `IMPORTED_IMPLIB_CONFIG>` with the import libraries (`.lib` files) so they can be linked.

See the [add\_library](https://cmake.org/cmake/help/v3.24/command/add_library.html#imported-libraries) documentation on imported targets.

---

<div class="post-metadata">

**Author:** ![hwhsu1231](https://discourse.cmake.org/user_avatar/discourse.cmake.org/hwhsu1231/32/5358_2.png) [@hwhsu1231](https://discourse.cmake.org/u/hwhsu1231)\
**Post date:** [July 19, 2022, 11:08am UTC](https://discourse.cmake.org/t/what-is-the-recommended-correct-value-of-imported-location-for-imported-library-targets/6081/4 "2022-07-19T11:08:22Z")

</div>

According to the [documentation](https://cmake.org/cmake/help/v3.24/manual/cmake-generator-expressions.7.html#genex:TARGET_RUNTIME_DLLS), it seems that the genex `TARGET_RUNTIME_DLLS` is evaluated by `IMPORTED_LOCATION`, not `IMPORTED_LOCATION_<CONFIG>`.

> Note: Imported Targets are supported only if they know the location of their `.dll` files. An imported `SHARED` library must have `IMPORTED_LOCATION` set to its `.dll` file.

Besides, if the target property `IMPORTED_LOCATION` is **EMPTY** or has only **ONE** value of a specific configuration, how do we use the genex `TARGET_RUNTIME_DLLS` to copy the correct `*.dll` to the **bin** directory on **build** stage?

```cmake
find_package(Qt6 CONFIG REQUIRED
  COMPONENTS Core Widgets Gui)

add_executable(exe main.cpp)

target_link_libraries(exe 
  PRIVATE 
    Qt6::Core 
    Qt6::Widgets
    Qt6::Gui)

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

```

---

<div class="post-metadata">

**Author:** ![hwhsu1231](https://discourse.cmake.org/user_avatar/discourse.cmake.org/hwhsu1231/32/5358_2.png) [@hwhsu1231](https://discourse.cmake.org/u/hwhsu1231)\
**Post date:** [July 21, 2022, 4:57am UTC](https://discourse.cmake.org/t/what-is-the-recommended-correct-value-of-imported-location-for-imported-library-targets/6081/5 "2022-07-21T04:57:40Z")

</div>

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
> 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**
>
> ```cmd
> [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**
>
> ```cmd
> [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**
>
> ```cmd
> [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
> 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**
>
> ```cmd
> [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**
>
> ```cmd
> [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**
>
> ```cmd
> [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>`](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#genex:TARGET_RUNTIME_DLLS) doesn’t mention `IMPORTED_LOCATION_<CONFIG>` in its documentation, I suggest that CMake add some **NOTES** to describe this mechanism.
