Repository: conan-io/conan
Pull request #10568 (2022-02-14 08:52:59)

test with transitive python_requires_extend
Changelog: Omit
Docs: Omit


Close https://github.com/conan-io/conan/issues/10565

SeanSnyders: Hi @memsharded 

Thank you for the playground recipes to test out this situation.
Your example does indeed work to what one would expect. But there are differences in how you implemented this example and how the Conan documentation suggest extension can be done.
One of the main changes in the documentation from your example here seems to be that the classes being extended does not derive from `ConanFile` itself, and only the final consumer (i.e. 'final') recipe does.

To that end, I had to change your examples a bit to reflect my situation. And through these changes I can exhibit the problem I have that in the `init()` method of the `consumer` recipe, the `python_requires` for `project` is not there where this is defined in the `company.CompanyBase` class.

**`company/conanfile.py`**:
```python
from conans import ConanFile
class CompanyConanFile(ConanFile):
    name = "company"
    version = "1.0"

class CompanyBase(object):

    python_requires = "project/1.0"

    def msg1(self):
        return "company"
    def msg2(self):
        return "company"
```

**`project/conanfile.py`**:
```python
from conans import ConanFile
class ProjectConanFile(ConanFile):
    name = "project"
    version = "1.0"

class ProjectBase(object):
    def msg1(self):
        return "project"
```

**`consumer/conanfile.py`**:
```python
from conans import ConanFile

class ConsumerConanFile(ConanFile):
    name = "consumer"
    version = "1.0"
    python_requires = "company/1.0"
    python_requires_extend = "company.CompanyBase"

    def init(self):
        for (k,v) in self.python_requires.items():
            self.output.info(f"self py_req: {k}")
        # would want to access the transitive python_requires class 'ProjectBase' from project
        project_req_name = 'project'
        #project = self.python_requires[project_req_name].module.ProjectBase()
        #self.output.info(project.msg1())
        try:
            project_req = self.python_requires[project_req_name]
        except KeyError:
            raise ConanException(f"Project requirement with name '{project_req_name}' does not seem to be available. Check correct requirements.")

    def generate(self):
        self.output.info("Msg1:{}!!!".format(self.msg1()))
        self.output.info("Msg2:{}!!!".format(self.msg2()))
```

Running in the folder where these recipes are defined in their respective folders:
`mkdir build && cd build`
and then
`conan export ../company && conan export ../project && conan install ../consumer`

gives me this output:
```
$ conan export ../company && conan export ../project && conan install ../consumer
[HOOK - attribute_checker.py] pre_export(): WARN: Conanfile doesn't have 'url'. It is recommended to add it as attribute
[HOOK - attribute_checker.py] pre_export(): WARN: Conanfile doesn't have 'license'. It is recommended to add it as attribute
[HOOK - attribute_checker.py] pre_export(): WARN: Conanfile doesn't have 'description'. It is recommended to add it as attribute
Exporting package recipe
company/1.0: A new conanfile.py version was exported
company/1.0: Folder: /Users/ssnyder/Development/TmpConanData/company/1.0/_/_/export
company/1.0: Using the exported files summary hash as the recipe revision: 77195e58eb843288a621f5429bac92e4 
company/1.0: Exported revision: 77195e58eb843288a621f5429bac92e4
[HOOK - attribute_checker.py] pre_export(): WARN: Conanfile doesn't have 'url'. It is recommended to add it as attribute
[HOOK - attribute_checker.py] pre_export(): WARN: Conanfile doesn't have 'license'. It is recommended to add it as attribute
[HOOK - attribute_checker.py] pre_export(): WARN: Conanfile doesn't have 'description'. It is recommended to add it as attribute
Exporting package recipe
project/1.0: A new conanfile.py version was exported
project/1.0: Folder: /Users/ssnyder/Development/TmpConanData/project/1.0/_/_/export
project/1.0: Using the exported files summary hash as the recipe revision: d4751f5047891942f354586ee5b34163 
project/1.0: Exported revision: d4751f5047891942f354586ee5b34163
Configuration:
[settings]
arch=x86_64
arch_build=x86_64
build_type=Release
compiler=apple-clang
compiler.libcxx=libc++
compiler.version=12.0
os=Macos
os_build=Macos
[options]
[build_requires]
[env]

: self py_req: company
ERROR: Error loading conanfile at '/Users/ssnyder/Development/Temp/ConanPythonRequires/consumer/conanfile.py': : Error in init() method, line 17
	project_req = self.python_requires[project_req_name]
	ConanException: 'project' is not a python_require
```

