Repository: conan-io/conan
Pull request #16351 (2024-05-28 15:40:24)

remove dead code
Changelog: Omit
Docs: Omit



Patch:
diff --git a/conan/tools/cmake/cmakedeps/cmakedeps.py b/conan/tools/cmake/cmakedeps/cmakedeps.py
index f8a9cca02..e982c9ae5 100644
--- a/conan/tools/cmake/cmakedeps/cmakedeps.py
+++ b/conan/tools/cmake/cmakedeps/cmakedeps.py
@@ -1,4 +1,3 @@
-import os
 import textwrap
 
 import jinja2
@@ -15,7 +14,6 @@ from conan.tools.cmake.cmakedeps.templates.target_configuration import TargetCon
 from conan.tools.cmake.cmakedeps.templates.target_data import ConfigDataTemplate
 from conan.tools.cmake.cmakedeps.templates.targets import TargetsTemplate
 from conan.tools.files import save
-from conans.client.generators import relativize_generated_file
 from conan.errors import ConanException
 from conans.model.dependencies import get_transitive_requires
 
@@ -120,8 +118,7 @@ class CMakeDeps(object):
             ret[config_version.filename] = config_version.render()
 
         data_target = ConfigDataTemplate(self, require, dep, find_module_mode)
-        data_content = relativize_generated_file(data_target.render(), self._conanfile,
-                                                 "${CMAKE_CURRENT_LIST_DIR}")
+        data_content = data_target.render()
         ret[data_target.filename] = data_content
 
         target_configuration = TargetConfigurationTemplate(self, require, dep, find_module_mode)
@@ -131,11 +128,9 @@ class CMakeDeps(object):
         ret[targets.filename] = targets.render()
 
         config = ConfigTemplate(self, require, dep, find_module_mode)
-        # Check if the XXConfig.cmake exists to keep the first generated configuration
-        # to only include the build_modules from the first conan install. The rest of the
-        # file is common for the different configurations.
-        if not os.path.exists(config.filename):
-            ret[config.filename] = config.render()
+        # Only the latest configuration BUILD_MODULES and additional_variables will be used
+        # in multi-config they will be overwritten by the latest install
+        ret[config.filename] = config.render()
 
     def set_property(self, dep, prop, value, build_context=False):
         """
diff --git a/conan/tools/cmake/cmakedeps/templates/config.py b/conan/tools/cmake/cmakedeps/templates/config.py
index 6a161d293..68c456398 100644
--- a/conan/tools/cmake/cmakedeps/templates/config.py
+++ b/conan/tools/cmake/cmakedeps/templates/config.py
@@ -83,7 +83,7 @@ class ConfigTemplate(CMakeDepsFileTemplate):
 
         {% endfor %}
 
-        # Only the first installed configuration is included to avoid the collision
+        # Only the last installed configuration BUILD_MODULES are included to avoid the collision
         foreach(_BUILD_MODULE {{ pkg_var(pkg_name, 'BUILD_MODULES_PATHS', config_suffix) }} )
             message({% raw %}${{% endraw %}{{ file_name }}_MESSAGE_MODE} "Conan: Including build module from '${_BUILD_MODULE}'")
             include({{ '${_BUILD_MODULE}' }})
diff --git a/conan/tools/cmake/cmakedeps/templates/target_data.py b/conan/tools/cmake/cmakedeps/templates/target_data.py
index e86d89be4..315e2cf30 100644
--- a/conan/tools/cmake/cmakedeps/templates/target_data.py
+++ b/conan/tools/cmake/cmakedeps/templates/target_data.py
@@ -5,7 +5,7 @@ from conan.tools.cmake.cmakedeps import FIND_MODE_NONE, FIND_MODE_CONFIG, FIND_M
     FIND_MODE_BOTH
 from conan.tools.cmake.cmakedeps.templates import CMakeDepsFileTemplate
 from conan.errors import ConanException
-
+from conans.client.generators import relativize_path
 
 """
 
@@ -57,6 +57,9 @@ class ConfigDataTemplate(CMakeDepsFileTemplate):
         # Make the root_folder relative to the generated xxx-data.cmake file
         root_folder = self._root_folder
         root_folder = root_folder.replace('\\', '/').replace('$', '\\$').replace('"', '\\"')
