Repository: conan-io/conan
Pull request #11949 (2022-08-24 09:13:40)

add ``is_msvc(..., build_context=False)`` argument
Changelog: Feature: Add ``is_msvc(..., build_context=False)`` argument
Docs: https://github.com/conan-io/docs/pull/XXXX

Close https://github.com/conan-io/conan/issues/11926



Patch:
diff --git a/conan/tools/apple/xcodedeps.py b/conan/tools/apple/xcodedeps.py
index 8a1c7cd35..4838df7a5 100644
--- a/conan/tools/apple/xcodedeps.py
+++ b/conan/tools/apple/xcodedeps.py
@@ -61,6 +61,7 @@ class XcodeDeps(object):
     general_name = "conandeps.xcconfig"
 
     _conf_xconfig = textwrap.dedent("""\
+        PACKAGE_ROOT_{{pkg_name}}{{condition}} = {{root}}
         // Compiler options for {{pkg_name}}::{{comp_name}}
         HEADER_SEARCH_PATHS_{{pkg_name}}_{{comp_name}}{{condition}} = {{include_dirs}}
         GCC_PREPROCESSOR_DEFINITIONS_{{pkg_name}}_{{comp_name}}{{condition}} = {{definitions}}
@@ -122,7 +123,7 @@ class XcodeDeps(object):
         for generator_file, content in generator_files.items():
             save(generator_file, content)
 
-    def _conf_xconfig_file(self, pkg_name, comp_name, transitive_cpp_infos):
+    def _conf_xconfig_file(self, pkg_name, comp_name, package_folder, transitive_cpp_infos):
         """
         content for conan_poco_x86_release.xcconfig, containing the activation
         """
@@ -133,6 +134,7 @@ class XcodeDeps(object):
         fields = {
             'pkg_name': pkg_name,
             'comp_name': comp_name,
+            'root': package_folder,
             'include_dirs': " ".join('"{}"'.format(p) for p in _merged_vars("includedirs")),
             'lib_dirs': " ".join('"{}"'.format(p) for p in _merged_vars("libdirs")),
             'libs': " ".join("-l{}".format(lib) for lib in _merged_vars("libs")),
@@ -197,13 +199,13 @@ class XcodeDeps(object):
                                                GLOBAL_XCCONFIG_TEMPLATE,
                                                [self.general_name])
 
-    def get_content_for_component(self, pkg_name, component_name, transitive_internal, transitive_external):
+    def get_content_for_component(self, pkg_name, component_name, package_folder, transitive_internal, transitive_external):
         result = {}
 
         conf_name = _xcconfig_settings_filename(self._conanfile.settings)
 
         props_name = "conan_{}_{}{}.xcconfig".format(pkg_name, component_name, conf_name)
-        result[props_name] = self._conf_xconfig_file(pkg_name, component_name, transitive_internal)
+        result[props_name] = self._conf_xconfig_file(pkg_name, component_name, package_folder, transitive_internal)
 
         # The entry point for each package
         file_dep_name = "conan_{}_{}.xcconfig".format(pkg_name, component_name)
@@ -262,6 +264,7 @@ class XcodeDeps(object):
                     transitive_external = list(OrderedDict.fromkeys(transitive_external).keys())
 
                     component_content = self.get_content_for_component(dep_name, comp_name,
+                                                                       dep.package_folder,
                                                                        transitive_internal,
                                                                        transitive_external)
                     include_components_names.append((dep_name, comp_name))
@@ -279,7 +282,7 @@ class XcodeDeps(object):
                         public_deps.append((_format_name(d.ref.name),) * 2)
 
                 required_components = dep.cpp_info.required_components if dep.cpp_info.required_components else public_deps
-                root_content = self.get_content_for_component(dep_name, dep_name, [dep.cpp_info],
+                root_content = self.get_content_for_component(dep_name, dep_name, dep.package_folder, [dep.cpp_info],
                                                               required_components)
                 include_components_names.append((dep_name, dep_name))
                 result.update(root_content)
diff --git a/conan/tools/microsoft/visual.py b/conan/tools/microsoft/visual.py
index d3f948ad5..307efff1e 100644
--- a/conan/tools/microsoft/visual.py
+++ b/conan/tools/microsoft/visual.py
@@ -226,12 +226,17 @@ def _vcvars_vers(conanfile, compiler, vs_version):
     return vcvars_ver
 
 
-def is_msvc(conanfile):
+def is_msvc(conanfile, build_context=False):
     """ Validate if current compiler in setttings is 'Visual Studio' or 'msvc'
     :param conanfile: ConanFile instance
+    :param build_context: If True, will use the settings from the build context, not host ones
     :return: True, if the host compiler is related to Visual Studio, otherwise, False.
     """
-    settings = conanfile.settings
+    # FIXME: 2.0: remove "hasattr()" condition
+    if not build_context or not hasattr(conanfile, "settings_build"):
+        settings = conanfile.settings
+    else:
+        settings = conanfile.settings_build
     return settings.get_safe("compiler") in ["Visual Studio", "msvc"]
 
 


Test patch:
diff --git a/conans/test/conftest.py b/conans/test/conftest.py
index a3e45cfd7..5c0cc4996 100644
--- a/conans/test/conftest.py
+++ b/conans/test/conftest.py
@@ -91,6 +91,14 @@ tools_locations = {
             "path": {'Windows': 'C:/Tools/ninja/1.10.2'}
         }
     },
+    # This is the non-msys2 mingw, which is 32 bits x86 arch
+    'mingw': {
+        "disabled": True,
+        "platform": "Windows",
+        "default": "system",
+        "exe": "mingw32-make",
+        "system": {"path": {'Windows': "C:/mingw"}},
+    },
     'mingw32': {
         "platform": "Windows",
         "default": "system",
diff --git a/conans/test/functional/subsystems_build_test.py b/conans/test/functional/subsystems_build_test.py
index 4faa08d36..eade2dc34 100644
--- a/conans/test/functional/subsystems_build_test.py
+++ b/conans/test/functional/subsystems_build_test.py
@@ -85,12 +85,12 @@ class TestSubsystems:
 class TestSubsystemsBuild:
 
     @staticmethod
-    def _build(client, static_runtime=None):
+    def _build(client, static_runtime=None, make="make"):
         makefile = gen_makefile(apps=["app"], static_runtime=static_runtime)
         main_cpp = gen_function_cpp(name="main")
         client.save({"Makefile": makefile,
                      "app.cpp": main_cpp})
-        client.run_command("make")
+        client.run_command(make)
         client.run_command("app")
 
     @pytest.mark.parametrize("static", [True, False])
@@ -111,6 +111,22 @@ class TestSubsystemsBuild:
         check_vs_runtime("app.exe", client, "15", "Debug", static_runtime=static,
                          subsystem="msys2")
 
+    @pytest.mark.parametrize("static", [True, False])
+    @pytest.mark.tool_mingw
+    def test_mingw(self, static):
+        """
+        This will work if you installed the Mingw toolchain outside msys2, from
+        https://sourceforge.net/projects/mingw/, and installed gcc, autotools, mingw32-make, etc
+
+        But this doesn't contain "make", only "mingw32-make"
+        """
+        client = TestClient()
+        self._build(client, static_runtime=static, make="mingw32-make")
+
+        check_exe_run(client.out, "main", "gcc", None, "Debug", "x86", None, subsystem="mingw32")
+        check_vs_runtime("app.exe", client, "15", "Debug", static_runtime=static,
+                         subsystem="mingw64")
+
     @pytest.mark.parametrize("static", [True, False])
     @pytest.mark.tool_msys2
     @pytest.mark.tool_mingw64
diff --git a/conans/test/unittests/tools/microsoft/test_msbuild.py b/conans/test/unittests/tools/microsoft/test_msbuild.py
index 89afb227a..82bceeaf9 100644
--- a/conans/test/unittests/tools/microsoft/test_msbuild.py
+++ b/conans/test/unittests/tools/microsoft/test_msbuild.py
@@ -197,6 +197,21 @@ def test_is_msvc(compiler, expected):
     assert is_msvc(conanfile) == expected
 
 
+def test_is_msvc_build():
+    settings = Settings({"build_type": ["Release"],
+                         "compiler": ["gcc", "msvc"],
+                         "os": ["Windows"],
+                         "arch": ["x86_64"]})
+    conanfile = ConanFile(Mock(), None)
+    conanfile.settings = "os", "compiler", "build_type", "arch"
+    conanfile.initialize(settings, EnvValues())
+    conanfile.settings.compiler = "gcc"
+    conanfile.settings_build = conanfile.settings.copy()
+    conanfile.settings_build.compiler = "msvc"
+    assert is_msvc(conanfile) is False
+    assert is_msvc(conanfile, build_context=True) is True
+
+
 @pytest.mark.parametrize("compiler,shared,runtime,build_type,expected", [
     ("Visual Studio", True, "MT", "Release", True),
     ("msvc", True, "static", "Release", True),