Repository: conan-io/conan
Pull request #16581 (2024-07-01 17:33:14)

fix detect_msvc_compiler
Changelog: Bugfix: Fix ``detect_msvc_compiler()`` from ``detect_api`` to properly detect VS 17.10 with ``compiler.version=194``
Docs: Omit

Close https://github.com/conan-io/conan/issues/16577


Patch:
diff --git a/conan/api/subapi/install.py b/conan/api/subapi/install.py
index 0fb5e1108..5a5b677f6 100644
--- a/conan/api/subapi/install.py
+++ b/conan/api/subapi/install.py
@@ -1,3 +1,5 @@
+import os
+
 from conan.internal.conan_app import ConanApp
 from conan.internal.deploy import do_deploys
 from conans.client.generators import write_generators
@@ -70,7 +72,9 @@ class InstallAPI:
 
         # The previous .set_base_folders has already decided between the source_folder and output
         if deploy or deploy_package:
-            base_folder = deploy_folder or conanfile.folders.base_build
+            # Issue related: https://github.com/conan-io/conan/issues/16543
+            base_folder = os.path.abspath(deploy_folder) if deploy_folder \
+                else conanfile.folders.base_build
             do_deploys(self.conan_api, deps_graph, deploy, deploy_package, base_folder)
 
         final_generators = []
diff --git a/conan/internal/api/detect_api.py b/conan/internal/api/detect_api.py
index 04bb3ab16..697a02960 100644
--- a/conan/internal/api/detect_api.py
+++ b/conan/internal/api/detect_api.py
@@ -384,14 +384,9 @@ def detect_default_compiler():
         return None, None, None
 
     if platform.system() == "Windows":
-        ide_version = _detect_vs_ide_version()
-        version = {"17": "193", "16": "192", "15": "191"}.get(str(ide_version))  # Map to compiler
-        if ide_version == "17":
-            update = detect_msvc_update(version)  # FIXME weird passing here the 193 compiler version
-            if update and int(update) >= 10:
-                version = "194"
-        if version:
-            return 'msvc', Version(version), None
+        compiler, version, compiler_exe = detect_msvc_compiler()
+        if compiler:
+            return compiler, version, compiler_exe
 
     if platform.system() == "SunOS":
         sun_cc, sun_cc_version, compiler_exe = detect_suncc_compiler()
@@ -533,8 +528,12 @@ def detect_clang_compiler(compiler_exe="clang"):
 
 
 def detect_msvc_compiler():
-    version = _detect_vs_ide_version()
-    version = {"17": "193", "16": "192", "15": "191"}.get(str(version))  # Map to compiler
+    ide_version = _detect_vs_ide_version()
+    version = {"17": "193", "16": "192", "15": "191"}.get(str(ide_version))  # Map to compiler
+    if ide_version == "17":
+        update = detect_msvc_update(version)  # FIXME weird passing here the 193 compiler version
+        if update and int(update) >= 10:
+            version = "194"
     if version:
         return 'msvc', Version(version), None
     return None, None, None
diff --git a/conan/tools/gnu/pkgconfigdeps.py b/conan/tools/gnu/pkgconfigdeps.py
index be968f3ff..4e2160989 100644
--- a/conan/tools/gnu/pkgconfigdeps.py
+++ b/conan/tools/gnu/pkgconfigdeps.py
@@ -78,12 +78,11 @@ class _PCContentGenerator:
         ret = {}
         for i, directory in enumerate(folders):
             directory = os.path.normpath(directory).replace("\\", "/")
-            prefix = ""
-            if not os.path.isabs(directory):
-                prefix = "${prefix}/"
-            elif directory.startswith(prefix_path_):
+            if directory.startswith(prefix_path_):
                 prefix = "${prefix}/"
                 directory = os.path.relpath(directory, prefix_path_).replace("\\", "/")
+            else:
+                prefix = "" if os.path.isabs(directory) else "${prefix}/"
             suffix = str(i) if i else ""
             var_name = f"{folder_name}{suffix}"
             ret[var_name] = f"{prefix}{directory}"
diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py
index a174b260b..0c6bedc7e 100644
--- a/conans/model/conan_file.py
+++ b/conans/model/conan_file.py
@@ -352,6 +352,7 @@ class ConanFile:
         from conans.util.runners import conan_run
         if not quiet:
             ConanOutput().writeln(f"{self.display_name}: RUN: {command}", fg=Color.BRIGHT_BLUE)