+        # it is the relative path of the caller, not the dependency
+        root_folder = relativize_path(root_folder, self.cmakedeps._conanfile,
+                                      "${CMAKE_CURRENT_LIST_DIR}")
 
         return {"global_cpp": global_cpp,
                 "has_components": self.conanfile.cpp_info.has_components,
diff --git a/conan/tools/cmake/toolchain/blocks.py b/conan/tools/cmake/toolchain/blocks.py
index fbc4e3b40..fbd719972 100644
--- a/conan/tools/cmake/toolchain/blocks.py
+++ b/conan/tools/cmake/toolchain/blocks.py
@@ -16,6 +16,7 @@ from conan.tools.cmake.toolchain import CONAN_TOOLCHAIN_FILENAME
 from conan.tools.cmake.utils import is_multi_configuration
 from conan.tools.intel import IntelCC
 from conan.tools.microsoft.visual import msvc_version_to_toolset_version
+from conans.client.generators import relativize_path
 from conans.client.subsystems import deduce_subsystem, WINDOWS
 from conan.errors import ConanException
 from conans.util.files import load
@@ -146,8 +147,9 @@ class VSDebuggerEnvironment(Block):
         bin_dirs = [p for dep in host_deps for p in dep.cpp_info.aggregated_components().bindirs]
         test_bindirs = [p for dep in test_deps for p in dep.cpp_info.aggregated_components().bindirs]
         bin_dirs.extend(test_bindirs)
+        bin_dirs = [relativize_path(p, self._conanfile, "${CMAKE_CURRENT_LIST_DIR}")
+                    for p in bin_dirs]
         bin_dirs = [p.replace("\\", "/") for p in bin_dirs]
-
         bin_dirs = ";".join(bin_dirs) if bin_dirs else None
         if bin_dirs:
             config_dict[build_type] = bin_dirs
@@ -238,6 +240,8 @@ class LinkerScriptsBlock(Block):
         if not linker_scripts:
             return
         linker_scripts = [linker_script.replace('\\', '/') for linker_script in linker_scripts]
+        linker_scripts = [relativize_path(p, self._conanfile, "${CMAKE_CURRENT_LIST_DIR}")
+                          for p in linker_scripts]
         linker_script_flags = ['-T"' + linker_script + '"' for linker_script in linker_scripts]
         return {"linker_script_flags": " ".join(linker_script_flags)}
 
@@ -324,6 +328,8 @@ class AndroidSystemBlock(Block):
         if not android_ndk_path:
             raise ConanException('CMakeToolchain needs tools.android:ndk_path configuration defined')
         android_ndk_path = android_ndk_path.replace("\\", "/")
+        android_ndk_path = relativize_path(android_ndk_path, self._conanfile,
+                                           "${CMAKE_CURRENT_LIST_DIR}")
 
         use_cmake_legacy_toolchain = self._conanfile.conf.get("tools.android:cmake_legacy_toolchain",
                                                               check_type=bool)
@@ -430,6 +436,8 @@ class AppleSystemBlock(Block):
             "enable_visibility": enable_visibility
         }
         if host_sdk_name:
+            host_sdk_name = relativize_path(host_sdk_name, self._conanfile,
+                                            "${CMAKE_CURRENT_LIST_DIR}")
             ctxt_toolchain["cmake_osx_sysroot"] = host_sdk_name
         # this is used to initialize the OSX_ARCHITECTURES property on each target as it is created
         if host_architecture:
@@ -527,23 +535,22 @@ class FindFiles(Block):
                 host_runtime_dirs = {}
                 for k, v in matches:
                     host_runtime_dirs.setdefault(k, []).append(v)
-        
+
         # Calculate the dirs for the current build_type
         runtime_dirs = []
         for req in host_req:
             cppinfo = req.cpp_info.aggregated_components()
             runtime_dirs.extend(cppinfo.bindirs if is_win else cppinfo.libdirs)
-        
+
         build_type = settings.get_safe("build_type")
         host_runtime_dirs[build_type] = [s.replace("\\", "/") for s in runtime_dirs]
 
         return host_runtime_dirs
 
-    @staticmethod
-    def _join_paths(paths):
-        return " ".join(['"{}"'.format(p.replace('\\', '/')
-                                        .replace('$', '\\$')
-                                        .replace('"', '\\"')) for p in paths])
+    def _join_paths(self, paths):
+        paths = [relativize_path(p, self._conanfile, "${CMAKE_CURRENT_LIST_DIR}") for p in paths]
+        paths = [p.replace('\\', '/').replace('$', '\\$').replace('"', '\\"') for p in paths]
+        return " ".join([f'"{p}"' for p in paths])
 
     def context(self):
         # To find the generated cmake_find_package finders
