Repository: conan-io/conan
Pull request: CMakeDeps: Fix imported library config suffix
Currently the imported libraries are set without config suffix first. At the end there is one additional set using the config suffix, which overwrites the already set libraries.

Fixes #13504

Changelog: Fix: Fix imported library config suffix.
Docs: Omit

- [X] Refer to the issue that supports this Pull Request.
- [X] If the issue has missing info, explain the purpose/use case/pain/need that covers this Pull Request.
- [X] I've read the [Contributing guide](https://github.com/conan-io/conan/blob/develop/.github/CONTRIBUTING.md).
- [X] I've followed the PEP8 style guides for Python code.
- [ ] I've opened another PR in the Conan docs repo to the ``develop`` branch, documenting this one.

Note: I think no documentation changes are required. Should I still make a change in the documentation?


Problem statement:
[bug] In the CMakeDeps Generator IMPORTED_LOCATION is overridden by IMPORTED_LOCATION${config_suffix}
### Environment details

* Operating System+version: Windows 10
* Compiler+version: MSVC 19
* Conan version: 2.0.2
* Python version: 3.10


### Steps to reproduce

1. Download a dependency (e.g. thrift) with conan using the CMakeDeps generator
2. Have a look at the created cmakedeps_macros.cmake

In the function `conan_package_library_targets` line 48 and 49 for windows the correct target properties are set for IMPORTED_IMPLIB and IMPORTED_LOCATION. 

`set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_LOCATION ${CONAN_SHARED_FOUND_LIBRARY})
 set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_IMPLIB ${CONAN_FOUND_LIBRARY})`

Unfortunately those values are superseded by the line 61 where a per config value for IMPORTED_LOCATION_${config_suffix} is set, making the previous setting useless.

`set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_LOCATION${config_suffix} ${CONAN_FOUND_LIBRARY})`

3. Create a cmake project using 

`  add_custom_command(TARGET mytarget POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_RUNTIME_DLLS:mytarget> $<TARGET_FILE_DIR:mytarget>)`

4. Instead of copying the dlls files to the binary folder upon building, the .lib files are copied.

### Logs

_No response_

Hints from issue discussion:
The right thing is to not set IMPORTED_LOCATION at all.

Instead IMPORTED_LOCATION_DEBUG or IMPORTED_LOCATION_RELEASE shall be set to the Library for LIBRARY targets and to the dll (or so) for a shared library. For the latter IMPORTED_IMPLIB_DEBUG or IMPORTED_IMPLIB_RELEASE has to be set to the library. IMPORTED_LOCATION and IMPORTED_IMPLIB will then be automatically determined by cmake.
Hey,

I have a fix for it here. 
[fix-cmakedeps-import-library-config-suffix.patch](https://github.com/conan-io/conan/files/11420056/fix-cmakedeps-import-library-config-suffix.patch)

I also tried to upload this into a branch, to start a pull request, but it seems like I have no permissions for that. Could somebody grant this permission to me, so that I can upload this change?
> I also tried to upload this into a branch, to start a pull request, but it seems like I have no permissions for that. Could somebody grant this permission to me, so that I can upload this change?

Hi @Untzelmann 

you cannot upload branches to the main repo, you need to push your branches to your Github fork, and do a PRs from your fork. That is the contribution flow to Conan, we all, including the maintainers, do PRs from our forks, not from the central repo.
Sorry, I actually never really worked on github, so this is all new to me.

I think this time I got it to work: https://github.com/conan-io/conan/pull/13841
> Sorry, I actually never really worked on github, so this is all new to me.

No prob, thanks for wanting to contribute :) Feel free to ask any further question that you might have.

Commit message: test_cmake_target_runtime_dlls: requires cmake 3.21

Patch to review:
diff --git a/conan/tools/cmake/cmakedeps/templates/macros.py b/conan/tools/cmake/cmakedeps/templates/macros.py
index d3249bcea11..dbddc69d80a 100644
--- a/conan/tools/cmake/cmakedeps/templates/macros.py
+++ b/conan/tools/cmake/cmakedeps/templates/macros.py
@@ -67,13 +67,13 @@ def template(self):
                        if(NOT TARGET ${_LIB_NAME})
                           add_library(${_LIB_NAME} UNKNOWN IMPORTED)
                        endif()