+        ConanOutput().debug(f"{self.display_name}: Full command: {wrapped_cmd}")
         retcode = conan_run(wrapped_cmd, cwd=cwd, stdout=stdout, stderr=stderr, shell=shell)
         if not quiet:
             ConanOutput().writeln("")


Test patch:
diff --git a/test/functional/toolchains/gnu/test_pkgconfigdeps_autotools.py b/test/functional/toolchains/gnu/test_pkgconfigdeps_autotools.py
index 1d328cd86..e6cd401db 100644
--- a/test/functional/toolchains/gnu/test_pkgconfigdeps_autotools.py
+++ b/test/functional/toolchains/gnu/test_pkgconfigdeps_autotools.py
@@ -110,5 +110,3 @@ def test_pkgconfigdeps_and_autotools():
         # Issue: https://github.com/conan-io/conan/issues/11867
         assert '-F/my/framework/file1' in client.out
         assert '-F/my/framework/file2' in client.out
-        assert "warning: directory not found for option '-F/my/framework/file1'" in client.out
-        assert "warning: directory not found for option '-F/my/framework/file2'" in client.out
diff --git a/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py b/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
index 50c2ec587..bbbc124f4 100644
--- a/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
+++ b/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
@@ -757,3 +757,33 @@ def test_different_versions():
     c.run("install --requires=dep/2.3 -g CMakeDeps")
     config = c.load("dep-config.cmake")
     assert 'set(dep_VERSION_STRING "2.3")' in config
+
+
+def test_using_deployer_folder():
+    """
+    Related to: https://github.com/conan-io/conan/issues/16543
+
+    CMakeDeps was failing if --deployer-folder was used. The error looked like:
+
+    conans.errors.ConanException: Error in generator 'CMakeDeps': error generating context for 'dep/1.0': mydeploy/direct_deploy/dep/include is not absolute
+    """
+    c = TestClient()
+    profile = textwrap.dedent("""
+    [settings]
+    arch=x86_64
+    build_type=Release
+    compiler=apple-clang
+    compiler.cppstd=gnu17
+    compiler.libcxx=libc++
+    compiler.version=15
+    os=Macos
+    """)
+    c.save({
+        "profile": profile,
+        "dep/conanfile.py": GenConanfile("dep")})
+    c.run("create dep --version 1.0")
+    c.run("install --requires=dep/1.0 -pr profile --deployer=direct_deploy "
+          "--deployer-folder=mydeploy -g CMakeDeps")
+    content = c.load("dep-release-x86_64-data.cmake")
+    assert ('set(dep_PACKAGE_FOLDER_RELEASE "${CMAKE_CURRENT_LIST_DIR}/mydeploy/direct_deploy/dep")'
+            in content)
diff --git a/test/integration/toolchains/gnu/test_pkgconfigdeps.py b/test/integration/toolchains/gnu/test_pkgconfigdeps.py
index 29530e431..467d4f1f4 100644
--- a/test/integration/toolchains/gnu/test_pkgconfigdeps.py
+++ b/test/integration/toolchains/gnu/test_pkgconfigdeps.py
@@ -1098,3 +1098,23 @@ def test_pkg_config_deps_and_private_deps():
     # Now, it passes and creates the pc files correctly (the skipped one is not created)
     client.run("install .")
     assert "Requires:" not in client.load("pkg.pc")
+
+
+def test_using_deployer_folder():
+    """
+    Testing that the absolute path is kept as the prefix instead of the
+    relative path.
+
+    Issue related: https://github.com/conan-io/conan/issues/16543
+    """
+    client = TestClient()
+    client.save({"dep/conanfile.py": GenConanfile("dep", "0.1")})
+    client.run("create dep/conanfile.py")
+    client.run("install --requires=dep/0.1 --deployer=direct_deploy "
+               "--deployer-folder=mydeploy -g PkgConfigDeps")
+    content = client.load("dep.pc")
+    prefix_base = client.current_folder.replace('\\', '/')
+    assert f"prefix={prefix_base}/mydeploy/direct_deploy/dep" in content
+    assert "libdir=${prefix}/lib" in content
+    assert "includedir=${prefix}/include" in content
+    assert "bindir=${prefix}/bin" in content