@@ -630,7 +637,10 @@ class UserToolchain(Block):
         # This is global [conf] injection of extra toolchain files
         user_toolchain = self._conanfile.conf.get("tools.cmake.cmaketoolchain:user_toolchain",
                                                   default=[], check_type=list)
-        return {"paths": [ut.replace("\\", "/") for ut in user_toolchain]}
+        paths = [relativize_path(p, self._conanfile, "${CMAKE_CURRENT_LIST_DIR}")
+                 for p in user_toolchain]
+        paths = [p.replace("\\", "/") for p in paths]
+        return {"paths": paths}
 
 
 class ExtraFlagsBlock(Block):
@@ -868,6 +878,7 @@ class GenericSystemBlock(Block):
             toolset = toolset_arch if toolset is None else "{},{}".format(toolset, toolset_arch)
         toolset_cuda = conanfile.conf.get("tools.cmake.cmaketoolchain:toolset_cuda")
         if toolset_cuda is not None:
+            toolset_cuda = relativize_path(toolset_cuda, conanfile, "${CMAKE_CURRENT_LIST_DIR}")
             toolset_cuda = f"cuda={toolset_cuda}"
             toolset = toolset_cuda if toolset is None else f"{toolset},{toolset_cuda}"
         return toolset
@@ -991,6 +1002,9 @@ class GenericSystemBlock(Block):
         # This is handled by the tools.apple:sdk_path and CMAKE_OSX_SYSROOT in Apple
         cmake_sysroot = self._conanfile.conf.get("tools.build:sysroot")
         cmake_sysroot = cmake_sysroot.replace("\\", "/") if cmake_sysroot is not None else None
+        if cmake_sysroot is not None:
+            cmake_sysroot = relativize_path(cmake_sysroot, self._conanfile,
+                                            "${CMAKE_CURRENT_LIST_DIR}")
 
         result = self._get_winsdk_version(system_version, generator_platform)
         system_version, winsdk_version, gen_platform_sdk_version = result
diff --git a/conan/tools/cmake/toolchain/toolchain.py b/conan/tools/cmake/toolchain/toolchain.py
index 549e2c0b3..6924a1d9f 100644
--- a/conan/tools/cmake/toolchain/toolchain.py
+++ b/conan/tools/cmake/toolchain/toolchain.py
@@ -19,7 +19,6 @@ from conan.tools.env import VirtualBuildEnv, VirtualRunEnv
 from conan.tools.intel import IntelCC
 from conan.tools.microsoft import VCVars
 from conan.tools.microsoft.visual import vs_ide_version
-from conans.client.generators import relativize_generated_file
 from conan.errors import ConanException
 from conans.model.options import _PackageOption
 from conans.util.files import save
@@ -202,7 +201,6 @@ class CMakeToolchain(object):
         context = self._context()
         content = Template(self._template, trim_blocks=True, lstrip_blocks=True,
                            keep_trailing_newline=True).render(**context)
-        content = relativize_generated_file(content, self._conanfile, "${CMAKE_CURRENT_LIST_DIR}")
         return content
 
     @property
diff --git a/conans/client/generators/__init__.py b/conans/client/generators/__init__.py
index eeed8ddbb..de0d06fd1 100644
--- a/conans/client/generators/__init__.py
+++ b/conans/client/generators/__init__.py
@@ -207,15 +207,6 @@ def _generate_aggregated_env(conanfile):
         conanfile.output.info(f"Generated aggregated env files: {generated}")
 
 
-def relativize_generated_file(content, conanfile, placeholder):
-    abs_base_path, new_path = relativize_paths(conanfile, placeholder)
-    if abs_base_path is None:
-        return content
-    content = content.replace(abs_base_path, new_path)
-    content = content.replace(abs_base_path.replace("\\", "/"), new_path.replace("\\", "/"))
-    return content
-
-
 def relativize_paths(conanfile, placeholder):
     abs_base_path = conanfile.folders._base_generators
     if not abs_base_path or not os.path.isabs(abs_base_path):
@@ -229,3 +220,17 @@ def relativize_paths(conanfile, placeholder):
     new_path = placeholder if rel_path == "." else os.path.join(placeholder, rel_path)
     new_path = os.path.join(new_path, "")  # For the trailing / to dissambiguate matches
     return abs_base_path, new_path