-                       set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_LOCATION ${CONAN_FOUND_LIBRARY})
+                       set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_LOCATION${config_suffix} ${CONAN_FOUND_LIBRARY})
                      else()
                         if(NOT TARGET ${_LIB_NAME})
                           add_library(${_LIB_NAME} SHARED IMPORTED)
                         endif()
-                        set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_LOCATION ${CONAN_SHARED_FOUND_LIBRARY})
-                        set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_IMPLIB ${CONAN_FOUND_LIBRARY})
+                        set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_LOCATION${config_suffix} ${CONAN_SHARED_FOUND_LIBRARY})
+                        set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_IMPLIB${config_suffix} ${CONAN_FOUND_LIBRARY})
                         message(DEBUG "Found DLL and STATIC at ${CONAN_SHARED_FOUND_LIBRARY}, ${CONAN_FOUND_LIBRARY}")
                      endif()
                      unset(CONAN_SHARED_FOUND_LIBRARY CACHE)
@@ -83,10 +83,8 @@ def template(self):
                          add_library(${_LIB_NAME} ${library_type} IMPORTED)
                      endif()
                      message(DEBUG "Created target ${_LIB_NAME} ${library_type} IMPORTED")
-                     set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_LOCATION ${CONAN_FOUND_LIBRARY} IMPORTED_NO_SONAME ${no_soname_mode})
+                     set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_LOCATION${config_suffix} ${CONAN_FOUND_LIBRARY} IMPORTED_NO_SONAME ${no_soname_mode})
                    endif()
-                   # Link library file
-                   set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_LOCATION${config_suffix} ${CONAN_FOUND_LIBRARY})
                    list(APPEND _out_libraries_target ${_LIB_NAME})
                    message(VERBOSE "Conan: Found: ${CONAN_FOUND_LIBRARY}")
                else()
diff --git a/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps.py b/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps.py
index d3001e94a3d..162e74ba9a7 100644
--- a/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps.py
+++ b/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps.py
@@ -661,6 +661,37 @@ def package_info(self):
     assert "talk: Release!" in client.out
     assert "main: Debug!" in client.out
 
+@pytest.mark.tool("cmake", "3.21")
+@pytest.mark.skipif(platform.system() != "Windows", reason="Windows DLL specific")
+def test_cmake_target_runtime_dlls():
+    # https://github.com/conan-io/conan/issues/13504
+
+    client = TestClient()
+    client.run("new cmake_lib -d name=hello -d version=1.0")
+    client.run('create . -tf="" -s build_type=Release -o "hello/*":shared=True')
+
+    client.run("new cmake_exe -d name=foo -d version=1.0 -d requires=hello/1.0 -f")
+    cmakelists = textwrap.dedent("""
+    cmake_minimum_required(VERSION 3.15)
+    project(foo CXX)
+    find_package(hello CONFIG REQUIRED)
+    add_executable(foo src/foo.cpp src/main.cpp)
+    target_link_libraries(foo PRIVATE hello::hello)
+    # Make sure CMake copies DLLs from dependencies, next to the executable
+    # in this case it should copy hello.dll
+    add_custom_command(TARGET foo POST_BUILD
+        COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:foo> $<TARGET_FILE_DIR:foo>
+        COMMAND_EXPAND_LISTS)
+    """)
+    client.save({"CMakeLists.txt": cmakelists})
+    client.run('install . -s build_type=Release -o "hello/*":shared=True')
+    client.run_command("cmake -S . -B build/ -DCMAKE_TOOLCHAIN_FILE=build/generators/conan_toolchain.cmake")
+    client.run_command("cmake --build build --config Release")
+    client.run_command("build\\Release\\foo.exe")
+    
+    assert os.path.exists(os.path.join(client.current_folder, "build", "Release", "hello.dll"))
+    assert "hello/1.0: Hello World Release!" in client.out # if the DLL wasn't copied, the application would not run and show output
+
 
 @pytest.mark.tool("cmake")
 def test_quiet():


Code review comments:
diff_hunk: @@ -661,6 +661,37 @@ def package_info(self):
     assert "talk: Release!" in client.out
     assert "main: Debug!" in client.out
 
+@pytest.mark.tool("cmake", "3.21")
path: conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps.py
text: @user2:
I think `3.21` is not installed in CI

```suggestion
@user1.mark.tool("cmake", "3.23")
```