Repository: conan-io/conan
Pull request #12095 (2022-09-12 15:04:00)

Solving conf_info from BR inherited by consumers' test_package
Changelog: Fixed a bug when getting the values from the `self.conf` in the conanfile of a `test_package` with build_requirements declaring the `self.conf_info`.

The issue is in conan 1.x , the test_package conanfile cannot read (loses) the `conf` inherited from the build requires.
It works for 2.x BUT this is a conan-center-index recipes migration issue so we should provide the fix.

Closes https://github.com/conan-io/conan/issues/11975




Patch:
diff --git a/.gitignore b/.gitignore
index b4fd19089..c30249731 100644
--- a/.gitignore
+++ b/.gitignore
@@ -90,9 +90,10 @@ conan.conf
 #Generated certificate file
 cacert.pem
 
-#linux backup files
+#linux backup and vim files
 *~
-.*.swp
+.*.sw?
+Session.vim
 
 #Pyinstaller generated binaries
 /pyinstaller
diff --git a/conan/tools/apple/xcodedeps.py b/conan/tools/apple/xcodedeps.py
index 4838df7a5..fb79a0259 100644
--- a/conan/tools/apple/xcodedeps.py
+++ b/conan/tools/apple/xcodedeps.py
@@ -77,9 +77,8 @@ class XcodeDeps(object):
     _dep_xconfig = textwrap.dedent("""\
         // Conan XcodeDeps generated file for {{pkg_name}}::{{comp_name}}
         // Includes all configurations for each dependency
-        {% for dep in deps %}
-        // Includes for {{dep[0]}}::{{dep[1]}} dependency
-        #include "conan_{{dep[0]}}_{{dep[1]}}.xcconfig"
+        {% for include in deps_includes %}
+        #include "{{include}}"
         {% endfor %}
         #include "{{dep_xconfig_filename}}"
 
@@ -160,10 +159,18 @@ class XcodeDeps(object):
             content_multi = load(multi_path)
         else:
             content_multi = self._dep_xconfig
+
+            def _get_includes(components):
+                # if we require the root component dep::dep include conan_dep.xcconfig
+                # for components (dep::component) include conan_dep_component.xcconfig
+                return [f"conan_{_format_name(component[0])}.xcconfig" if component[0] == component[1]
+                        else f"conan_{_format_name(component[0])}_{_format_name(component[1])}.xcconfig"
+                        for component in components]
+
             content_multi = Template(content_multi).render({"pkg_name": pkg_name,
                                                             "comp_name": comp_name,
                                                             "dep_xconfig_filename": dep_xconfig_filename,
-                                                            "deps": reqs})
+                                                            "deps_includes": _get_includes(reqs)})
 
         if dep_xconfig_filename not in content_multi:
             content_multi = content_multi.replace('.xcconfig"',
diff --git a/conan/tools/cmake/toolchain/blocks.py b/conan/tools/cmake/toolchain/blocks.py
index 52608545e..3eb5865e5 100644
--- a/conan/tools/cmake/toolchain/blocks.py
+++ b/conan/tools/cmake/toolchain/blocks.py
@@ -523,8 +523,9 @@ class FindFiles(Block):
         os_ = self._conanfile.settings.get_safe("os")
         is_apple_ = is_apple_os(self._conanfile)
 
-        # Read information from host context
-        host_req = self._conanfile.dependencies.host.values()
+        # Read information from host context, also including test_requires, which are in host
+        # TODO: Add here in 2.0 the "skip": False trait
+        host_req = self._conanfile.dependencies.filter({"build": False}).values()
         host_build_paths_root = []
         host_build_paths_noroot = []
         host_lib_paths = []
diff --git a/conan/tools/cmake/toolchain/toolchain.py b/conan/tools/cmake/toolchain/toolchain.py
index 4227efae4..310648c41 100644
--- a/conan/tools/cmake/toolchain/toolchain.py
+++ b/conan/tools/cmake/toolchain/toolchain.py
@@ -17,6 +17,7 @@ from conan.tools.intel import IntelCC
 from conan.tools.microsoft import VCVars
 from conan.tools.microsoft.visual import vs_ide_version
 from conans.errors import ConanException
+from conans.model.options import PackageOption
 from conans.util.files import save
 
 
@@ -182,6 +183,13 @@ class CMakeToolchain(object):
         for name, value in self.cache_variables.items():
             if isinstance(value, bool):
                 cache_variables[name] = "ON" if value else "OFF"
+            elif isinstance(value, PackageOption):
+                if str(value).lower() in ["true", "false", "none"]:
+                    cache_variables[name] = "ON" if bool(value) else "OFF"
+                elif str(value).isdigit():
+                    cache_variables[name] = int(value)
+                else:
+                    cache_variables[name] = str(value)
             else:
                 cache_variables[name] = value
 
diff --git a/conan/tools/gnu/pkgconfigdeps.py b/conan/tools/gnu/pkgconfigdeps.py
index 2eb5a8ff8..38a7737d6 100644
--- a/conan/tools/gnu/pkgconfigdeps.py
+++ b/conan/tools/gnu/pkgconfigdeps.py
@@ -86,7 +86,7 @@ def _get_formatted_dirs(folders, prefix_path_):
 _PCInfo = namedtuple("PCInfo", ['name', 'requires', 'description', 'cpp_info', 'aliases'])
 
 
-class PCContentGenerator:
+class _PCContentGenerator:
 
     template = textwrap.dedent("""\
         {%- macro get_libs(libdirs, cpp_info, gnudeps_flags) -%}
@@ -198,13 +198,13 @@ class PCContentGenerator:
         return template.render(context)
 
 
-class PCGenerator:
+class _PCGenerator:
 
     def __init__(self, conanfile, dep, build_context_suffix=None):
         self._conanfile = conanfile
         self._build_context_suffix = build_context_suffix or {}
         self._dep = dep
-        self._content_generator = PCContentGenerator(self._conanfile, self._dep)
+        self._content_generator = _PCContentGenerator(self._conanfile, self._dep)
 
     def _get_cpp_info_requires_names(self, cpp_info):
         """
@@ -398,7 +398,7 @@ class PkgConfigDeps:
             if dep.is_build_context and dep.ref.name not in self.build_context_activated:
                 continue
 
-            pc_generator = PCGenerator(self._conanfile, dep, build_context_suffix=self.build_context_suffix)
+            pc_generator = _PCGenerator(self._conanfile, dep, build_context_suffix=self.build_context_suffix)
             pc_files.update(pc_generator.pc_files)
         return pc_files
 
diff --git a/conan/tools/microsoft/msbuilddeps.py b/conan/tools/microsoft/msbuilddeps.py
index 009395802..52353f433 100644
--- a/conan/tools/microsoft/msbuilddeps.py
+++ b/conan/tools/microsoft/msbuilddeps.py
@@ -11,7 +11,6 @@ from conans.errors import ConanException
 from conans.util.files import load, save
 
 VALID_LIB_EXTENSIONS = (".so", ".lib", ".a", ".dylib", ".bc")
-EXCLUDED_SYMBOLS_PATTERN = re.compile(r"[\.+\-]")
 
 
 class MSBuildDeps(object):
@@ -133,7 +132,7 @@ class MSBuildDeps(object):
 
     @staticmethod
     def _get_valid_xml_format(name):
-        return EXCLUDED_SYMBOLS_PATTERN.sub("_", name)
+        return re.compile(r"[.+]").sub("_", name)
 
     def _vars_props_file(self, dep, name, cpp_info, deps, build):
         """
diff --git a/conan/tools/microsoft/toolchain.py b/conan/tools/microsoft/toolchain.py
index 24c2fede8..2b9c4686b 100644
--- a/conan/tools/microsoft/toolchain.py
+++ b/conan/tools/microsoft/toolchain.py
@@ -36,6 +36,9 @@ class MSBuildToolchain(object):
           </ItemDefinitionGroup>
           <PropertyGroup Label="Configuration">
             <PlatformToolset>{{ toolset }}</PlatformToolset>
+            {% for k, v in properties.items() %}
+            <{{k}}>{{ v }}</{{k}}>
+            {% endfor %}
           </PropertyGroup>
         </Project>
     """)
@@ -51,6 +54,7 @@ class MSBuildToolchain(object):
         self.runtime_library = self._runtime_library(conanfile.settings)
         self.cppstd = conanfile.settings.get_safe("compiler.cppstd")
         self.toolset = self._msvs_toolset(conanfile)
+        self.properties = {}
         check_using_build_profile(self._conanfile)
 
     def _name_condition(self, settings):
@@ -163,7 +167,8 @@ class MSBuildToolchain(object):
             "runtime_library": runtime_library,
             "toolset": toolset,
             "compile_options": compile_options,
-            "parallel": parallel
+            "parallel": parallel,
+            "properties": self.properties,
         }
 
     def _write_config_toolchain(self, config_filename):
diff --git a/conan/tools/microsoft/visual.py b/conan/tools/microsoft/visual.py
index 307efff1e..961e72460 100644
--- a/conan/tools/microsoft/visual.py
+++ b/conan/tools/microsoft/visual.py
@@ -198,6 +198,11 @@ def vcvars_arch(conanfile):
                 'x86_64': 'x86_amd64',
                 'armv7': 'x86_arm',
                 'armv8': 'x86_arm64'}.get(arch_host)
+    elif arch_build == 'armv8':
+        arch = {'x86': 'arm64_x86',
+                'x86_64': 'arm64_x64',
+                'armv7': 'arm64_arm',
+                'armv8': 'arm64'}.get(arch_host)
 
     if not arch:
         raise ConanException('vcvars unsupported architectures %s-%s' % (arch_build, arch_host))
diff --git a/conans/client/cmd/build.py b/conans/client/cmd/build.py
index 6cda8eb6c..1a4207bfa 100644
--- a/conans/client/cmd/build.py
+++ b/conans/client/cmd/build.py
@@ -12,7 +12,7 @@ from conans.util.log import logger
 def cmd_build(app, conanfile_path, base_path, source_folder, build_folder, package_folder,
               install_folder, test=False, should_configure=True, should_build=True,
               should_install=True, should_test=True, layout_source_folder=None,
-              layout_build_folder=None):
+              layout_build_folder=None, conf=None):
     """ Call to build() method saved on the conanfile.py
     param conanfile_path: path to a conanfile.py
     """
@@ -29,6 +29,8 @@ def cmd_build(app, conanfile_path, base_path, source_folder, build_folder, packa
                              "requirements and generators from '%s' file"
                              % (CONANFILE, CONANFILE, CONANFILE_TXT))
 
+    if conf:
+        conan_file.conf.compose_conf(conf)
     if test:
         try:
             conan_file.requires.add_ref(test)
diff --git a/conans/client/manager.py b/conans/client/manager.py
index f27fba832..d0160ce5c 100644
--- a/conans/client/manager.py
+++ b/conans/client/manager.py
@@ -146,4 +146,4 @@ def deps_install(app, ref_or_path, install_folder, base_folder, graph_info, remo
             if hasattr(deploy_conanfile, "deploy") and callable(deploy_conanfile.deploy):
                 run_deploy(deploy_conanfile, install_folder)
 
-    return install_folder
+    return install_folder, conanfile
diff --git a/conans/client/tools/win.py b/conans/client/tools/win.py
index 618cd8a84..fc51b1a20 100644
--- a/conans/client/tools/win.py
+++ b/conans/client/tools/win.py
@@ -442,6 +442,11 @@ def vcvars_command(conanfile=None, arch=None, compiler_version=None, force=False
                        'x86_64': 'x86_amd64',
                        'armv7': 'x86_arm',
                        'armv8': 'x86_arm64'}.get(arch_setting)
+    elif arch_build == 'armv8':
+        vcvars_arch = {'x86': 'arm64_x86',
+                       'x86_64': 'arm64_x64',
+                       'armv7': 'arm64_arm',
+                       'armv8': 'arm64'}.get(arch_setting)
 
     if not vcvars_arch:
         raise ConanException('unsupported architecture %s' % arch_setting)
diff --git a/conans/model/options.py b/conans/model/options.py
index 642c4afe2..8c2702380 100644
--- a/conans/model/options.py
+++ b/conans/model/options.py
@@ -231,6 +231,12 @@ class OptionsValues(object):
             return None
         return getattr(self._package_values, attr)
 
+    def rm_safe(self, attr):
+        try:
+            delattr(self._package_values, attr)
+        except ConanException:
+            pass
+
     def __getitem__(self, item):
         return self._reqs_options.setdefault(item, PackageOptionValues())
 
@@ -425,6 +431,12 @@ class PackageOptions(object):
     def get_safe(self, field, default=None):
         return self._data.get(field, default)
 
+    def rm_safe(self, field):
+        try:
+            delattr(self, field)
+        except ConanException:
+            pass
+
     def validate(self):
         for child in self._data.values():
             child.validate()
@@ -584,6 +596,9 @@ class Options(object):
         except ConanException:
             pass
 
+    def rm_safe(self, field):
+        self._package_options.rm_safe(field)
+
     @property
     def values(self):
         result = OptionsValues()
diff --git a/conans/model/settings.py b/conans/model/settings.py
index 8a7e697aa..096483ed3 100644
--- a/conans/model/settings.py
+++ b/conans/model/settings.py
@@ -213,6 +213,19 @@ class Settings(object):
             return str(tmp)
         return default
 
+    def rm_safe(self, name):
+        try:
+            tmp = self
+            attr_ = name
+            if "." in name:
+                fields = name.split(".")
+                attr_ = fields.pop()
+                for prop in fields:
+                    tmp = getattr(tmp, prop)
+            delattr(tmp, attr_)
+        except ConanException:
+            pass
+
     def copy(self):
         """ deepcopy, recursive
         """
diff --git a/conans/requirements.txt b/conans/requirements.txt
index e433e5cf0..6afa64a16 100644
--- a/conans/requirements.txt
+++ b/conans/requirements.txt
@@ -6,7 +6,7 @@ patch-ng>=1.17.4, <1.18
 fasteners>=0.14.1
 six>=1.10.0,<=1.16.0
 node-semver==0.6.1
-distro>=1.0.2, <=1.6.0; sys_platform == 'linux' or sys_platform == 'linux2'
+distro>=1.0.2, <=1.7.0; sys_platform == 'linux' or sys_platform == 'linux2'
 pygments>=2.0, <3.0
 tqdm>=4.28.1, <5
 Jinja2>=2.9, <3.0.0;python_version<='2.7'


Test patch:
diff --git a/conans/client/cmd/test.py b/conans/client/cmd/test.py
index 4c2f580dd..996ff39b1 100644
--- a/conans/client/cmd/test.py
+++ b/conans/client/cmd/test.py
@@ -32,7 +32,7 @@ def install_build_and_test(app, conanfile_abs_path, reference, graph_info,
     if build_modes is None:
         build_modes = ["never"]
     try:
-        install_folder = deps_install(app=app,
+        install_folder, conanfile = deps_install(app=app,
                                       create_reference=reference,
                                       ref_or_path=conanfile_abs_path,
                                       install_folder=test_build_folder,
@@ -53,7 +53,7 @@ def install_build_and_test(app, conanfile_abs_path, reference, graph_info,
         cmd_build(app, conanfile_abs_path, test_build_folder,
                   source_folder=base_folder, build_folder=test_build_folder,
                   package_folder=os.path.join(test_build_folder, "package"),
-                  install_folder=install_folder, test=reference)
+                  install_folder=install_folder, test=reference, conf=conanfile.conf)
     finally:
         if delete_after_build:
             # Required for windows where deleting the cwd is not possible.
diff --git a/conans/test/functional/toolchains/apple/test_xcodedeps_components.py b/conans/test/functional/toolchains/apple/test_xcodedeps_components.py
index 2a50ab1e0..978b3e40d 100644
--- a/conans/test/functional/toolchains/apple/test_xcodedeps_components.py
+++ b/conans/test/functional/toolchains/apple/test_xcodedeps_components.py
@@ -105,10 +105,10 @@ def test_xcodedeps_components():
         self.cpp_info.components["core"].includedirs.append("include")
         self.cpp_info.components["core"].libdirs.append("lib")
 
-        self.cpp_info.components["client"].libs = ["client"]
-        self.cpp_info.components["client"].includedirs.append("include")
-        self.cpp_info.components["client"].libdirs.append("lib")
-        self.cpp_info.components["client"].requires.extend(["core", "tcp::tcp"])
+        self.cpp_info.components["client-test"].libs = ["client"]
+        self.cpp_info.components["client-test"].includedirs.append("include")
+        self.cpp_info.components["client-test"].libdirs.append("lib")
+        self.cpp_info.components["client-test"].requires.extend(["core", "tcp::tcp"])
 
         self.cpp_info.components["server"].libs = ["server"]
         self.cpp_info.components["server"].includedirs.append("include")
@@ -136,7 +136,7 @@ def test_xcodedeps_components():
         self.cpp_info.libs = ["chat"]
         self.cpp_info.includedirs.append("include")
         self.cpp_info.libdirs.append("lib")
-        self.cpp_info.requires.append("network::client")
+        self.cpp_info.requires.append("network::client-test")
     """
 
     cmakelists_chat = textwrap.dedent("""
@@ -146,7 +146,7 @@ def test_xcodedeps_components():
         add_library(chat src/chat.cpp include/chat.h)
         target_include_directories(chat PUBLIC include)
         set_target_properties(chat PROPERTIES PUBLIC_HEADER "include/chat.h")
-        target_link_libraries(chat network::client)
+        target_link_libraries(chat network::client-test)
         install(TARGETS chat)
         """)
 
@@ -184,7 +184,7 @@ def test_xcodedeps_components():
     client.run("install chat/1.0@ -g XcodeDeps --install-folder=conan -s build_type=Debug "
                "--build=missing")
     chat_xcconfig = client.load(os.path.join("conan", "conan_chat_chat.xcconfig"))
-    assert '#include "conan_network_client.xcconfig"' in chat_xcconfig
+    assert '#include "conan_network_client_test.xcconfig"' in chat_xcconfig
     assert '#include "conan_network_server.xcconfig"' not in chat_xcconfig
     assert '#include "conan_network_network.xcconfig"' not in chat_xcconfig
     host_arch = client.get_default_host_profile().settings['arch']
@@ -204,6 +204,78 @@ def test_xcodedeps_components():
     assert "chat/1.0: Hello World Release!" in client.out
 
 
+@pytest.mark.skipif(platform.system() != "Darwin", reason="Only for MacOS")
+@pytest.mark.tool_cmake
+def test_cpp_info_require_whole_package():
+    """
+    https://github.com/conan-io/conan/issues/12089
+
+    liba has two components liba::cmp1 liba::cmp2
+
+    libb has not components and requires liba::liba so should generate the same info as
+    if it was requiring liba::cmp1 and liba::cmp2
+
+    libc has components and one component requires liba::liba so should generate the same info as if
+    it was requiring liba::cmp1 and liba::cmp2
+    """
+    client = TestClient(path_with_spaces=False)
+
+    liba = textwrap.dedent("""
+        import os
+        from conan import ConanFile
+        class LibConan(ConanFile):
+            settings = "os", "compiler", "build_type", "arch"
+            name = "liba"
+            version = "1.0"
+            def package_info(self):
+                self.cpp_info.components["cmp1"].includedirs.append("cmp1")
+                self.cpp_info.components["cmp2"].includedirs.append("cmp2")
+        """)
+
+    libb = textwrap.dedent("""
+        import os
+        from conan import ConanFile
+        class LibConan(ConanFile):
+            settings = "os", "compiler", "build_type", "arch"
+            name = "libb"
+            version = "1.0"
+            requires = "liba/1.0"
+            def package_info(self):
+                self.cpp_info.requires = ["liba::liba"]
+        """)
+
+    libc = textwrap.dedent("""
+        import os
+        from conan import ConanFile
+        class LibConan(ConanFile):
+            settings = "os", "compiler", "build_type", "arch"
+            name = "libc"
+            version = "1.0"
+            requires = "liba/1.0"
+            def package_info(self):
+                self.cpp_info.components["cmp1"].includedirs.append("cmp1")
+                self.cpp_info.components["cmp2"].includedirs.append("cmp2")
+                self.cpp_info.components["cmp1"].requires = ["liba::liba"]
+        """)
+
+    client.save({"liba.py": liba, "libb.py": libb, "libc.py": libc})
+
+    client.run("create liba.py")
+    client.run("create libb.py")
+    client.run("create libc.py")
+    client.run("install libb/1.0@ -g XcodeDeps --install-folder=libb")
+
+    libb_xcconfig = client.load(os.path.join("libb", "conan_libb_libb.xcconfig"))
+    assert '#include "conan_liba.xcconfig"' in libb_xcconfig
+    assert '#include "conan_liba_liba.xcconfig"' not in libb_xcconfig
+
+    client.run("install libc/1.0@ -g XcodeDeps --install-folder=libc")
+
+    libc_comp1_xcconfig = client.load(os.path.join("libc", "conan_libc_cmp1.xcconfig"))
+    assert '#include "conan_liba.xcconfig"' in libc_comp1_xcconfig
+    assert '#include "conan_liba_liba.xcconfig"' not in libc_comp1_xcconfig
+
+
 @pytest.mark.skipif(platform.system() != "Darwin", reason="Only for MacOS")
 @pytest.mark.tool_cmake
 def test_xcodedeps_test_require():
diff --git a/conans/test/functional/toolchains/test_msbuild_toolchain.py b/conans/test/functional/toolchains/test_msbuild_toolchain.py
index b6869796d..f3d557b72 100644
--- a/conans/test/functional/toolchains/test_msbuild_toolchain.py
+++ b/conans/test/functional/toolchains/test_msbuild_toolchain.py
@@ -31,11 +31,13 @@ def test_toolchain_win(compiler, version, runtime):
             settings = "os", "compiler", "build_type", "arch"
             def generate(self):
                 msbuild = MSBuildToolchain(self)
+                msbuild.properties["IncludeExternals"] = "true"
                 msbuild.generate()
             """)
     client.save({"conanfile.py": conanfile})
     client.run("install . {}".format(settings))
     props = client.load("conantoolchain_release_x64.props")
+    assert "<IncludeExternals>true</IncludeExternals>" in props
     assert "<LanguageStandard>stdcpp17</LanguageStandard>" in props
     if version == "190":
         assert "<PlatformToolset>v140</PlatformToolset>" in props
diff --git a/conans/test/functional/tools/old/vcvars/vcvars_arch_test.py b/conans/test/functional/tools/old/vcvars/vcvars_arch_test.py
index c8ddb3570..01ddb370e 100644
--- a/conans/test/functional/tools/old/vcvars/vcvars_arch_test.py
+++ b/conans/test/functional/tools/old/vcvars/vcvars_arch_test.py
@@ -53,6 +53,17 @@ class VCVarsArchTest(unittest.TestCase):
         settings.arch = 'x86'
         self.assert_vcvars_command(settings, "amd64_x86")
 
+        settings.arch_build = 'armv8'
+        settings.arch = 'armv8'
+
+        self.assert_vcvars_command(settings, "arm64")
+
+        settings.arch = 'x86'
+        self.assert_vcvars_command(settings, "arm64_x86")
+
+        settings.arch = 'x86_64'
+        self.assert_vcvars_command(settings, "arm64_x64")
+
     def test_arch_override(self):
         settings = Settings.loads(get_default_settings_yml())
         settings.compiler = 'Visual Studio'
diff --git a/conans/test/integration/package_id/compatible_test.py b/conans/test/integration/package_id/compatible_test.py
index fb9393812..305dba427 100644
--- a/conans/test/integration/package_id/compatible_test.py
+++ b/conans/test/integration/package_id/compatible_test.py
@@ -4,7 +4,7 @@ import unittest
 
 
 from conans.model.ref import ConanFileReference
-from conans.test.utils.tools import TestClient, GenConanfile
+from conans.test.utils.tools import TestClient, GenConanfile, TestServer
 from conans.util.files import save
 
 
@@ -87,6 +87,53 @@ class CompatibleIDsTest(unittest.TestCase):
         self.assertIn("pkg/0.1@user/stable:53f56fbd582a1898b3b9d16efd6d3c0ec71e7cfb - Build",
                       client.out)
 
+    def test_compatible_setting_debug_release(self):
+        # From issue https://github.com/conan-io/conan/issues/9398
+        client = TestClient(default_server_user=True)
+        conanfile = textwrap.dedent("""\
+            from conan import ConanFile
+            class Pkg(ConanFile):
+                name = "pkga"
+                version = "0.1"
+                settings = "build_type"
+
+                def package_id(self):
+                    compatible_pkg = self.info.clone()
+                    compatible_pkg.settings.build_type = "Release"
+                    self.compatible_packages.append(compatible_pkg)
+            """)
+        client.save({"conanfile.py": conanfile})
+        # Create the recipe and upload it into the remote
+        client.run("create . -s build_type=Release")
+        client.run("upload pkg* -r=default --confirm --all")
+        client.run("remove * -f")
+
+        # Install locally the uploaded package
+        client.run("install pkga/0.1@")
+
+        # Create a middle package and export it
+        conanfile = textwrap.dedent("""\
+            from conan import ConanFile
+
+            class PkgB(ConanFile):
+                name = "pkgb"
+                version = "0.1"
+                build_requires = "pkga/0.1"
+               """)
+        client.save({"conanfile.py": conanfile}, clean_first=True)
+        client.run("export .")
+
+        # Create a final package and install it changing the "build_type"
+        conanfile = textwrap.dedent("""\
+            from conan import ConanFile
+
+            class PkgC(ConanFile):
+               requires = "pkgb/0.1"
+               build_requires = "pkga/0.1"
+               """)
+        client.save({"conanfile.py": conanfile}, clean_first=True)
+        client.run("install . -s build_type=Debug --build=missing")
+
     def test_compatible_setting_no_user_channel(self):
         client = TestClient()
         conanfile = textwrap.dedent("""
diff --git a/conans/test/integration/settings/remove_subsetting_test.py b/conans/test/integration/settings/remove_subsetting_test.py
index 5c8e6d8a2..209838e1b 100644
--- a/conans/test/integration/settings/remove_subsetting_test.py
+++ b/conans/test/integration/settings/remove_subsetting_test.py
@@ -1,4 +1,5 @@
 import os
+import textwrap
 import unittest
 
 from conans.test.utils.tools import TestClient
@@ -144,3 +145,57 @@ class ConanLib(ConanFile):
         client.run("package .")
         self.assertIn("ERROR: PACKAGE 'settings.compiler.libcxx' doesn't exist for 'gcc'",
                       client.out)
+
+
+def test_settings_and_options_rm_safe():
+    client = TestClient()
+    conanfile = textwrap.dedent("""
+    from conan import ConanFile
+    class Pkg(ConanFile):
+        settings = "os", "build_type", "compiler"
+        options = {"opt1": [True, False], "opt2": [True, False]}
+        default_options = "opt1=True", "opt2=False"
+
+        def configure(self):
+            # setting
+            self.settings.rm_safe("build_type")
+            # sub-setting
+            self.settings.rm_safe("compiler.version")
+            # wrong settings
+            self.settings.rm_safe("fake_field")
+            self.settings.rm_safe("fake_field.version")
+
+        def config_options(self):
+            # option
+            self.options.rm_safe("opt2")
+            # wrong option
+            self.options.rm_safe("opt15")
+
+        def build(self):
+            try:
+                self.settings.build_type
+            except Exception as exc:
+                self.output.warn(str(exc))
+            try:
+                self.settings.compiler.version
+            except Exception as exc:
+                self.output.warn(str(exc))
+            try:
+                self.options.opt2
+            except Exception as exc:
+                self.output.warn(str(exc))
+            assert "opt2" not in self.options
+    """)
+    client.save({"conanfile.py": conanfile})
+    build_folder = os.path.join(client.current_folder, "build")
+    mkdir(build_folder)
+    client.current_folder = build_folder
+
+    client.run("install ..")
+    client.run("build ..")
+    assert "'settings.build_type' doesn't exist" in client.out
+    assert "'settings' possible configurations are ['compiler', 'os']" in client.out
+    assert "'settings.compiler.version' doesn't exist" in client.out
+    assert "'settings.compiler' possible configurations are [" in client.out
+    assert "option 'opt2' doesn't exist" in client.out
+    assert "Possible options are ['opt1']" in client.out
diff --git a/conans/test/integration/toolchains/apple/test_xcodedeps.py b/conans/test/integration/toolchains/apple/test_xcodedeps.py
index 68d4d1991..6ec5f1c86 100644
--- a/conans/test/integration/toolchains/apple/test_xcodedeps.py
+++ b/conans/test/integration/toolchains/apple/test_xcodedeps.py
@@ -153,7 +153,7 @@ def test_xcodedeps_aggregate_components():
         assert f"conan_libb_libb_comp{index}.xcconfig" in lib_entry
 
     component7_entry = client.load("conan_libb_libb_comp7.xcconfig")
-    assert '#include "conan_liba_liba.xcconfig"' in component7_entry
+    assert '#include "conan_liba.xcconfig"' in component7_entry
 
     arch_setting = client.get_default_host_profile().settings['arch']
     arch = "arm64" if arch_setting == "armv8" else arch_setting
diff --git a/conans/test/integration/toolchains/cmake/test_cmaketoolchain.py b/conans/test/integration/toolchains/cmake/test_cmaketoolchain.py
index 8b6f35791..2b6382672 100644
--- a/conans/test/integration/toolchains/cmake/test_cmaketoolchain.py
+++ b/conans/test/integration/toolchains/cmake/test_cmaketoolchain.py
@@ -227,7 +227,6 @@ def test_find_builddirs():
 
                 def generate(self):
                     cmake = CMakeToolchain(self)
-                    {}
                     cmake.generate()
             """)
 
@@ -237,6 +236,30 @@ def test_find_builddirs():
         contents = f.read()
         assert "/path/to/builddir" in contents
 
+    conanfile = textwrap.dedent("""
+       import os
+       from conans import ConanFile
+       from conan.tools.cmake import CMakeToolchain
+
+       class Conan(ConanFile):
+           name = "mydep"
+           version = "1.0"
+           settings = "os", "arch", "compiler", "build_type"
+
+           def build_requirements(self):
+               self.test_requires("dep/1.0")
+
+           def generate(self):
+               cmake = CMakeToolchain(self)
+               cmake.generate()
+       """)
+
+    client.save({"conanfile.py": conanfile})
+    client.run("install . ")
+    with open(os.path.join(client.current_folder, "conan_toolchain.cmake")) as f:
+        contents = f.read()
+        assert "/path/to/builddir" in contents
+
 
 @pytest.mark.skipif(platform.system() != "Darwin", reason="Only OSX")
 def test_cmaketoolchain_cmake_system_processor_cross_apple():
@@ -447,17 +470,22 @@ def test_cmake_presets_singleconfig():
 def test_toolchain_cache_variables():
     client = TestClient()
     conanfile = textwrap.dedent("""
-        from conans import ConanFile
-        from conan.tools.cmake import CMakeToolchain, CMake
+        from conan import ConanFile
+        from conan.tools.cmake import CMakeToolchain
 
         class Conan(ConanFile):
             settings = "os", "arch", "compiler", "build_type"
+            options = {"enable_foobar": [True, False], "qux": ["ANY"], "number": [1,2]}
+            default_options = {"enable_foobar": True, "qux": "baz", "number": 1}
 
             def generate(self):
                 toolchain = CMakeToolchain(self)
                 toolchain.cache_variables["foo"] = True
                 toolchain.cache_variables["foo2"] = False
                 toolchain.cache_variables["var"] = "23"
+                toolchain.cache_variables["ENABLE_FOOBAR"] = self.options.enable_foobar
+                toolchain.cache_variables["QUX"] = self.options.qux
+                toolchain.cache_variables["NUMBER"] = self.options.number
                 toolchain.cache_variables["CMAKE_SH"] = "THIS VALUE HAS PRIORITY"
                 toolchain.cache_variables["CMAKE_POLICY_DEFAULT_CMP0091"] = "THIS VALUE HAS PRIORITY"
                 toolchain.cache_variables["CMAKE_MAKE_PROGRAM"] = "THIS VALUE HAS NO PRIORITY"
@@ -476,6 +504,9 @@ def test_toolchain_cache_variables():
     assert cache_variables["CMAKE_POLICY_DEFAULT_CMP0091"] == "THIS VALUE HAS PRIORITY"
     assert cache_variables["CMAKE_MAKE_PROGRAM"] == "MyMake"
     assert cache_variables["BUILD_TESTING"] == 'OFF'
+    assert cache_variables["ENABLE_FOOBAR"] == 'ON'
+    assert cache_variables["QUX"] == 'baz'
+    assert cache_variables["NUMBER"] == 1
 
 
 def test_android_c_library():
diff --git a/conans/test/integration/toolchains/env/test_virtualenv_winbash.py b/conans/test/integration/toolchains/env/test_virtualenv_winbash.py
index e79fdbd0f..dc231f5d8 100644
--- a/conans/test/integration/toolchains/env/test_virtualenv_winbash.py
+++ b/conans/test/integration/toolchains/env/test_virtualenv_winbash.py
@@ -1,9 +1,11 @@
 import os
 import platform
+import textwrap
 
 import pytest
 
 from conans.test.assets.genconanfile import GenConanfile
+from conans.test.conftest import tools_locations
 from conans.test.utils.tools import TestClient
 from conans.tools import save
 
@@ -166,3 +168,54 @@ def test_nowinbash_virtual_cygwin(client):
     assert not os.path.exists(os.path.join(client.current_folder, "conanrunenv.bat"))
     run_contents = client.load("conanrunenv.sh")
     assert 'export RUNTIME_VAR="/cygdrive/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
diff --git a/conans/test/integration/toolchains/microsoft/test_msbuilddeps.py b/conans/test/integration/toolchains/microsoft/test_msbuilddeps.py
index 55f7f9174..0422276c3 100644
--- a/conans/test/integration/toolchains/microsoft/test_msbuilddeps.py
+++ b/conans/test/integration/toolchains/microsoft/test_msbuilddeps.py
@@ -1,5 +1,6 @@
 import os
 import textwrap
+from xml.dom import minidom
 
 import pytest
 
@@ -30,20 +31,24 @@ def test_msbuilddeps_format_names():
         from conan import ConanFile
         class Pkg(ConanFile):
             settings = "os", "compiler", "build_type", "arch"
-            name = "pkg"
+            name = "pkg.name-more+"
             version = "1.0"
 
             def package_info(self):
                 self.cpp_info.components["libmpdecimal++"].libs = ["libmp++"]
+                self.cpp_info.components["mycomp.some-comp+"].libs = ["mylib"]
+                self.cpp_info.components["libmpdecimal++"].requires = ["mycomp.some-comp+"]
         """)
     c.save({"conanfile.py": conanfile})
     c.run("create . -s arch=x86_64")
     # Issue: https://github.com/conan-io/conan/issues/11822
-    c.run("install pkg/1.0@ -g MSBuildDeps -s build_type=Release -s arch=x86_64")
+    c.run("install pkg.name-more+/1.0@ -g MSBuildDeps -s build_type=Release -s arch=x86_64")
     # Checking that MSBuildDeps builds correctly the XML file
-    props = c.load("conan_pkg_libmpdecimal__.props")
-    assert "<conan_pkg_libmpdecimal___props_imported>" in props
-    props = c.load("conan_pkg_libmpdecimal___release_x64.props")
-    assert "Conanpkg_libmpdecimal__IncludeDirectories" in props
-    props = c.load("conan_pkg_libmpdecimal___vars_release_x64.props")
-    assert "<Conanpkg_libmpdecimal__RootFolder>" in props
+    # loading all .props and xml parse them to check no errors
+    counter = 0
+    for f in os.listdir(c.current_folder):
+        if f.endswith(".props"):
+            content = c.load(f)
+            minidom.parseString(content)
+            counter += 1
+    assert counter == 8