+
+
+def relativize_path(path, conanfile, placeholder):
+    abs_base_path, new_path = relativize_paths(conanfile, placeholder)
+    if abs_base_path is None:
+        return path
+    if path.startswith(abs_base_path):
+        path = path.replace(abs_base_path, new_path, 1)
+    else:
+        abs_base_path = abs_base_path.replace("\\", "/")
+        new_path = new_path.replace("\\", "/")
+        if path.startswith(abs_base_path):
+            path = path.replace(abs_base_path, new_path, 1)
+    return path
diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py
index 13030c5b8..c343ccd2b 100644
--- a/conans/client/graph/graph_binaries.py
+++ b/conans/client/graph/graph_binaries.py
@@ -181,11 +181,6 @@ class GraphBinariesAnalyzer(object):
             node.build_allowed = True
             node.binary = BINARY_BUILD if not node.cant_build else BINARY_INVALID
 
-        if (node.binary in (BINARY_BUILD, BINARY_MISSING) and node.conanfile.info.invalid and
-                node.conanfile.info.invalid[0] == BINARY_INVALID):
-            # BINARY_BUILD IS NOT A VIABLE fallback for invalid
-            node.binary = BINARY_INVALID
-
     def _process_node(self, node, build_mode, remotes, update):
         # Check that this same reference hasn't already been checked
         if self._evaluate_is_cached(node):
@@ -234,12 +229,6 @@ class GraphBinariesAnalyzer(object):
         else:  # This binary already exists in the cache, maybe can be updated
             self._evaluate_in_cache(cache_latest_prev, node, remotes, update)
 
-        # The INVALID should only prevail if a compatible package, due to removal of
-        # settings in package_id() was not found
-        if node.binary in (BINARY_MISSING, BINARY_BUILD):
-            if node.conanfile.info.invalid and node.conanfile.info.invalid[0] == BINARY_INVALID:
-                node.binary = BINARY_INVALID
-
     def _process_compatible_node(self, node, remotes, update):
         """ simplified checking of compatible_packages, that should be found existing, but
         will never be built, for example. They cannot be editable either at this point.


Test patch:
diff --git a/test/functional/toolchains/gnu/autotools/test_win_bash.py b/test/functional/toolchains/gnu/autotools/test_win_bash.py
index 613544dac..ddfc375ab 100644
--- a/test/functional/toolchains/gnu/autotools/test_win_bash.py
+++ b/test/functional/toolchains/gnu/autotools/test_win_bash.py
@@ -4,6 +4,7 @@ import textwrap
 import pytest
 
 from conan.test.assets.autotools import gen_makefile_am, gen_configure_ac
+from conan.test.assets.genconanfile import GenConanfile
 from conan.test.assets.sources import gen_function_cpp
 from test.conftest import tools_locations
 from test.functional.utils import check_exe_run
@@ -100,3 +101,52 @@ def test_add_msys2_path_automatically():
     client.save({"conanfile.py": conanfile})
     client.run("create .")
     assert "ar.exe" in client.out
+
+
+@pytest.mark.skipif(platform.system() != "Windows", reason="Requires Windows")
+def test_conf_inherited_in_test_package():
+    client = TestClient()
+    bash_path = None
+    try:
+        bash_path = tools_locations["msys2"]["system"]["path"]["Windows"] + "/bash.exe"
+    except KeyError:
+        pytest.skip("msys2 path not defined")
+
+    conanfile = textwrap.dedent("""
+        from conan import ConanFile
+
+        class Recipe(ConanFile):
+            name="msys2"
+            version="1.0"
+
+            def package_info(self):
+                self.conf_info.define("tools.microsoft.bash:subsystem", "msys2")
+                self.conf_info.define("tools.microsoft.bash:path", "{}")
+    """.format(bash_path))
+    client.save({"conanfile.py": conanfile})
+    client.run("create .")
+
+    conanfile = GenConanfile("consumer", "1.0")
+    test_package = textwrap.dedent("""
+        from conan import ConanFile
+
+        class Recipe(ConanFile):
+            name="test"
+            version="1.0"
+            win_bash = True
+
+            def build_requirements(self):
+                self.tool_requires(self.tested_reference_str)
+                self.tool_requires("msys2/1.0")
+
+            def build(self):
+                self.output.warning(self.conf.get("tools.microsoft.bash:subsystem"))
+                self.run("aclocal --version")
+
+            def test(self):
+                pass
+        """)
+    client.save({"conanfile.py": conanfile, "test_package/conanfile.py": test_package})
+    client.run("create . -s:b os=Windows -s:h os=Windows")
+    assert "are needed to run commands in a Windows subsystem" not in client.out
+    assert "aclocal (GNU automake)" in client.out
diff --git a/test/integration/configuration/conf/test_conf_profile.py b/test/integration/configuration/conf/test_conf_profile.py
index e6f81fc65..45b0589c3 100644
--- a/test/integration/configuration/conf/test_conf_profile.py
+++ b/test/integration/configuration/conf/test_conf_profile.py
@@ -1,4 +1,3 @@
-import platform
 import textwrap
 
 import pytest
@@ -156,9 +155,9 @@ def test_msbuild_config():
     assert "/verbosity:Quiet" in client.out
 
 
-@pytest.mark.tool("visual_studio")
-@pytest.mark.skipif(platform.system() != "Windows", reason="Only for windows")
 def test_msbuild_compile_options():
+    # This works in all platforms because MSBuildToolchain works even in Linux, it will
+    # just skip generating the conanvcvars.bat
     client = TestClient()
     conanfile = textwrap.dedent("""
         from conan import ConanFile