memsharded: Sorry for the long wait, this PR was not assigned and got buried in many other notifications.
I have checked your feedback and added a new test with the approach to implement what you are intending to implement.
The keys are:
- The dependency is "consumer"->"project python-require"->"company python_require" (it seems you have reversed in your latest example, I keep this order in mine
- The consumer shouldn't be aware of the transitive dependency, it is not possible to add to every recipe that needs that python_require all that code in the ``init()`` function
- Then, the "project" python-require is the one that should be resolving the transitivity. It is not straightforward Python, but it is possible, as seen in the test.
- The ``python_requires`` must be in the ``ConanFile``, they cannot be in other files and resolved dynamically, as Conan needs to resolve it and that only happens in ``ConanFile``s

In any case, it would be strongly recommended to fully avoid this kind of transitivity, and keep ``python_requires`` completely flat.


```python
    def test_transitive_extend2(self):
        client = TestClient()
        company = textwrap.dedent("""
            from conan import ConanFile
            class CompanyConanFile(ConanFile):
                name = "company"
                version = "1.0"

            class CompanyBase:
                def msg1(self):
                    return "company"
                def msg2(self):
                    return "company"
            """)
        project = textwrap.dedent("""
            from conan import ConanFile
            class ProjectBase:
                def msg1(self):
                    return "project"

            class ProjectBaseConanFile(ConanFile):
                name = "project"
                version = "1.0"
                python_requires = "company/1.0"

                def init(self):
                    pkg_name, base_class_name = "company", "CompanyBase"
                    base_class = getattr(self.python_requires[pkg_name].module, base_class_name)
                    global ProjectBase
                    ProjectBase = type('ProjectBase', (ProjectBase, base_class, object), {})
            """)
        consumer = textwrap.dedent("""
            from conan import ConanFile
            class Base(ConanFile):
                name = "consumer"
                version = "1.0"
                python_requires = "project/1.0"
                python_requires_extend = "project.ProjectBase"
                def generate(self):
                    self.output.info("Msg1:{}!!!".format(self.msg1()))
                    self.output.info("Msg2:{}!!!".format(self.msg2()))
                """)
        client.save({"company/conanfile.py": company,
                     "project/conanfile.py": project,
                     "consumer/conanfile.py": consumer})
        client.run("export company")
        client.run("export project")
        client.run("install consumer")
        assert "conanfile.py (consumer/1.0): Msg1:project!!!" in client.out
        assert "conanfile.py (consumer/1.0): Msg2:company!!!" in client.out
```

Patch:
diff --git a/conan/tools/_compilers.py b/conan/tools/_compilers.py
index a4f6f9da2..fb976a469 100644
--- a/conan/tools/_compilers.py
+++ b/conan/tools/_compilers.py
@@ -398,6 +398,10 @@ def _cppstd_gcc(gcc_version, cppstd):
         v23 = "c++2b"
         vgnu23 = "gnu++2b"
 
+    if Version(gcc_version) >= "12":
+        v20 = "c++20"
+        vgnu20 = "gnu++20"
+
     flag = {"98": v98, "gnu98": vgnu98,
             "11": v11, "gnu11": vgnu11,
             "14": v14, "gnu14": vgnu14,
diff --git a/conan/tools/apple/xcodedeps.py b/conan/tools/apple/xcodedeps.py
index fb79a0259..f4b6d9209 100644
--- a/conan/tools/apple/xcodedeps.py
+++ b/conan/tools/apple/xcodedeps.py
@@ -130,6 +130,7 @@ class XcodeDeps(object):
             merged = [var for cpp_info in transitive_cpp_infos for var in getattr(cpp_info, name)]
             return list(OrderedDict.fromkeys(merged).keys())
 
+        # TODO: Investigate if paths can be made relative to "root" folder
         fields = {
             'pkg_name': pkg_name,
             'comp_name': comp_name,
@@ -270,8 +271,10 @@ class XcodeDeps(object):
                     transitive_internal = list(OrderedDict.fromkeys(transitive_internal).keys())
                     transitive_external = list(OrderedDict.fromkeys(transitive_external).keys())
 
+                    # In case dep is editable and package_folder=None
+                    pkg_folder = dep.package_folder or dep.recipe_folder
                     component_content = self.get_content_for_component(dep_name, comp_name,
-                                                                       dep.package_folder,
+                                                                       pkg_folder,
                                                                        transitive_internal,
                                                                        transitive_external)
                     include_components_names.append((dep_name, comp_name))
@@ -289,7 +292,9 @@ 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.package_folder, [dep.cpp_info],
+                # In case dep is editable and package_folder=None
+                pkg_folder = dep.package_folder or dep.recipe_folder
+                root_content = self.get_content_for_component(dep_name, dep_name, pkg_folder, [dep.cpp_info],
                                                               required_components)
                 include_components_names.append((dep_name, dep_name))
                 result.update(root_content)
diff --git a/conan/tools/cmake/cmakedeps/cmakedeps.py b/conan/tools/cmake/cmakedeps/cmakedeps.py
index 1a873729a..47647a715 100644
--- a/conan/tools/cmake/cmakedeps/cmakedeps.py
+++ b/conan/tools/cmake/cmakedeps/cmakedeps.py
@@ -17,6 +17,7 @@ class CMakeDeps(object):
 
     def __init__(self, conanfile):
         self._conanfile = conanfile
+        self._conanfile.must_use_new_helpers = True  # TODO: Remove 2.0
         self.arch = self._conanfile.settings.get_safe("arch")
         self.configuration = str(self._conanfile.settings.build_type)
 
diff --git a/conan/tools/cmake/layout.py b/conan/tools/cmake/layout.py
index f39ef6974..abddc047f 100644
--- a/conan/tools/cmake/layout.py
+++ b/conan/tools/cmake/layout.py
@@ -22,20 +22,21 @@ def cmake_layout(conanfile, generator=None, src_folder=".", build_folder="build"
         raise ConanException("'build_type' setting not defined, it is necessary for cmake_layout()")
 
     build_folder = build_folder if not subproject else os.path.join(subproject, build_folder)
-    custom_conf = get_build_folder_custom_vars(conanfile)
-    if custom_conf:
-        build_folder = os.path.join(build_folder, custom_conf)
+    config_build_folder, user_defined_build = get_build_folder_custom_vars(conanfile)
 
-    if multi:
-        conanfile.folders.build = build_folder
+    if config_build_folder:
+        conanfile.folders.build = os.path.join(build_folder, config_build_folder)
     else:
-        conanfile.folders.build = os.path.join(build_folder, build_type)
+        if not multi and not user_defined_build:
+            conanfile.folders.build = os.path.join(build_folder, build_type)
+        else:
+            conanfile.folders.build = build_folder
 
-    conanfile.folders.generators = os.path.join(build_folder, "generators")
+    conanfile.folders.generators = os.path.join(conanfile.folders.build, "generators")
 
     conanfile.cpp.source.includedirs = ["include"]
 
-    if multi:
+    if multi and not user_defined_build:
         conanfile.cpp.build.libdirs = ["{}".format(build_type)]
         conanfile.cpp.build.bindirs = ["{}".format(build_type)]
     else:
@@ -49,17 +50,11 @@ def get_build_folder_custom_vars(conanfile):
                                     default=[], check_type=list)
     ret = []
     for s in build_vars:
+        group, var = s.split(".", 1)
         tmp = None
-        if s.startswith("settings."):
-            _, var = s.split("settings.", 1)
-            if var == "build_type":
-                raise ConanException("Error, don't include 'settings.build_type' in the "
-                                     "'tools.cmake.cmake_layout:build_folder_vars' conf. It is "
-                                     "managed by default because 'CMakeToolchain' and 'CMakeDeps' "
-                                     "are multi-config generators.`")
+        if group == "settings":
             tmp = conanfile.settings.get_safe(var)
-        elif s.startswith("options."):
-            _, var = s.split("options.", 1)
+        elif group == "options":
             value = conanfile.options.get_safe(var)
             if value is not None:
                 tmp = "{}_{}".format(var, value)
@@ -69,4 +64,5 @@ def get_build_folder_custom_vars(conanfile):
         if tmp:
             ret.append(tmp.lower())
 
-    return "-".join(ret)
+    user_defined_build = "settings.build_type" in build_vars
+    return "-".join(ret), user_defined_build
diff --git a/conan/tools/cmake/presets.py b/conan/tools/cmake/presets.py
index 6d4a9a735..dacf021ef 100644
--- a/conan/tools/cmake/presets.py
+++ b/conan/tools/cmake/presets.py
@@ -21,7 +21,10 @@ def _build_preset(conanfile, multiconfig):
 
 def _build_preset_name(conanfile):
     build_type = conanfile.settings.get_safe("build_type")
-    custom_conf = get_build_folder_custom_vars(conanfile)
+    custom_conf, user_defined_build = get_build_folder_custom_vars(conanfile)
+    if user_defined_build:
+        return custom_conf
+
     if custom_conf:
         if build_type:
             return "{}-{}".format(custom_conf, build_type.lower())
@@ -32,7 +35,10 @@ def _build_preset_name(conanfile):
 
 def _configure_preset_name(conanfile, multiconfig):
     build_type = conanfile.settings.get_safe("build_type")
-    custom_conf = get_build_folder_custom_vars(conanfile)
+    custom_conf, user_defined_build = get_build_folder_custom_vars(conanfile)
+
+    if user_defined_build:
+        return custom_conf
 
     if multiconfig or not build_type:
         return "default" if not custom_conf else custom_conf
diff --git a/conan/tools/cmake/toolchain/toolchain.py b/conan/tools/cmake/toolchain/toolchain.py
index cd54a9a87..2a0e181f8 100644
--- a/conan/tools/cmake/toolchain/toolchain.py
+++ b/conan/tools/cmake/toolchain/toolchain.py
@@ -118,6 +118,7 @@ class CMakeToolchain(object):
 
     def __init__(self, conanfile, generator=None):
         self._conanfile = conanfile
+        self._conanfile.must_use_new_helpers = True  # TODO: Remove 2.0
         self.generator = self._get_generator(generator)
         self.variables = Variables()
         # This doesn't support multi-config, they go to the same configPreset common in multi-config
diff --git a/conan/tools/microsoft/msbuilddeps.py b/conan/tools/microsoft/msbuilddeps.py
index 2053d38a0..8e0ab92dc 100644
--- a/conan/tools/microsoft/msbuilddeps.py
+++ b/conan/tools/microsoft/msbuilddeps.py
@@ -90,6 +90,7 @@ class MSBuildDeps(object):
 
     def __init__(self, conanfile):
         self._conanfile = conanfile
+        self._conanfile.must_use_new_helpers = True  # TODO: Remove 2.0
         self.configuration = conanfile.settings.build_type
         # TODO: This platform is not exactly the same as ``msbuild_arch``, because it differs
         # in x86=>Win32
diff --git a/conan/tools/microsoft/toolchain.py b/conan/tools/microsoft/toolchain.py
index 2b9c4686b..b98f6be45 100644
--- a/conan/tools/microsoft/toolchain.py
+++ b/conan/tools/microsoft/toolchain.py
@@ -45,6 +45,7 @@ class MSBuildToolchain(object):
 
     def __init__(self, conanfile):
         self._conanfile = conanfile
+        self._conanfile.must_use_new_helpers = True  # TODO: Remove 2.0
         self.preprocessor_definitions = {}
         self.compile_options = {}
         self.cxxflags = []
diff --git a/conans/client/build/cmake.py b/conans/client/build/cmake.py
index acaeffb3c..0006d8622 100644
--- a/conans/client/build/cmake.py
+++ b/conans/client/build/cmake.py
@@ -46,6 +46,9 @@ class CMake(object):
         :param cmake_program: Path to the custom cmake executable
         :param generator_platform: Generator platform name or none to autodetect (-A cmake option)
         """
+        if getattr(conanfile, "must_use_new_helpers", None):
+            raise ConanException("Using the wrong 'CMake' helper. To use CMakeDeps, CMakeToolchain "
+                                 "you should use 'from conan.tools.cmake import CMake'")
         self._append_vcvars = append_vcvars
         self._conanfile = conanfile
         self._settings = conanfile.settings
diff --git a/conans/client/build/msbuild.py b/conans/client/build/msbuild.py
index da88f0703..778b81a76 100644
--- a/conans/client/build/msbuild.py
+++ b/conans/client/build/msbuild.py
@@ -22,6 +22,10 @@ class MSBuild(object):
 
     def __init__(self, conanfile):
         if isinstance(conanfile, ConanFile):
+            if getattr(conanfile, "must_use_new_helpers", None):
+                raise ConanException(
+                    "Using the wrong 'MSBuild' helper. To use MSBuildDeps, MSBuildToolchain "
+                    "you should use 'from conan.tools.microsoft import MSBuild'")
             self._conanfile = conanfile
             self._settings = self._conanfile.settings
             self._output = self._conanfile.output


Test patch:
diff --git a/conans/test/functional/layout/test_build_system_layout_helpers.py b/conans/test/functional/layout/test_build_system_layout_helpers.py
index 4bd7c8cd4..c683114b8 100644
--- a/conans/test/functional/layout/test_build_system_layout_helpers.py
+++ b/conans/test/functional/layout/test_build_system_layout_helpers.py
@@ -168,7 +168,8 @@ def test_cmake_layout_external_sources():
 
     # Local flow
     client.run("install . foo/1.0 -s os=Linux")
-    assert os.path.exists(os.path.join(client.current_folder, "build", "generators", "generate.txt"))
+    assert os.path.exists(os.path.join(client.current_folder,
+                                       "build", "Release", "generators", "generate.txt"))
     client.run("source .")
     assert os.path.exists(os.path.join(client.current_folder, "src", "source.txt"))
     client.run("build .")
@@ -294,4 +295,4 @@ def test_cmake_layout_custom_build_folder():
     client.save({"conanfile.py": conanfile})
     client.run("install .")
     assert os.path.exists(os.path.join(client.current_folder,
-                                       "mybuild/generators/conan_toolchain.cmake"))
+                                       "mybuild/Release/generators/conan_toolchain.cmake"))
diff --git a/conans/test/functional/layout/test_local_commands.py b/conans/test/functional/layout/test_local_commands.py
index bd036d617..0c07d5cdd 100644
--- a/conans/test/functional/layout/test_local_commands.py
+++ b/conans/test/functional/layout/test_local_commands.py
@@ -372,7 +372,11 @@ def test_start_dir_failure():
     c = TestClient()
     c.save(pkg_cmake("dep", "0.1"))
     c.run("install .")
-    expected_path = os.path.join(c.current_folder, "build", "generators", "conan_toolchain.cmake")
+    if platform.system() != "Windows":
+        gen_folder = os.path.join(c.current_folder, "build", "Release", "generators")
+    else:
+        gen_folder = os.path.join(c.current_folder, "build", "generators")
+    expected_path = os.path.join(gen_folder, "conan_toolchain.cmake")
     assert os.path.exists(expected_path)
     os.unlink(expected_path)
     with c.chdir("build"):
diff --git a/conans/test/functional/toolchains/cmake/cmakedeps/test_apple_frameworks.py b/conans/test/functional/toolchains/cmake/cmakedeps/test_apple_frameworks.py
index 33cb47b03..7dbc10bbf 100644
--- a/conans/test/functional/toolchains/cmake/cmakedeps/test_apple_frameworks.py
+++ b/conans/test/functional/toolchains/cmake/cmakedeps/test_apple_frameworks.py
@@ -348,7 +348,8 @@ def test_apple_own_framework_cmake_find_package_multi():
 @pytest.mark.skipif(platform.system() != "Darwin", reason="Only OSX")
 def test_component_uses_apple_framework():
     conanfile_py = textwrap.dedent("""
-from conans import ConanFile, CMake, tools
+from conans import ConanFile, tools
+from conan.tools.cmake import CMake
 
 
 class HelloConan(ConanFile):
@@ -406,7 +407,8 @@ install(TARGETS ${PROJECT_NAME}
         """)
     test_conanfile_py = textwrap.dedent("""
 import os
-from conans import ConanFile, CMake, tools
+from conans import ConanFile, tools
+from conan.tools.cmake import CMake
 
 class TestPackageConan(ConanFile):
     settings = "os", "compiler", "build_type", "arch"
diff --git a/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps.py b/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps.py
index 45b5d1d97..c1ceb5d3a 100644
--- a/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps.py
+++ b/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps.py
@@ -497,7 +497,7 @@ def test_system_dep():
     files = pkg_cmake("mylib", "0.1", requires=["zlib/0.1"])
     files["CMakeLists.txt"] = files["CMakeLists.txt"].replace("find_package(zlib)",
                                                               "find_package(ZLIB)")
-    files["CMakeLists.txt"] = files["CMakeLists.txt"].replace("zlib::zlib","ZLIB::ZLIB")
+    files["CMakeLists.txt"] = files["CMakeLists.txt"].replace("zlib::zlib", "ZLIB::ZLIB")
     client.save({os.path.join("mylib", name): content for name, content in files.items()})
     files = pkg_cmake("consumer", "0.1", requires=["mylib/0.1"])
     client.save({os.path.join("consumer", name): content for name, content in files.items()})
@@ -509,7 +509,7 @@ def test_system_dep():
     client.run("install consumer")
     if platform.system() != "Windows":
         host_arch = client.get_default_host_profile().settings['arch']
-        data = os.path.join(f"consumer/build/generators/mylib-release-{host_arch}-data.cmake")
+        data = f"consumer/build/Release/generators/mylib-release-{host_arch}-data.cmake"
         contents = client.load(data)
         assert 'set(ZLIB_FIND_MODE "")' in contents
 
diff --git a/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_and_linker_flags.py b/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_and_linker_flags.py
index e03007054..06c6d1943 100644
--- a/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_and_linker_flags.py
+++ b/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_and_linker_flags.py
@@ -52,7 +52,8 @@ def test_shared_link_flags():
     client.run("new hello/1.0 -m cmake_lib")
     client.save({"conanfile.py": conanfile})
     client.run("create .")
-    t = os.path.join("test_package", "build", "generators", "hello-release-x86_64-data.cmake")
+    t = os.path.join("test_package", "build", "Release",
+                     "generators", "hello-release-x86_64-data.cmake")
     target_data_cmake_content = client.load(t)
     assert 'set(hello_SHARED_LINK_FLAGS_RELEASE "-z now;-z relro")' in target_data_cmake_content
     assert 'set(hello_EXE_LINK_FLAGS_RELEASE "-z now;-z relro")' in target_data_cmake_content
diff --git a/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_build_modules.py b/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_build_modules.py
index 3566bfade..ae6a392b3 100644
--- a/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_build_modules.py
+++ b/conans/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_build_modules.py
@@ -34,7 +34,8 @@ def test_build_modules_alias_target():
     client.run("create .")
 
     consumer = textwrap.dedent("""
-        from conans import ConanFile, CMake
+        from conans import ConanFile
+        from conan.tools.cmake import CMake
 
         class Conan(ConanFile):
             name = "consumer"
@@ -103,7 +104,8 @@ def test_build_modules_components_is_not_possible():
     client.run("create .")
 
     consumer = textwrap.dedent("""
-        from conans import ConanFile, CMake
+        from conans import ConanFile
+        from conan.tools.cmake import CMake
 
         class Conan(ConanFile):
             name = "consumer"
diff --git a/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py b/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py
index 49f73cf5a..dbd70681e 100644
--- a/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py
+++ b/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py
@@ -297,8 +297,14 @@ def test_install_output_directories():
     p_folder = client.cache.package_layout(pref.ref).package(pref)
     assert os.path.exists(os.path.join(p_folder, "mylibs"))
     assert not os.path.exists(os.path.join(p_folder, "lib"))
+
     b_folder = client.cache.package_layout(pref.ref).build(pref)
-    toolchain = client.load(os.path.join(b_folder, "build", "generators", "conan_toolchain.cmake"))
+    if platform.system() != "Windows":
+        gen_folder = os.path.join(b_folder, "build", "Release", "generators")
+    else:
+        gen_folder = os.path.join(b_folder, "build", "generators")
+
+    toolchain = client.load(os.path.join(gen_folder, "conan_toolchain.cmake"))
     assert 'set(CMAKE_INSTALL_LIBDIR "mylibs")' in toolchain
 
 
@@ -962,15 +968,15 @@ def test_cmake_presets_with_conanfile_txt():
     assert "Hello World Release!" in c.out
 
 
-def test_cmake_presets_forbidden_build_type():
+def test_cmake_presets_not_forbidden_build_type():
     client = TestClient(path_with_spaces=False)
     client.run("new hello/0.1 --template cmake_exe")
     # client.run("new cmake_exe -d name=hello -d version=0.1")
     settings_layout = '-c tools.cmake.cmake_layout:build_folder_vars=' \
                       '\'["options.missing", "settings.build_type"]\''
-    client.run("install . {}".format(settings_layout), assert_error=True)
-    assert "Error, don't include 'settings.build_type' in the " \
-           "'tools.cmake.cmake_layout:build_folder_vars' conf" in client.out
+    client.run("install . {}".format(settings_layout))
+    assert os.path.exists(os.path.join(client.current_folder,
+                                       "build/release/generators/conan_toolchain.cmake"))
 
 
 def test_resdirs_cmake_install():
@@ -1116,7 +1122,8 @@ def test_cmake_toolchain_vars_when_option_declared():
     # the CMakeLists
     fpic_option = "-o mylib:fPIC=False" if platform.system() != "Windows" else ""
     t.run(f"install . -o mylib:shared=False {fpic_option}")
-    t.run_command("cmake -S . -B build/ -DCMAKE_TOOLCHAIN_FILE=build/generators/conan_toolchain.cmake")
+    folder = "build/generators" if platform.system() == "Windows" else "build/Release/generators"
+    t.run_command(f"cmake -S . -B build/ -DCMAKE_TOOLCHAIN_FILE={folder}/conan_toolchain.cmake")
     assert "mylib target type: STATIC_LIBRARY" in t.out
     assert f"mylib position independent code: OFF" in t.out
 
@@ -1185,8 +1192,6 @@ def test_find_program_for_tool_requires():
                 "build_profile": build_profile
                 })
 
-    xxx = client.get_default_build_profile()
-
     client.run("create . -pr:b build_profile -pr:h build_profile")
     client.run("create . -pr:b build_profile -pr:h host_profile")
 
@@ -1226,7 +1231,7 @@ def test_find_program_for_tool_requires():
     host_context_package_id = "bf544cd3bc20b82121fd76b82eacbb36d75fa167"
 
     with client.chdir("build"):
-        client.run_command("cmake .. -DCMAKE_TOOLCHAIN_FILE=generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release")
+        client.run_command("cmake .. -DCMAKE_TOOLCHAIN_FILE=Release/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release")
         # Verify binary executable is found from build context package,
         # and library comes from host context package
         assert f"package/{build_context_package_id}/bin/foobin" in client.out
diff --git a/conans/test/functional/toolchains/cmake/test_cmake_toolchain_xcode_flags.py b/conans/test/functional/toolchains/cmake/test_cmake_toolchain_xcode_flags.py
index 30b5622b2..f108945ef 100644
--- a/conans/test/functional/toolchains/cmake/test_cmake_toolchain_xcode_flags.py
+++ b/conans/test/functional/toolchains/cmake/test_cmake_toolchain_xcode_flags.py
@@ -38,7 +38,7 @@ def test_cmake_apple_bitcode_arc_and_visibility_flags_enabled(op_system, os_vers
     client.run("new hello/0.1 --template=cmake_lib")
     _add_message_status_flags(client)
     client.run("install . --profile:build=default --profile:host=host")
-    toolchain = client.load(os.path.join("build", "generators", "conan_toolchain.cmake"))
+    toolchain = client.load(os.path.join("build", "Release", "generators", "conan_toolchain.cmake"))
     # bitcode
     assert 'set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "YES")' in toolchain
     assert 'set(CMAKE_XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE "bitcode")' in toolchain
@@ -121,7 +121,7 @@ def test_cmake_apple_bitcode_arc_and_visibility_flags_disabled(op_system, os_ver
     client.run("new hello/0.1 --template=cmake_lib")
     _add_message_status_flags(client)
     client.run("install . --profile:build=default --profile:host=host")
-    toolchain = client.load(os.path.join("build", "generators", "conan_toolchain.cmake"))
+    toolchain = client.load(os.path.join("build", "Release", "generators", "conan_toolchain.cmake"))
     # bitcode
     assert 'set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "NO")' in toolchain
     assert 'set(CMAKE_XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE "bitcode")' not in toolchain
@@ -163,7 +163,7 @@ def test_cmake_apple_bitcode_arc_and_visibility_flags_are_none(op_system, os_ver
     client.run("new hello/0.1 --template=cmake_lib")
     _add_message_status_flags(client)
     client.run("install . --profile:build=default --profile:host=host")
-    toolchain = client.load(os.path.join("build", "generators", "conan_toolchain.cmake"))
+    toolchain = client.load(os.path.join("build", "Release", "generators", "conan_toolchain.cmake"))
     # bitcode
     assert 'set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "NO")' not in toolchain
     assert 'set(CMAKE_XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE "bitcode")' not in toolchain
diff --git a/conans/test/integration/command/info/info_test.py b/conans/test/integration/command/info/info_test.py
index 2c5faafa8..a5992a4c6 100644
--- a/conans/test/integration/command/info/info_test.py
+++ b/conans/test/integration/command/info/info_test.py
@@ -747,3 +747,26 @@ class HelloConan(ConanFile):
             client.run("info . " + args)
             assert "AttributeError: 'HelloConan' object has no attribute 'tested_reference_str'"\
                    not in client.out
+
+
+def test_info_not_hit_server():
+    c = TestClient(default_server_user=True)
+    c.save({"pkg/conanfile.py": GenConanfile("pkg", "0.1"),
+            "consumer/conanfile.py": GenConanfile("consumer", "0.1").with_require("pkg/0.1")})
+    c.run("create pkg")
+    c.run("create consumer")
+    c.run("upload * -r=default --all -c")
+    c.run("remove * -f")
+    c.run("install consumer/0.1@")
+    assert "Downloaded" in c.out
+    # break the server to make sure it is not being contacted at all
+    c.servers["default"] = None
+    c.run("info consumer/0.1@")
+    assert "Downloaded" not in c.out
+    c.run("remove pkg* -f")
+    c.run("info consumer/0.1@", assert_error=True)
+    assert "ERROR: 'NoneType' object " in c.out
+    c.run("remote disable *")
+    c.run("info consumer/0.1@", assert_error=True)
+    assert "ERROR: 'NoneType' object " not in c.out
+    assert "ERROR: No remote defined" in c.out
diff --git a/conans/test/integration/configuration/conf/test_conf_profile.py b/conans/test/integration/configuration/conf/test_conf_profile.py
index c2c208665..0f55ad7eb 100644
--- a/conans/test/integration/configuration/conf/test_conf_profile.py
+++ b/conans/test/integration/configuration/conf/test_conf_profile.py
@@ -164,3 +164,36 @@ def test_msbuild_compile_options():
     client.run("install . -pr=myprofile")
     msbuild_tool = client.load("conantoolchain_release_x64.props")
     assert "<ExceptionHandling>Async</ExceptionHandling>" in msbuild_tool
+
+
+def test_config_package_append(client):
+    profile1 = textwrap.dedent("""\
+        [conf]
+        user.myteam:myconf=["a", "b", "c"]
+        """)
+    profile2 = textwrap.dedent("""\
+        include(profile1)
+        [conf]
+        mypkg*:user.myteam:myconf+=["d"]
+        mydep*:user.myteam:myconf=+["e"]
+        """)
+    conanfile = textwrap.dedent("""
+        from conan import ConanFile
+        class Pkg(ConanFile):
+            def generate(self):
+                self.output.info(f"MYCONF: {self.conf.get('user.myteam:myconf')}")
+            def build(self):
+                self.output.info(f"MYCONFBUILD: {self.conf.get('user.myteam:myconf')}")
+            """)
+    client.save({"profile1": profile1,
+                 "profile2": profile2,
+                 "conanfile.py": conanfile})
+    client.run("install . mypkg/0.1@ -pr=profile2")
+    assert "conanfile.py (mypkg/0.1): MYCONF: ['a', 'b', 'c', 'd']" in client.out
+    client.run("install . mydep/0.1@ -pr=profile2")
+    assert "conanfile.py (mydep/0.1): MYCONF: ['e', 'a', 'b', 'c']" in client.out
+
+    client.run("create . mypkg/0.1@ -pr=profile2")
+    assert "mypkg/0.1: MYCONFBUILD: ['a', 'b', 'c', 'd']" in client.out
+    client.run("create . mydep/0.1@ -pr=profile2")
+    assert "mydep/0.1: MYCONFBUILD: ['e', 'a', 'b', 'c']" in client.out
diff --git a/conans/test/integration/graph/version_ranges/version_range_override_test.py b/conans/test/integration/graph/version_ranges/version_range_override_test.py
index c861a3992..0a23c78b3 100644
--- a/conans/test/integration/graph/version_ranges/version_range_override_test.py
+++ b/conans/test/integration/graph/version_ranges/version_range_override_test.py
@@ -90,3 +90,45 @@ class VersionRangeOverrideFailTestCase(unittest.TestCase):
         lock = t.load("conan.lock")
         self.assertIn("gtest/1.8.1@bloomberg/stable", lock)
         self.assertNotIn("gtest/1.8.0@PORT/stable", lock)
+
+    def test_override(self):
+        """
+        pkga -> ros_perception  -> ros_core
+           \\-----> pkgb  -----------/
+        """
+        # https://github.com/conan-io/conan/issues/8071
+        t = TestClient()
+        t.save({"conanfile.py": GenConanfile()})
+        t.run("create . ros_core/1.1.4@3rdparty/unstable")
+        t.run("create . ros_core/PR-53@3rdparty/snapshot")
+        t.save({"conanfile.py": GenConanfile().with_requires("ros_core/1.1.4@3rdparty/unstable")})
+        t.run("create . ros_perception/1.1.4@3rdparty/unstable")
+        t.run("create . ros_perception/PR-53@3rdparty/snapshot")
+        t.save({"conanfile.py": GenConanfile().with_requires("ros_core/[~=1.1]@3rdparty/unstable")})
+        t.run("create . pkgb/0.1@common/unstable")
+        t.save({"conanfile.py": GenConanfile("pkga", "0.1").with_requires(
+            "ros_perception/[~=1.1]@3rdparty/unstable",
+            "pkgb/[~=0]@common/unstable")})
+        t.run("create . ")
+        self.assertIn("ros_core/1.1.4@3rdparty/unstable", t.out)
+        self.assertIn("ros_perception/1.1.4@3rdparty/unstable", t.out)
+        self.assertNotIn("snapshot", t.out)
+
+        t.save({"conanfile.py": GenConanfile("pkga", "0.1")
+               .with_require("pkgb/[~=0]@common/unstable")
+               .with_require("ros_perception/PR-53@3rdparty/snapshot")
+               .with_require("ros_core/PR-53@3rdparty/snapshot", override=True)})
+
+        t.run("create .  --build=missing --build=pkga")
+        self.assertIn("ros_core/PR-53@3rdparty/snapshot", t.out)
+        self.assertIn("ros_perception/PR-53@3rdparty/snapshot", t.out)
+
+        # Override only the upstream without overriding the direct one
+        t.save({"conanfile.py": GenConanfile("pkga", "0.1")
+               .with_require("pkgb/[~=0]@common/unstable")
+               .with_require("ros_perception/[~=1.1]@3rdparty/unstable")
+               .with_require("ros_core/PR-53@3rdparty/snapshot", override=True)})
+
+        t.run("create .  --build=missing --build=pkga")
+        self.assertIn("ros_core/PR-53@3rdparty/snapshot", t.out)
+        self.assertIn("ros_perception/1.1.4@3rdparty/unstable", t.out)
diff --git a/conans/test/integration/layout/test_layout_paths.py b/conans/test/integration/layout/test_layout_paths.py
index 5d863f411..5049ac534 100644
--- a/conans/test/integration/layout/test_layout_paths.py
+++ b/conans/test/integration/layout/test_layout_paths.py
@@ -1,3 +1,4 @@
+import os
 import textwrap
 
 from conans.test.assets.genconanfile import GenConanfile
@@ -6,6 +7,7 @@ from conans.test.utils.tools import TestClient
 
 def test_editable_layout_paths():
     # https://github.com/conan-io/conan/issues/12521
+    # https://github.com/conan-io/conan/issues/12839
     c = TestClient()
     dep = textwrap.dedent("""
         import os
@@ -21,13 +23,16 @@ def test_editable_layout_paths():
             "pkg/conanfile.py": GenConanfile("pkg", "0.1").with_settings("build_type", "arch")
                                                           .with_requires("dep/0.1")
                                                           .with_generator("CMakeDeps")
-                                                          .with_generator("PkgConfigDeps")})
+                                                          .with_generator("PkgConfigDeps")
+                                                          .with_generator("XcodeDeps")})
     c.run("editable add dep dep/0.1")
-    c.run("install pkg")
+    c.run("install pkg -s arch=x86_64")
     # It doesn't crash anymore
     assert "dep/0.1:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9 - Editable" in c.out
-    arch = c.get_default_host_profile().settings['arch']
-    data = c.load(f"dep-release-{arch}-data.cmake")
+    data = c.load(f"dep-release-x86_64-data.cmake")
     assert 'set(dep_INCLUDE_DIRS_RELEASE "${dep_PACKAGE_FOLDER_RELEASE}/include")' in data
     pc = c.load("dep.pc")
     assert "includedir1=${prefix}/include" in pc
+    xcode = c.load("conan_dep_dep_release_x86_64.xcconfig")
+    dep_path = os.path.join(c.current_folder, "dep")
+    assert f"PACKAGE_ROOT_dep[config=Release][arch=x86_64][sdk=*] = {dep_path}" in xcode
diff --git a/conans/test/integration/py_requires/python_requires_test.py b/conans/test/integration/py_requires/python_requires_test.py
index c2d5bab40..174f92ad1 100644
--- a/conans/test/integration/py_requires/python_requires_test.py
+++ b/conans/test/integration/py_requires/python_requires_test.py
@@ -1020,3 +1020,103 @@ def test_multiple_reuse():
     c.run("install consumer")
     assert "VALUE COMMON: 42!!!" in c.out
     assert "VALUE TOOL: 42!!!" in c.out
+
+
+class TestTransitiveExtend:
+    # https://github.com/conan-io/conan/issues/10511
+    # https://github.com/conan-io/conan/issues/10565
+    def test_transitive_extend(self):
+        client = TestClient()
+        company = textwrap.dedent("""
+            from conan import ConanFile
+            class CompanyConanFile(ConanFile):
+                name = "company"
+                version = "1.0"
+
+                def msg1(self):
+                    return "company"
+                def msg2(self):
+                    return "company"
+            """)
+        project = textwrap.dedent("""
+            from conan import ConanFile
+            class ProjectBaseConanFile(ConanFile):
+                name = "project"
+                version = "1.0"
+
+                python_requires = "company/1.0"
+                python_requires_extend = "company.CompanyConanFile"
+
+                def msg1(self):
+                    return "project"
+            """)
+        consumer = textwrap.dedent("""
+            from conan import ConanFile
+            class Base(ConanFile):
+                name = "consumer"
+                version = "1.0"
+                python_requires = "project/1.0"
+                python_requires_extend = "project.ProjectBaseConanFile"
+                def generate(self):
+                    self.output.info("Msg1:{}!!!".format(self.msg1()))
+                    self.output.info("Msg2:{}!!!".format(self.msg2()))
+                """)
+        client.save({"company/conanfile.py": company,
+                     "project/conanfile.py": project,
+                     "consumer/conanfile.py": consumer})
+        client.run("export company")
+        client.run("export project")
+        client.run("install consumer")
+        assert "conanfile.py (consumer/1.0): Msg1:project!!!" in client.out
+        assert "conanfile.py (consumer/1.0): Msg2:company!!!" in client.out
+
+    def test_transitive_extend2(self):
+        client = TestClient()
+        company = textwrap.dedent("""
+            from conan import ConanFile
+            class CompanyConanFile(ConanFile):
+                name = "company"
+                version = "1.0"
+
+            class CompanyBase:
+                def msg1(self):
+                    return "company"
+                def msg2(self):
+                    return "company"
+            """)
+        project = textwrap.dedent("""
+            from conan import ConanFile
+            class ProjectBase:
+                def msg1(self):
+                    return "project"
+
+            class ProjectBaseConanFile(ConanFile):
+                name = "project"
+                version = "1.0"
+                python_requires = "company/1.0"
+
+                def init(self):
+                    pkg_name, base_class_name = "company", "CompanyBase"
+                    base_class = getattr(self.python_requires[pkg_name].module, base_class_name)
+                    global ProjectBase
+                    ProjectBase = type('ProjectBase', (ProjectBase, base_class, object), {})
+            """)
+        consumer = textwrap.dedent("""
+            from conan import ConanFile
+            class Base(ConanFile):
+                name = "consumer"
+                version = "1.0"
+                python_requires = "project/1.0"
+                python_requires_extend = "project.ProjectBase"
+                def generate(self):
+                    self.output.info("Msg1:{}!!!".format(self.msg1()))
+                    self.output.info("Msg2:{}!!!".format(self.msg2()))
+                """)
+        client.save({"company/conanfile.py": company,
+                     "project/conanfile.py": project,
+                     "consumer/conanfile.py": consumer})
+        client.run("export company")
+        client.run("export project")
+        client.run("install consumer")
+        assert "conanfile.py (consumer/1.0): Msg1:project!!!" in client.out
+        assert "conanfile.py (consumer/1.0): Msg2:company!!!" in client.out
diff --git a/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py b/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
index 6d3e9b57d..b3da541f9 100644
--- a/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
+++ b/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
@@ -1,4 +1,5 @@
 import os
+import platform
 import textwrap
 
 from conans.test.assets.genconanfile import GenConanfile
@@ -225,9 +226,14 @@ def test_dependency_props_from_consumer():
 
     client.save({"foo.py": foo.format(set_find_mode=""), "bar.py": bar}, clean_first=True)
 
-    module_file = os.path.join(client.current_folder, "build", "generators", "module-custom_bar_module_file_nameTargets.cmake")
-    components_module = os.path.join(client.current_folder, "build", "generators", "custom_bar_file_name-Target-release.cmake")
-    config_file = os.path.join(client.current_folder, "build", "generators", "custom_bar_file_nameTargets.cmake")
+    if platform.system() != "Windows":
+        gen_folder = os.path.join(client.current_folder, "build", "Release", "generators")
+    else:
+        gen_folder = os.path.join(client.current_folder, "build", "generators")
+
+    module_file = os.path.join(gen_folder, "module-custom_bar_module_file_nameTargets.cmake")
+    components_module = os.path.join(gen_folder, "custom_bar_file_name-Target-release.cmake")
+    config_file = os.path.join(gen_folder, "custom_bar_file_nameTargets.cmake")
 
     # uses cmake_find_mode set in bar: both
     client.run("create bar.py bar/1.0@")
@@ -311,19 +317,20 @@ def test_props_from_consumer_build_context_activated():
 
     client.save({"foo.py": foo.format(set_find_mode=""), "bar.py": bar}, clean_first=True)
 
-    module_file = os.path.join(client.current_folder, "build", "generators",
-                               "module-custom_bar_module_file_nameTargets.cmake")
-    components_module = os.path.join(client.current_folder, "build", "generators",
-                                     "custom_bar_file_name-Target-release.cmake")
-    config_file = os.path.join(client.current_folder, "build", "generators",
-                               "custom_bar_file_nameTargets.cmake")
+    if platform.system() != "Windows":
+        gen_folder = os.path.join(client.current_folder, "build", "Release", "generators")
+    else:
+        gen_folder = os.path.join(client.current_folder, "build", "generators")
+
+    module_file = os.path.join(gen_folder, "module-custom_bar_module_file_nameTargets.cmake")
+    components_module = os.path.join(gen_folder, "custom_bar_file_name-Target-release.cmake")
+    config_file = os.path.join(gen_folder, "custom_bar_file_nameTargets.cmake")
 
-    module_file_build = os.path.join(client.current_folder, "build", "generators",
+    module_file_build = os.path.join(gen_folder,
                                      "module-custom_bar_build_module_file_name_BUILDTargets.cmake")
-    components_module_build = os.path.join(client.current_folder, "build", "generators",
+    components_module_build = os.path.join(gen_folder,
                                            "custom_bar_build_file_name_BUILD-Target-release.cmake")
-    config_file_build = os.path.join(client.current_folder, "build", "generators",
-                                     "custom_bar_build_file_name_BUILDTargets.cmake")
+    config_file_build = os.path.join(gen_folder, "custom_bar_build_file_name_BUILDTargets.cmake")
 
     # uses cmake_find_mode set in bar: both
     client.run("create bar.py bar/1.0@ -pr:h=default -pr:b=default")
diff --git a/conans/test/integration/toolchains/cmake/test_cmaketoolchain.py b/conans/test/integration/toolchains/cmake/test_cmaketoolchain.py
index e219bcc5a..38a793f42 100644
--- a/conans/test/integration/toolchains/cmake/test_cmaketoolchain.py
+++ b/conans/test/integration/toolchains/cmake/test_cmaketoolchain.py
@@ -8,7 +8,6 @@ from mock import mock
 
 from conan.tools.cmake.presets import load_cmake_presets
 from conans.test.assets.genconanfile import GenConanfile
-from conans.test.utils.test_files import temp_folder
 from conans.test.utils.tools import TestClient
 from conans.util.files import rmdir
 
@@ -379,7 +378,7 @@ def test_cmake_presets_binary_dir_available():
     else:
         build_dir = os.path.join(client.current_folder, "build")
 
-    presets = load_cmake_presets(os.path.join(client.current_folder, "build", "generators"))
+    presets = load_cmake_presets(os.path.join(build_dir, "generators"))
     assert presets["configurePresets"][0]["binaryDir"] == build_dir
 
 
@@ -422,6 +421,7 @@ def test_cmake_presets_multiconfig():
     # Repeat one
     client.run("install mylib/1.0@ -g CMakeToolchain -s build_type=Debug --profile:h=profile")
     client.run("install mylib/1.0@ -g CMakeToolchain -s build_type=Debug --profile:h=profile")
+    presets = json.loads(client.load("CMakePresets.json"))
     assert len(presets["buildPresets"]) == 4
     assert presets["buildPresets"][0]["configuration"] == "Release"
     assert presets["buildPresets"][1]["configuration"] == "Debug"
@@ -517,6 +517,7 @@ def test_toolchain_cache_variables():
     assert "-DCMAKE_TOOLCHAIN_FILE=" in client.out
     assert f"-G {_format_val('MinGW Makefiles')}" in client.out
 
+
 def test_android_c_library():
     client = TestClient()
     conanfile = textwrap.dedent("""
@@ -845,3 +846,36 @@ def test_set_cmake_lang_compilers_and_launchers():
     assert 'set(CMAKE_C_COMPILER "/my/local/gcc")' in toolchain
     assert 'set(CMAKE_CXX_COMPILER "g++")' in toolchain
     assert 'set(CMAKE_RC_COMPILER "C:/local/rc.exe")' in toolchain
+
+
+def test_cmake_layout_toolchain_folder():
+    """ in single-config generators, the toolchain is a different file per configuration
+    https://github.com/conan-io/conan/issues/12827
+    """
+    c = TestClient()
+    conanfile = textwrap.dedent("""
+        from conan import ConanFile
+        from conan.tools.cmake import cmake_layout
+
+        class Conan(ConanFile):
+            settings = "os", "arch", "compiler", "build_type"
+            generators = "CMakeToolchain"
+
+            def layout(self):
+                cmake_layout(self)
+            """)
+    c.save({"conanfile.py": conanfile})
+    c.run("install . -s os=Linux -s compiler=gcc -s compiler.version=7 -s build_type=Release "
+          "-s compiler.libcxx=libstdc++11")
+    assert os.path.exists(os.path.join(c.current_folder,
+                                       "build/Release/generators/conan_toolchain.cmake"))
+    c.run("install . -s os=Linux -s compiler=gcc -s compiler.version=7 -s build_type=Debug "
+          "-s compiler.libcxx=libstdc++11")
+    assert os.path.exists(os.path.join(c.current_folder,
+                                       "build/Debug/generators/conan_toolchain.cmake"))
+    c.run("install . -s os=Linux -s compiler=gcc -s compiler.version=7 -s build_type=Debug "
+          "-s compiler.libcxx=libstdc++11 -s arch=x86 "
+          "-c tools.cmake.cmake_layout:build_folder_vars='[\"settings.arch\", \"settings.build_type\"]'")
+    print(c.out)
+    assert os.path.exists(os.path.join(c.current_folder,
+                                       "build/x86-debug/generators/conan_toolchain.cmake"))
diff --git a/conans/test/integration/toolchains/test_not_mix_legacy.py b/conans/test/integration/toolchains/test_not_mix_legacy.py
new file mode 100644
index 000000000..c0fb38fec
--- /dev/null
+++ b/conans/test/integration/toolchains/test_not_mix_legacy.py
@@ -0,0 +1,79 @@
+import textwrap
+
+from conans.test.utils.tools import TestClient
+
+
+def test_not_mix_legacy_cmake():
+    c = TestClient()
+    conanfile = textwrap.dedent("""
+        from conan import ConanFile
+        from conans import CMake
+        class Pkg(ConanFile):
+            name = "pkg"
+            version = "0.1"
+            settings = "build_type"
+            generators = "CMakeDeps"
+            def build(self):
+                CMake(self)
+            """)
+    c.save({"conanfile.py": conanfile})
+    c.run("create .", assert_error=True)
+    assert "Using the wrong 'CMake' helper" in c.out
+
+
+def test_not_mix_legacy_cmake_generate():
+    c = TestClient()
+    conanfile = textwrap.dedent("""
+        from conan import ConanFile
+        from conans import CMake
+        from conan.tools.cmake import CMakeDeps
+        class Pkg(ConanFile):
+            name = "pkg"
+            version = "0.1"
+            settings = "build_type"
+            def generate(self):
+                CMakeDeps(self)
+            def build(self):
+                CMake(self)
+            """)
+    c.save({"conanfile.py": conanfile})
+    c.run("create .", assert_error=True)
+    assert "Using the wrong 'CMake' helper" in c.out
+
+
+def test_not_mix_legacy_msbuild():
+    c = TestClient()
+    conanfile = textwrap.dedent("""
+        from conan import ConanFile
+        from conans import MSBuild
+        class Pkg(ConanFile):
+            name = "pkg"
+            version = "0.1"
+            settings = "build_type", "arch"
+            generators = "MSBuildDeps"
+            def build(self):
+                MSBuild(self)
+            """)
+    c.save({"conanfile.py": conanfile})
+    c.run("create .", assert_error=True)
+    assert "Using the wrong 'MSBuild' helper" in c.out
+
+
+def test_not_mix_legacy_msbuild_generate():
+    c = TestClient()
+    conanfile = textwrap.dedent("""
+        from conan import ConanFile
+        from conans import MSBuild
+        from conan.tools.microsoft import MSBuildDeps
+        class Pkg(ConanFile):
+            name = "pkg"
+            version = "0.1"
+            settings = "build_type", "arch"
+            def generate(self):
+                MSBuildDeps(self)
+            def build(self):
+                MSBuild(self)
+            """)
+    c.save({"conanfile.py": conanfile})
+    c.run("create .", assert_error=True)
+    assert "Using the wrong 'MSBuild' helper" in c.out
diff --git a/conans/test/unittests/tools/gnu/autotoolschain_test.py b/conans/test/unittests/tools/gnu/autotoolschain_test.py
index 8141dc8c8..93b7d31ec 100644
--- a/conans/test/unittests/tools/gnu/autotoolschain_test.py
+++ b/conans/test/unittests/tools/gnu/autotoolschain_test.py
@@ -25,6 +25,23 @@ def test_get_gnu_triplet_for_cross_building():
     assert autotoolschain._build == "i686-solaris"
 
 
+def test_get_toolchain_cppstd():
+    settings = MockSettings({"build_type": "Release",
+                             "compiler": "gcc",
+                             "compiler.version": "10",
+                             "compiler.cppstd": "20",
+                             "os": "Linux",
+                             "arch": "x86_64"})
+    conanfile = ConanFileMock()
+    conanfile.settings = settings
+    conanfile.settings_build = settings
+    autotoolschain = AutotoolsToolchain(conanfile)
+    assert autotoolschain.cppstd == "-std=c++2a"
+    settings.values["compiler.version"] = "12"
+    autotoolschain = AutotoolsToolchain(conanfile)
+    assert autotoolschain.cppstd == "-std=c++20"
+
+
 @pytest.mark.parametrize("runtime, runtime_type, expected",
                          [("static", "Debug", "MTd"),
                           ("static", "Release", "MT"),