diff --git a/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py b/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
index 563f14069..50c2ec587 100644
--- a/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
+++ b/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
@@ -708,6 +708,7 @@ def test_cmakedeps_set_property_overrides():
     other = c.load("app/other-release-data.cmake")
     assert 'set(other_other_mycomp1_NO_SONAME_MODE_RELEASE TRUE)' in other
 
+
 def test_cmakedeps_set_legacy_variable_name():
     client = TestClient()
     base_conanfile = str(GenConanfile("dep", "1.0"))
@@ -742,3 +743,17 @@ def test_cmakedeps_set_legacy_variable_name():
         assert f"prefix_{variable}" in dep_config
     # Check that variables are not duplicated
     assert dep_config.count("PREFIX_VERSION") == 1
+
+
+def test_different_versions():
+    # https://github.com/conan-io/conan/issues/16274
+    c = TestClient()
+    c.save({"dep/conanfile.py": GenConanfile("dep")})
+    c.run("create dep --version 1.2")
+    c.run("create dep --version 2.3")
+    c.run("install --requires=dep/1.2 -g CMakeDeps")
+    config = c.load("dep-config.cmake")
+    assert 'set(dep_VERSION_STRING "1.2")' in config
+    c.run("install --requires=dep/2.3 -g CMakeDeps")
+    config = c.load("dep-config.cmake")
+    assert 'set(dep_VERSION_STRING "2.3")' in config
diff --git a/test/integration/toolchains/env/test_virtualenv_winbash.py b/test/integration/toolchains/env/test_virtualenv_winbash.py
index 97acf9a9b..523ca7aef 100644
--- a/test/integration/toolchains/env/test_virtualenv_winbash.py
+++ b/test/integration/toolchains/env/test_virtualenv_winbash.py
@@ -107,54 +107,3 @@ def test_nowinbash(client):
     assert not os.path.exists(os.path.join(client.current_folder, "conanrunenv.bat"))
     run_contents = client.load("conanrunenv.sh")
     assert 'export RUNTIME_VAR="/c/path/to/exe"' in run_contents
-
-
-@pytest.mark.skipif(platform.system() != "Windows", reason="Requires Windows")
-@pytest.mark.tool("msys2")
-def test_conf_inherited_in_test_package():
-    client = TestClient()
-    bash_path = tools_locations["msys2"]["system"]["path"]["Windows"] + "/bash.exe"
-    conanfile = textwrap.dedent("""
-            from conan import ConanFile
-
-            class Recipe(ConanFile):
-                name="msys2"
-                version="1.0"
-
-                def package_info(self):
-                    self.conf_info.define("tools.microsoft.bash:subsystem", "msys2")
-                    self.conf_info.define("tools.microsoft.bash:path", "{}")
-    """.format(bash_path))
-    client.save({"conanfile.py": conanfile})
-    client.run("create .")
-
-    conanfile = textwrap.dedent("""
-                from conan import ConanFile
-
-                class Recipe(ConanFile):
-                    name="consumer"
-                    version="1.0"
-        """)
-    test_package = textwrap.dedent("""
-                    from conan import ConanFile
-
-                    class Recipe(ConanFile):
-                        name="test"
-                        version="1.0"
-                        win_bash = True
-
-                        def build_requirements(self):
-                            self.tool_requires(self.tested_reference_str)
-                            self.tool_requires("msys2/1.0")
-
-                        def build(self):
-                            self.output.warning(self.conf.get("tools.microsoft.bash:subsystem"))
-                            self.run("aclocal --version")
-
-                        def test(self):
-                            pass
-            """)
-    client.save({"conanfile.py": conanfile, "test_package/conanfile.py": test_package})
-    client.run("create . -s:b os=Windows -s:h os=Windows")
-    assert "are needed to run commands in a Windows subsystem" not in client.out
-    assert "aclocal (GNU automake)" in client.out