Repository: conan-io/conan
Pull request #16964 (2024-09-09 20:07:50)

New CMakeDeps
Changelog: Feature: New ``CMakeDeps`` generator activated by ``tools.cmake.cmakedeps:new`` conf with value ``will_break_next`` for evaluation. This new generator deduces or use ``cpp_info.location/link_location`` to define STATIC; SHARED, INTERFACE imported targets. It will also define the IMPORTED_LOCATION, the IMPORTED_CONFIGURATION, etc.
Changelog: Feature: Use ``cpp_info.languages``, that default to the recipe ``languages`` to propagate "link-language" requirements to consumers of the packages
Changelog: Feature: Define ``cpp_info.default_components`` for the new ``CMakeDeps`` generator only
Changelog: Feature: Model ``cpp_info.exes`` field for executable applications, used only by the new ``CMakeDeps`` generator, that generate IMPORTED executable targets in ``CMakeDeps`` for ``cpp_info.exes``
Docs: https://github.com/conan-io/docs/pull/XXXX

Close https://github.com/conan-io/conan/issues/7240
Close https://github.com/conan-io/conan/issues/13560
Close https://github.com/conan-io/conan/issues/16990
Close https://github.com/conan-io/conan/issues/16688
Close https://github.com/conan-io/conan/issues/12012
Close https://github.com/conan-io/conan/issues/12180
Close https://github.com/conan-io/conan/issues/14606
Close https://github.com/conan-io/conan/issues/17018
Close https://github.com/conan-io/conan/issues/16324
Close https://github.com/conan-io/conan/issues/14607

TODO: Close https://github.com/conan-io/conan/issues/17224



valgur: Could these issues also be addressed in the reworked CMakeDeps, maybe?
- #12180
- #12012
- #15386

The need to set `CMAKE_TRY_COMPILE_CONFIGURATION` is a very common pitfall when building external projects, but I suppose it might be unavoidable if the CMakeDeps wants to support multi-config CMake generators.

Patch:
diff --git a/conan/cps/cps.py b/conan/cps/cps.py
index 67007d857..621a387ce 100644
--- a/conan/cps/cps.py
+++ b/conan/cps/cps.py
@@ -85,7 +85,7 @@ class CPSComponent:
             cps_comp.type = CPSComponentType.INTERFACE
             return cps_comp
 
-        cpp_info.deduce_cps(pkg_type)
+        cpp_info.deduce_locations(pkg_type)
         cps_comp.type = CPSComponentType.from_conan(cpp_info.type)
         cps_comp.location = cpp_info.location
         cps_comp.link_location = cpp_info.link_location
diff --git a/conan/tools/cmake/__init__.py b/conan/tools/cmake/__init__.py
index d4123be74..73c8a835b 100644
--- a/conan/tools/cmake/__init__.py
+++ b/conan/tools/cmake/__init__.py
@@ -1,4 +1,14 @@
 from conan.tools.cmake.toolchain.toolchain import CMakeToolchain
 from conan.tools.cmake.cmake import CMake
-from conan.tools.cmake.cmakedeps.cmakedeps import CMakeDeps
 from conan.tools.cmake.layout import cmake_layout
+
+
+def CMakeDeps(conanfile):  # noqa
+    if conanfile.conf.get("tools.cmake.cmakedeps:new", choices=["will_break_next"]):
+        from conan.tools.cmake.cmakedeps2.cmakedeps import CMakeDeps2
+        conanfile.output.warning("Using the new CMakeDeps generator, behind the "
+                                 "'tools.cmake.cmakedeps:new' gate conf. This conf will change"
+                                 "next release, breaking, so use it only for testing and dev")
+        return CMakeDeps2(conanfile)
+    from conan.tools.cmake.cmakedeps.cmakedeps import CMakeDeps as _CMakeDeps
+    return _CMakeDeps(conanfile)
diff --git a/conan/tools/cmake/cmakedeps2/__init__.py b/conan/tools/cmake/cmakedeps2/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/conan/tools/cmake/cmakedeps2/cmakedeps.py b/conan/tools/cmake/cmakedeps2/cmakedeps.py
new file mode 100644
index 000000000..b92e8276e
--- /dev/null
+++ b/conan/tools/cmake/cmakedeps2/cmakedeps.py
@@ -0,0 +1,211 @@
+import os
+import re
+import textwrap
+
+from jinja2 import Template
+
+from conan.internal import check_duplicated_generator
+from conan.tools.cmake.cmakedeps2.config import ConfigTemplate2
+from conan.tools.cmake.cmakedeps2.config_version import ConfigVersionTemplate2
+from conan.tools.cmake.cmakedeps2.target_configuration import TargetConfigurationTemplate2
+from conan.tools.cmake.cmakedeps2.targets import TargetsTemplate2
+from conan.tools.files import save
+from conan.errors import ConanException
+from conans.model.dependencies import get_transitive_requires
+from conans.util.files import load
+
+FIND_MODE_MODULE = "module"
+FIND_MODE_CONFIG = "config"
+FIND_MODE_NONE = "none"
+FIND_MODE_BOTH = "both"
+
+
+class CMakeDeps2:
+
+    def __init__(self, conanfile):
+        self._conanfile = conanfile
+        self.configuration = str(self._conanfile.settings.build_type)
+
+        # These are just for legacy compatibility, but not use at al
+        self.build_context_activated = []
+        self.build_context_build_modules = []
+        self.build_context_suffix = {}
+        # Enable/Disable checking if a component target exists or not
+        self.check_components_exist = False
+
+        self._properties = {}
+
+    def generate(self):
+        check_duplicated_generator(self, self._conanfile)
+        # Current directory is the generators_folder
+        generator_files = self._content()
+        for generator_file, content in generator_files.items():
+            save(self._conanfile, generator_file, content)
+        _PathGenerator(self, self._conanfile).generate()
+
+    def _content(self):
+        host_req = self._conanfile.dependencies.host
+        build_req = self._conanfile.dependencies.direct_build
+        test_req = self._conanfile.dependencies.test
+
+        # Iterate all the transitive requires
+        ret = {}
+        for require, dep in list(host_req.items()) + list(build_req.items()) + list(test_req.items()):
+            cmake_find_mode = self.get_property("cmake_find_mode", dep)
+            cmake_find_mode = cmake_find_mode or FIND_MODE_CONFIG
+            cmake_find_mode = cmake_find_mode.lower()
+            if cmake_find_mode == FIND_MODE_NONE:
+                continue
+
+            config = ConfigTemplate2(self, dep)
+            ret[config.filename] = config.content()
+            config_version = ConfigVersionTemplate2(self, dep)
+            ret[config_version.filename] = config_version.content()
+
+            targets = TargetsTemplate2(self, dep)
+            ret[targets.filename] = targets.content()
+            target_configuration = TargetConfigurationTemplate2(self, dep, require)
+            ret[target_configuration.filename] = target_configuration.content()
+        return ret
+
+    def set_property(self, dep, prop, value, build_context=False):
+        """
+        Using this method you can overwrite the :ref:`property<CMakeDeps Properties>` values set by
+        the Conan recipes from the consumer.
+
+        :param dep: Name of the dependency to set the :ref:`property<CMakeDeps Properties>`. For
+         components use the syntax: ``dep_name::component_name``.
+        :param prop: Name of the :ref:`property<CMakeDeps Properties>`.
+        :param value: Value of the property. Use ``None`` to invalidate any value set by the
+         upstream recipe.
+        :param build_context: Set to ``True`` if you want to set the property for a dependency that
+         belongs to the build context (``False`` by default).
+        """
+        build_suffix = "&build" if build_context else ""
+        self._properties.setdefault(f"{dep}{build_suffix}", {}).update({prop: value})
+
+    def get_property(self, prop, dep, comp_name=None, check_type=None):
+        dep_name = dep.ref.name
+        build_suffix = "&build" if dep.context == "build" else ""
+        dep_comp = f"{str(dep_name)}::{comp_name}" if comp_name else f"{str(dep_name)}"
+        try:
+            value = self._properties[f"{dep_comp}{build_suffix}"][prop]
+            if check_type is not None and not isinstance(value, check_type):
+                raise ConanException(f'The expected type for {prop} is "{check_type.__name__}", '
+                                     f'but "{type(value).__name__}" was found')
+            return value
+        except KeyError:
+            # Here we are not using the cpp_info = deduce_cpp_info(dep) because it is not
+            # necessary for the properties
+            return dep.cpp_info.get_property(prop, check_type=check_type) if not comp_name \
+                else dep.cpp_info.components[comp_name].get_property(prop, check_type=check_type)
+
+    def get_cmake_filename(self, dep, module_mode=None):
+        """Get the name of the file for the find_package(XXX)"""
+        # This is used by CMakeDeps to determine:
+        # - The filename to generate (XXX-config.cmake or FindXXX.cmake)
+        # - The name of the defined XXX_DIR variables
+        # - The name of transitive dependencies for calls to find_dependency
+        if module_mode and self._get_find_mode(dep) in [FIND_MODE_MODULE, FIND_MODE_BOTH]:
+            ret = self.get_property("cmake_module_file_name", dep)
+            if ret:
+                return ret
+        ret = self.get_property("cmake_file_name", dep)
+        return ret or dep.ref.name
+
+    def _get_find_mode(self, dep):
+        """
+        :param dep: requirement
+        :return: "none" or "config" or "module" or "both" or "config" when not set
+        """
+        tmp = self.get_property("cmake_find_mode", dep)
+        if tmp is None:
+            return "config"
+        return tmp.lower()
+
+    def get_transitive_requires(self, conanfile):
+        # Prepared to filter transitive tool-requires with visible=True
+        return get_transitive_requires(self._conanfile, conanfile)
+
+
+class _PathGenerator:
+    _conan_cmakedeps_paths = "conan_cmakedeps_paths.cmake"
+
+    def __init__(self, cmakedeps, conanfile):
+        self._conanfile = conanfile
+        self._cmakedeps = cmakedeps
+
+    def generate(self):
+        template = textwrap.dedent("""\
+            {% for pkg_name, folder in pkg_paths.items() %}
+            set({{pkg_name}}_DIR "{{folder}}")
+            {% endfor %}
+            {% if host_runtime_dirs %}
+            set(CONAN_RUNTIME_LIB_DIRS {{ host_runtime_dirs }} )
+            {% endif %}
+            """)
+
+        host_req = self._conanfile.dependencies.host
+        build_req = self._conanfile.dependencies.direct_build
+        test_req = self._conanfile.dependencies.test
+
+        # gen_folder = self._conanfile.generators_folder.replace("\\", "/")
+        # if not, test_cmake_add_subdirectory test fails
+        # content.append('set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)')
+        pkg_paths = {}
+        for req, dep in list(host_req.items()) + list(build_req.items()) + list(test_req.items()):
+            cmake_find_mode = self._cmakedeps.get_property("cmake_find_mode", dep)
+            cmake_find_mode = cmake_find_mode or FIND_MODE_CONFIG
+            cmake_find_mode = cmake_find_mode.lower()
+
+            pkg_name = self._cmakedeps.get_cmake_filename(dep)
+            # https://cmake.org/cmake/help/v3.22/guide/using-dependencies/index.html
+            if cmake_find_mode == FIND_MODE_NONE:
+                try:
+                    # This is irrespective of the components, it should be in the root cpp_info
+                    # To define the location of the pkg-config.cmake file
+                    build_dir = dep.cpp_info.builddirs[0]
+                except IndexError:
+                    build_dir = dep.package_folder
+                pkg_folder = build_dir.replace("\\", "/") if build_dir else None
+                if pkg_folder:
+                    config_file = ConfigTemplate2(self._cmakedeps, dep).filename
+                    if os.path.isfile(os.path.join(pkg_folder, config_file)):
+                        pkg_paths[pkg_name] = pkg_folder
+                continue
+
+            # If CMakeDeps generated, the folder is this one
+            # content.append(f'set({pkg_name}_ROOT "{gen_folder}")')
+            pkg_paths[pkg_name] = "${CMAKE_CURRENT_LIST_DIR}"
+
+        context = {"host_runtime_dirs": self._get_host_runtime_dirs(),
+                   "pkg_paths": pkg_paths}
+        content = Template(template, trim_blocks=True, lstrip_blocks=True).render(context)
+        save(self._conanfile, self._conan_cmakedeps_paths, content)
+
+    def _get_host_runtime_dirs(self):
+        host_runtime_dirs = {}
+
+        # Get the previous configuration
+        if os.path.exists(self._conan_cmakedeps_paths):
+            existing_toolchain = load(self._conan_cmakedeps_paths)
+            pattern_lib_dirs = r"set\(CONAN_RUNTIME_LIB_DIRS ([^)]*)\)"
+            variable_match = re.search(pattern_lib_dirs, existing_toolchain)
+            if variable_match:
+                capture = variable_match.group(1)
+                matches = re.findall(r'"\$<\$<CONFIG:([A-Za-z]*)>:([^>]*)>"', capture)
+                for config, paths in matches:
+                    host_runtime_dirs.setdefault(config, []).append(paths)
+
+        is_win = self._conanfile.settings.get_safe("os") == "Windows"
+        for req in self._conanfile.dependencies.host.values():
+            config = req.settings.get_safe("build_type", self._cmakedeps.configuration)
+            aggregated_cppinfo = req.cpp_info.aggregated_components()
+            runtime_dirs = aggregated_cppinfo.bindirs if is_win else aggregated_cppinfo.libdirs
+            for d in runtime_dirs:
+                d = d.replace("\\", "/")
+                existing = host_runtime_dirs.setdefault(config, [])
+                if d not in existing:
+                    existing.append(d)
+
+        return ' '.join(f'"$<$<CONFIG:{c}>:{i}>"' for c, v in host_runtime_dirs.items() for i in v)
diff --git a/conan/tools/cmake/cmakedeps2/config.py b/conan/tools/cmake/cmakedeps2/config.py
new file mode 100644
index 000000000..459d3b421
--- /dev/null
+++ b/conan/tools/cmake/cmakedeps2/config.py
@@ -0,0 +1,61 @@
+import textwrap
+
+import jinja2
+from jinja2 import Template
+
+
+class ConfigTemplate2:
+    """
+    FooConfig.cmake
+    foo-config.cmake
+    """
+    def __init__(self, cmakedeps, conanfile):
+        self._cmakedeps = cmakedeps
+        self._conanfile = conanfile
+
+    def content(self):
+        t = Template(self._template, trim_blocks=True, lstrip_blocks=True,
+                     undefined=jinja2.StrictUndefined)
+        return t.render(self._context)
+
+    @property
+    def filename(self):
+        f = self._cmakedeps.get_cmake_filename(self._conanfile)
+        return f"{f}-config.cmake" if f == f.lower() else f"{f}Config.cmake"
+
+    @property
+    def _context(self):
+        f = self._cmakedeps.get_cmake_filename(self._conanfile)
+        targets_include = f"{f}Targets.cmake"
+        pkg_name = self._conanfile.ref.name
+        build_modules_paths = self._cmakedeps.get_property("cmake_build_modules", self._conanfile,
+                                                           check_type=list) or []
+        # FIXME: Proper escaping of paths for CMake and relativization
+        # FIXME: build_module_paths coming from last config only
+        build_modules_paths = [f.replace("\\", "/") for f in build_modules_paths]
+        return {"pkg_name": pkg_name,
+                "targets_include_file": targets_include,
+                "build_modules_paths": build_modules_paths}
+
+    @property
+    def _template(self):
+        return textwrap.dedent("""\
+        # Requires CMake > 3.15
+        if(${CMAKE_VERSION} VERSION_LESS "3.15")
+            message(FATAL_ERROR "The 'CMakeDeps' generator only works with CMake >= 3.15")
+        endif()
+
+        include(${CMAKE_CURRENT_LIST_DIR}/{{ targets_include_file }})
+
+        get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+        if(NOT isMultiConfig AND NOT CMAKE_BUILD_TYPE)
+           message(FATAL_ERROR "Please, set the CMAKE_BUILD_TYPE variable when calling to CMake "
+                               "adding the '-DCMAKE_BUILD_TYPE=<build_type>' argument.")
+        endif()
+
+        # build_modules_paths comes from last configuration only
+        {% for build_module in build_modules_paths %}
+        message(STATUS "Conan: Including build module from '{{build_module}}'")
+        include("{{ build_module }}")
+        {% endfor %}
+        """)
diff --git a/conan/tools/cmake/cmakedeps2/config_version.py b/conan/tools/cmake/cmakedeps2/config_version.py
new file mode 100644
index 000000000..4a3212ba2
--- /dev/null
+++ b/conan/tools/cmake/cmakedeps2/config_version.py
@@ -0,0 +1,102 @@
+import textwrap
+
+import jinja2
+from jinja2 import Template
+
+from conan.errors import ConanException
+
+
+class ConfigVersionTemplate2:
+    """
+    foo-config-version.cmake
+    """
+    def __init__(self, cmakedeps, conanfile):
+        self._cmakedeps = cmakedeps
+        self._conanfile = conanfile
+
+    def content(self):
+        t = Template(self._template, trim_blocks=True, lstrip_blocks=True,
+                     undefined=jinja2.StrictUndefined)
+        return t.render(self._context)
+
+    @property
+    def filename(self):
+        f = self._cmakedeps.get_cmake_filename(self._conanfile)
+        return  f"{f}-config-version.cmake" if f == f.lower() else f"{f}ConfigVersion.cmake"
+
+    @property
+    def _context(self):
+        policy = self._cmakedeps.get_property("cmake_config_version_compat", self._conanfile)
+        if policy is None:
+            policy = "SameMajorVersion"
+        if policy not in ("AnyNewerVersion", "SameMajorVersion", "SameMinorVersion", "ExactVersion"):
+            raise ConanException(f"Unknown cmake_config_version_compat={policy} in {self._conanfile}")
+        version = self._cmakedeps.get_property("system_package_version", self._conanfile)
+        version = version or self._conanfile.ref.version
+        return {"version": version,
+                "policy": policy}
+
+    @property
+    def _template(self):
+        # https://gitlab.kitware.com/cmake/cmake/blob/master/Modules/BasicConfigVersion-SameMajorVersion.cmake.in
+        # This will be at XXX-config-version.cmake
+        # AnyNewerVersion|SameMajorVersion|SameMinorVersion|ExactVersion
+        ret = textwrap.dedent("""\
+            set(PACKAGE_VERSION "{{ version }}")
+
+            if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+                set(PACKAGE_VERSION_COMPATIBLE FALSE)
+            else()
+                {% if policy == "AnyNewerVersion" %}
+                set(PACKAGE_VERSION_COMPATIBLE TRUE)
+                {% elif policy == "SameMajorVersion" %}
+                if("{{ version }}" MATCHES "^([0-9]+)\\\\.")
+                    set(CVF_VERSION_MAJOR {{ '${CMAKE_MATCH_1}' }})
+                else()
+                    set(CVF_VERSION_MAJOR "{{ version }}")
+                endif()
+
+                if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR)
+                    set(PACKAGE_VERSION_COMPATIBLE TRUE)
+                else()
+                    set(PACKAGE_VERSION_COMPATIBLE FALSE)
+                endif()
+                {% elif policy == "SameMinorVersion" %}
+                if("{{ version }}" MATCHES "^([0-9]+)\\.([0-9]+)")
+                    set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
+                    set(CVF_VERSION_MINOR "${CMAKE_MATCH_2}")
+                else()
+                    set(CVF_VERSION_MAJOR "{{ version }}")
+                    set(CVF_VERSION_MINOR "")
+                endif()
+                if((PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR) AND
+                    (PACKAGE_FIND_VERSION_MINOR STREQUAL CVF_VERSION_MINOR))
+                  set(PACKAGE_VERSION_COMPATIBLE TRUE)
+                else()
+                  set(PACKAGE_VERSION_COMPATIBLE FALSE)
+                endif()
+                {% elif policy == "ExactVersion" %}
+                if("{{ version }}" MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)")
+                    set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
+                    set(CVF_VERSION_MINOR "${CMAKE_MATCH_2}")
+                    set(CVF_VERSION_MINOR "${CMAKE_MATCH_3}")
+                else()
+                    set(CVF_VERSION_MAJOR "{{ version }}")
+                    set(CVF_VERSION_MINOR "")
+                    set(CVF_VERSION_PATCH "")
+                endif()
+                if((PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR) AND
+                    (PACKAGE_FIND_VERSION_MINOR STREQUAL CVF_VERSION_MINOR) AND
+                    (PACKAGE_FIND_VERSION_PATCH STREQUAL CVF_VERSION_PATCH))
+                  set(PACKAGE_VERSION_COMPATIBLE TRUE)
+                else()
+                  set(PACKAGE_VERSION_COMPATIBLE FALSE)
+                endif()
+                {% endif %}
+
+                if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+                    set(PACKAGE_VERSION_EXACT TRUE)
+                endif()
+            endif()
+            """)
+        return ret
diff --git a/conan/tools/cmake/cmakedeps2/target_configuration.py b/conan/tools/cmake/cmakedeps2/target_configuration.py
new file mode 100644
index 000000000..5d8c21504
--- /dev/null
+++ b/conan/tools/cmake/cmakedeps2/target_configuration.py
@@ -0,0 +1,384 @@
+import os
+import textwrap
+
+import jinja2
+from jinja2 import Template
+
+from conan.errors import ConanException
+from conans.client.graph.graph import CONTEXT_BUILD, CONTEXT_HOST
+from conans.model.pkg_type import PackageType
+
+
+class TargetConfigurationTemplate2:
+    """
+    FooTarget-release.cmake
+    """
+    def __init__(self, cmakedeps, conanfile, require):
+        self._cmakedeps = cmakedeps
+        self._conanfile = conanfile  # The dependency conanfile, not the consumer one
+        self._require = require
+
+    def content(self):
+        t = Template(self._template, trim_blocks=True, lstrip_blocks=True,
+                     undefined=jinja2.StrictUndefined)
+        return t.render(self._context)
+
+    @property
+    def filename(self):
+        f = self._cmakedeps.get_cmake_filename(self._conanfile)
+        # Fallback to consumer configuration if it doesn't have build_type
+        config = self._conanfile.settings.get_safe("build_type", self._cmakedeps.configuration)
+        config = (config or "none").lower()
+        build = "Build" if self._conanfile.context == CONTEXT_BUILD else ""
+        return f"{f}-Targets{build}-{config}.cmake"
+
+    def _requires(self, info, components):
+        result = []
+        requires = info.parsed_requires()
+        pkg_name = self._conanfile.ref.name
+        transitive_reqs = self._cmakedeps.get_transitive_requires(self._conanfile)
+        if not requires and not components:  # global cpp_info without components definition
+            # require the pkgname::pkgname base (user defined) or INTERFACE base target
+            return [f"{d.ref.name}::{d.ref.name}" for d in transitive_reqs.values()]
+
+        for required_pkg, required_comp in requires:
+            if required_pkg is None:  # Points to a component of same package
+                dep_comp = components.get(required_comp)
+                assert dep_comp, f"Component {required_comp} not found in {self._conanfile}"
+                dep_target = self._cmakedeps.get_property("cmake_target_name", self._conanfile,
+                                                          required_comp)
+                dep_target = dep_target or f"{pkg_name}::{required_comp}"
+                result.append(dep_target)
+            else:  # Different package
+                try:
+                    dep = transitive_reqs[required_pkg]
+                except KeyError:  # The transitive dep might have been skipped
+                    pass
+                else:
+                    # To check if the component exist, it is ok to use the standard cpp_info
+                    # No need to use the cpp_info = deduce_cpp_info(dep)
+                    dep_comp = dep.cpp_info.components.get(required_comp)
+                    if dep_comp is None:
+                        # It must be the interface pkgname::pkgname target
+                        assert required_pkg == required_comp
+                        comp = None
+                    else:
+                        comp = required_comp
+                    dep_target = self._cmakedeps.get_property("cmake_target_name", dep, comp)
+                    dep_target = dep_target or f"{required_pkg}::{required_comp}"
+                    result.append(dep_target)
+        return result
+
+    @property
+    def _context(self):
+        cpp_info = self._conanfile.cpp_info.deduce_full_cpp_info(self._conanfile)
+        pkg_name = self._conanfile.ref.name
+        # fallback to consumer configuration if it doesn't have build_type
+        config = self._conanfile.settings.get_safe("build_type", self._cmakedeps.configuration)
+        config = config.upper() if config else None
+        pkg_folder = self._conanfile.package_folder.replace("\\", "/")
+        config_folder = f"_{config}" if config else ""
+        build = "_BUILD" if self._conanfile.context == CONTEXT_BUILD else ""
+        pkg_folder_var = f"{pkg_name}_PACKAGE_FOLDER{config_folder}{build}"
+
+        libs = {}
+        # The BUILD context does not generate libraries targets atm
+        if self._conanfile.context == CONTEXT_HOST:
+            libs = self._get_libs(cpp_info, pkg_name, pkg_folder, pkg_folder_var)
+            self._add_root_lib_target(libs, pkg_name, cpp_info)
+        exes = self._get_exes(cpp_info, pkg_name, pkg_folder, pkg_folder_var)
+
+        prefixes = self._cmakedeps.get_property("cmake_additional_variables_prefixes",
+                                                self._conanfile, check_type=list) or []
+        f = self._cmakedeps.get_cmake_filename(self._conanfile)
+        prefixes = [f] + prefixes
+        include_dirs = definitions = libraries = None
+        if not self._require.build:  # To add global variables for try_compile and legacy
+            aggregated_cppinfo = cpp_info.aggregated_components()
+            # FIXME: Proper escaping of paths for CMake and relativization
+            include_dirs = ";".join(i.replace("\\", "/") for i in aggregated_cppinfo.includedirs)
+            definitions = ""
+            root_target_name = self._cmakedeps.get_property("cmake_target_name", self._conanfile)
+            libraries = root_target_name or f"{pkg_name}::{pkg_name}"
+
+        # TODO: Missing find_modes
+        dependencies = self._get_dependencies()
+        return {"dependencies": dependencies,
+                "pkg_folder": pkg_folder,
+                "pkg_folder_var": pkg_folder_var,
+                "config": config,
+                "exes": exes,
+                "libs": libs,
+                "context": self._conanfile.context,
+                # Extra global variables
+                "additional_variables_prefixes": prefixes,
+                "version": self._conanfile.ref.version,
+                "include_dirs": include_dirs,
+                "definitions": definitions,
+                "libraries": libraries
+                }
+
+    def _get_libs(self, cpp_info, pkg_name, pkg_folder, pkg_folder_var) -> dict:
+        libs = {}
+        if cpp_info.has_components:
+            for name, component in cpp_info.components.items():
+                target_name = self._cmakedeps.get_property("cmake_target_name", self._conanfile,
+                                                           name)
+                target_name = target_name or f"{pkg_name}::{name}"
+                target = self._get_cmake_lib(component, cpp_info.components, pkg_folder,
+                                             pkg_folder_var)
+                if target is not None:
+                    libs[target_name] = target
+        else:
+            target_name = self._cmakedeps.get_property("cmake_target_name", self._conanfile)
+            target_name = target_name or f"{pkg_name}::{pkg_name}"
+            target = self._get_cmake_lib(cpp_info, None, pkg_folder, pkg_folder_var)
+            if target is not None:
+                libs[target_name] = target
+        return libs
+
+    def _get_cmake_lib(self, info, components, pkg_folder, pkg_folder_var):
+        if info.exe or not (info.includedirs or info.libs):
+            return
+
+        includedirs = ";".join(self._path(i, pkg_folder, pkg_folder_var)
+                               for i in info.includedirs) if info.includedirs else ""
+        requires = " ".join(self._requires(info, components))
+        defines = " ".join(info.defines)
+        # TODO: Missing escaping?
+        # TODO: Missing link language
+        # FIXME: Filter by lib traits!!!!!
+        if not self._require.headers:  # If not depending on headers, paths and
+            includedirs = defines = None
+        system_libs = " ".join(info.system_libs)
+        target = {"type": "INTERFACE",
+                  "includedirs": includedirs,
+                  "defines": defines,
+                  "requires": requires,
+                  "cxxflags": " ".join(info.cxxflags),
+                  "cflags": " ".join(info.cflags),
+                  "sharedlinkflags": " ".join(info.sharedlinkflags),
+                  "exelinkflags": " ".join(info.exelinkflags),
+                  "system_libs": system_libs}
+
+        if info.frameworks:
+            self._conanfile.output.warning("frameworks not supported yet in new CMakeDeps generator")
+
+        if info.libs:
+            if len(info.libs) != 1:
+                raise ConanException(f"New CMakeDeps only allows 1 lib per component:\n"
+                                     f"{self._conanfile}: {info.libs}")
+            assert info.location, "info.location missing for .libs, it should have been deduced"
+            location = self._path(info.location, pkg_folder, pkg_folder_var)
+            link_location = self._path(info.link_location, pkg_folder, pkg_folder_var) \
+                if info.link_location else None
+            lib_type = "SHARED" if info.type is PackageType.SHARED else \
+                "STATIC" if info.type is PackageType.STATIC else None
+            assert lib_type, f"Unknown package type {info.type}"
+            target["type"] = lib_type
+            target["location"] = location
+            target["link_location"] = link_location
+            link_languages = info.languages or self._conanfile.languages or []
+            link_languages = ["CXX" if c == "C++" else c for c in link_languages]
+            target["link_languages"] = link_languages
+
+        return target
+
+    def _add_root_lib_target(self, libs, pkg_name, cpp_info):
+        """
+        Addd a new pkgname::pkgname INTERFACE target that depends on default_components or
+        on all other library targets (not exes)
+        It will not be added if there exists already a pkgname::pkgname target.
+        """
+        root_target_name = self._cmakedeps.get_property("cmake_target_name", self._conanfile)
+        root_target_name = root_target_name or f"{pkg_name}::{pkg_name}"
+        if libs and root_target_name not in libs:
+            # Add a generic interface target for the package depending on the others
+            if cpp_info.default_components is not None:
+                all_requires = []
+                for defaultc in cpp_info.default_components:
+                    target_name = self._cmakedeps.get_property("cmake_target_name", self._conanfile,
+                                                               defaultc)
+                    comp_name = target_name or f"{pkg_name}::{defaultc}"
+                    all_requires.append(comp_name)
+                all_requires = " ".join(all_requires)
+            else:
+                all_requires = " ".join(libs.keys())
+            libs[root_target_name] = {"type": "INTERFACE",
+                                      "requires": all_requires}
+
+    def _get_exes(self, cpp_info, pkg_name, pkg_folder, pkg_folder_var):
+        exes = {}
+
+        if cpp_info.has_components:
+            assert not cpp_info.exe, "Package has components and exe"
+            assert not cpp_info.libs, "Package has components and libs"
+            for name, comp in cpp_info.components.items():
+                if comp.exe or comp.type is PackageType.APP:
+                    target_name = self._cmakedeps.get_property("cmake_target_name", self._conanfile,
+                                                               name)
+                    target = target_name or f"{pkg_name}::{name}"
+                    exe_location = self._path(comp.location, pkg_folder, pkg_folder_var)
+                    exes[target] = exe_location
+        else:
+            if cpp_info.exe:
+                assert not cpp_info.libs, "Package has exe and libs"
+                assert cpp_info.location, "Package has exe and no location"
+                target_name = self._cmakedeps.get_property("cmake_target_name", self._conanfile)
+                target = target_name or f"{pkg_name}::{pkg_name}"
+                exe_location = self._path(cpp_info.location, pkg_folder, pkg_folder_var)
+                exes[target] = exe_location
+
+        return exes
+
+    def _get_dependencies(self):
+        """ transitive dependencies Filenames for find_dependency()
+        """
+        # Build requires are already filtered by the get_transitive_requires
+        transitive_reqs = self._cmakedeps.get_transitive_requires(self._conanfile)
+        # FIXME: Hardcoded CONFIG
+        ret = {self._cmakedeps.get_cmake_filename(r): "CONFIG" for r in transitive_reqs.values()}
+        return ret
+
+    @staticmethod
+    def _path(p, pkg_folder, pkg_folder_var):
+        def escape(p_):
+            return p_.replace("$", "\\$").replace('"', '\\"')
+
+        p = p.replace("\\", "/")
+        if os.path.isabs(p):
+            if p.startswith(pkg_folder):
+                rel = p[len(pkg_folder):].lstrip("/")
+                return f"${{{pkg_folder_var}}}/{escape(rel)}"
+            return escape(p)
+        return f"${{{pkg_folder_var}}}/{escape(p)}"
+
+    @staticmethod
+    def _escape_cmake_string(values):
+        return " ".join(v.replace("\\", "\\\\").replace('$', '\\$').replace('"', '\\"')
+                        for v in values)
+
+    @property
+    def _template(self):
+        # TODO: Check why not set_property instead of target_link_libraries
+        return textwrap.dedent("""\
+        {%- macro config_wrapper(config, value) -%}
+             {% if config -%}
+             $<$<CONFIG:{{config}}>:{{value}}>
+             {%- else -%}
+             {{value}}
+             {%- endif %}
+        {%- endmacro -%}
+        set({{pkg_folder_var}} "{{pkg_folder}}")
+
+        # Dependencies finding
+        include(CMakeFindDependencyMacro)
+
+        {% for dep, dep_find_mode in dependencies.items() %}
+        if(NOT {{dep}}_FOUND)
+            find_dependency({{dep}} REQUIRED {{dep_find_mode}})
+        endif()
+        {% endfor %}
+
+        ################# Libs information ##############
+        {% for lib, lib_info in libs.items() %}
+        #################### {{lib}} ####################
+        if(NOT TARGET {{ lib }})
+            message(STATUS "Conan: Target declared imported {{lib_info["type"]}} library '{{lib}}'")
+            add_library({{lib}} {{lib_info["type"]}} IMPORTED)
+        endif()
+        {% if lib_info.get("includedirs") %}
+        set_property(TARGET {{lib}} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+                     {{config_wrapper(config, lib_info["includedirs"])}})
+        {% endif %}
+        {% if lib_info.get("defines") %}
+        set_property(TARGET {{lib}} APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS
+                     {{config_wrapper(config, lib_info["defines"])}})
+        {% endif %}
+        {% if lib_info.get("cxxflags") %}
+        set_property(TARGET {{lib}} APPEND PROPERTY INTERFACE_COMPILE_OPTIONS
+                     $<$<COMPILE_LANGUAGE:CXX>:{{config_wrapper(config, lib_info["cxxflags"])}}>)
+        {% endif %}
+        {% if lib_info.get("cflags") %}
+        set_property(TARGET {{lib}} APPEND PROPERTY INTERFACE_COMPILE_OPTIONS
+                     $<$<COMPILE_LANGUAGE:C>:{{config_wrapper(config, lib_info["cflags"])}}>)
+        {% endif %}
+        {% if lib_info.get("sharedlinkflags") %}
+        {% set linkflags = config_wrapper(config, lib_info["sharedlinkflags"]) %}
+        set_property(TARGET {{lib}} APPEND PROPERTY INTERFACE_LINK_OPTIONS
+                     "$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>:{{linkflags}}>"
+                     "$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,MODULE_LIBRARY>:{{linkflags}}>")
+        {% endif %}
+        {% if lib_info.get("exelinkflags") %}
+        {% set exeflags = config_wrapper(config, lib_info["exelinkflags"]) %}
+        set_property(TARGET {{lib}} APPEND PROPERTY INTERFACE_LINK_OPTIONS
+                     "$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:{{exeflags}}>")
+        {% endif %}
+
+        {% if lib_info.get("link_languages") %}
+        get_property(_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
+        {% for lang in lib_info["link_languages"] %}
+        if(NOT "{{lang}}" IN_LIST _languages)
+            message(SEND_ERROR
+                    "Target {{lib}} has {{lang}} linkage but {{lang}} not enabled in project()")
+        endif()
+        set_property(TARGET {{lib}} APPEND PROPERTY
+                     IMPORTED_LINK_INTERFACE_LANGUAGES_{{config}} {{lang}})
+        {% endfor %}
+        {% endif %}
+        {% if lib_info.get("location") %}
+        set_property(TARGET {{lib}} APPEND PROPERTY IMPORTED_CONFIGURATIONS {{config}})
+        set_target_properties({{lib}} PROPERTIES IMPORTED_LOCATION_{{config}}
+                              "{{lib_info["location"]}}")
+        {% endif %}
+        {% if lib_info.get("link_location") %}
+        set_target_properties({{lib}} PROPERTIES IMPORTED_IMPLIB_{{config}}
+                              "{{lib_info["link_location"]}}")
+        {% endif %}
+        {% if lib_info.get("requires") %}
+        target_link_libraries({{lib}} INTERFACE {{lib_info["requires"]}})
+        {% endif %}
+        {% if lib_info.get("system_libs") %}
+        target_link_libraries({{lib}} INTERFACE {{lib_info["system_libs"]}})
+        {% endif %}
+
+        {% endfor %}
+
+        ################# Global variables for try compile and legacy ##############
+        {% for prefix in additional_variables_prefixes %}
+        set({{ prefix }}_VERSION_STRING "{{ version }}")
+        {% if include_dirs is not none %}
+        set({{ prefix }}_INCLUDE_DIRS "{{ include_dirs }}" )
+        set({{ prefix }}_INCLUDE_DIR "{{ include_dirs }}" )
+        {% endif %}
+        {% if libraries is not none %}
+        set({{ prefix }}_LIBRARIES {{ libraries }} )
+        {% endif %}
+        {% if definitions is not none %}
+        set({{ prefix }}_DEFINITIONS {{ definitions}} )
+        {% endif %}
+        {% endfor %}
+
+        ################# Exes information ##############
+        {% for exe, location in exes.items() %}
+        #################### {{exe}} ####################
+        if(NOT TARGET {{ exe }})
+            message(STATUS "Conan: Target declared imported executable '{{exe}}' {{context}}")
+            add_executable({{exe}} IMPORTED)
+        else()
+            get_property(_context TARGET {{exe}} PROPERTY CONAN_CONTEXT)
+            if(NOT $${_context} STREQUAL "{{context}}")
+                message(STATUS "Conan: Exe {{exe}} was already defined in ${_context}")
+                get_property(_configurations TARGET {{exe}} PROPERTY IMPORTED_CONFIGURATIONS)
+                message(STATUS "Conan: Exe {{exe}} defined configurations: ${_configurations}")
+                foreach(_config ${_configurations})
+                    set_property(TARGET {{exe}} PROPERTY IMPORTED_LOCATION_${_config})
+                endforeach()
+                set_property(TARGET {{exe}} PROPERTY IMPORTED_CONFIGURATIONS)
+            endif()
+        endif()
+        set_property(TARGET {{exe}} APPEND PROPERTY IMPORTED_CONFIGURATIONS {{config}})
+        set_target_properties({{exe}} PROPERTIES IMPORTED_LOCATION_{{config}} "{{location}}")
+        set_property(TARGET {{exe}} PROPERTY CONAN_CONTEXT "{{context}}")
+        {% endfor %}
+        """)
diff --git a/conan/tools/cmake/cmakedeps2/targets.py b/conan/tools/cmake/cmakedeps2/targets.py
new file mode 100644
index 000000000..2b934f825
--- /dev/null
+++ b/conan/tools/cmake/cmakedeps2/targets.py
@@ -0,0 +1,47 @@
+import textwrap
+
+import jinja2
+from jinja2 import Template
+
+
+class TargetsTemplate2:
+    """
+    FooTargets.cmake
+    """
+    def __init__(self, cmakedeps, conanfile):
+        self._cmakedeps = cmakedeps
+        self._conanfile = conanfile
+
+    def content(self):
+        t = Template(self._template, trim_blocks=True, lstrip_blocks=True,
+                     undefined=jinja2.StrictUndefined)
+        return t.render(self._context)
+
+    @property
+    def filename(self):
+        f = self._cmakedeps.get_cmake_filename(self._conanfile)
+        return f"{f}Targets.cmake"
+
+    @property
+    def _context(self):
+        filename = self._cmakedeps.get_cmake_filename(self._conanfile)
+        ret = {"ref": str(self._conanfile.ref),
+               "filename": filename}
+        return ret
+
+    @property
+    def _template(self):
+        return textwrap.dedent("""\
+            message(STATUS "Configuring Targets for {{ ref }}")
+
+            # Load information for each installed configuration.
+            file(GLOB _target_files "${CMAKE_CURRENT_LIST_DIR}/{{filename}}-Targets-*.cmake")
+            foreach(_target_file IN LISTS _target_files)
+              include("${_target_file}")
+            endforeach()
+
+            file(GLOB _build_files "${CMAKE_CURRENT_LIST_DIR}/{{filename}}-TargetsBuild-*.cmake")
+            foreach(_build_file IN LISTS _build_files)
+              include("${_build_file}")
+            endforeach()
+            """)
diff --git a/conan/tools/cmake/toolchain/blocks.py b/conan/tools/cmake/toolchain/blocks.py
index ca8a85e38..e19b113a9 100644
--- a/conan/tools/cmake/toolchain/blocks.py
+++ b/conan/tools/cmake/toolchain/blocks.py
@@ -520,6 +520,10 @@ class AppleSystemBlock(Block):
 class FindFiles(Block):
     template = textwrap.dedent("""\
         # Define paths to find packages, programs, libraries, etc.
+        if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/conan_cmakedeps_paths.cmake")
+          message(STATUS "Conan toolchain: Including CMakeDeps generated conan_find_paths.cmake")
+          include("${CMAKE_CURRENT_LIST_DIR}/conan_cmakedeps_paths.cmake")
+        else()
 
         {% if find_package_prefer_config %}
         set(CMAKE_FIND_PACKAGE_PREFER_CONFIG {{ find_package_prefer_config }})
@@ -578,6 +582,7 @@ class FindFiles(Block):
             set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE "BOTH")
         endif()
         {% endif %}
+        endif()
     """)
 
     def _runtime_dirs_value(self, dirs):
diff --git a/conans/model/build_info.py b/conans/model/build_info.py
index 4505075e6..4b4ef9f33 100644
--- a/conans/model/build_info.py
+++ b/conans/model/build_info.py
@@ -79,6 +79,8 @@ class _Component:
         self._sharedlinkflags = None  # linker flags
         self._exelinkflags = None  # linker flags
         self._objects = None  # linker flags
+        self._exe = None  # application executable, only 1 allowed, following CPS
+        self._languages = None
 
         self._sysroot = None
         self._requires = None
@@ -119,9 +121,11 @@ class _Component:
             "sysroot": self._sysroot,
             "requires": self._requires,
             "properties": self._properties,
+            "exe": self._exe,  # single exe, incompatible with libs
             "type": self._type,
             "location": self._location,
-            "link_location": self._link_location
+            "link_location": self._link_location,
+            "languages": self._languages
         }
 
     @staticmethod
@@ -131,6 +135,14 @@ class _Component:
             setattr(result, f"_{field}", value)
         return result
 
+    def clone(self):
+        # Necessary below for exploding a cpp_info.libs = [lib1, lib2] into components
+        result = _Component()
+        for k, v in vars(self).items():
+            if k.startswith("_"):
+                setattr(result, k, copy.copy(v))
+        return result
+
     @property
     def includedirs(self):
         if self._includedirs is None:
@@ -258,6 +270,14 @@ class _Component:
     def libs(self, value):
         self._libs = value
 
+    @property
+    def exe(self):
+        return self._exe
+
+    @exe.setter
+    def exe(self, value):
+        self._exe = value
+
     @property
     def type(self):
         return self._type
@@ -282,6 +302,14 @@ class _Component:
     def link_location(self, value):
         self._link_location = value
 
+    @property
+    def languages(self):
+        return self._languages
+
+    @languages.setter
+    def languages(self, value):
+        self._languages = value
+
     @property
     def defines(self):
         if self._defines is None:
@@ -453,7 +481,9 @@ class _Component:
     def parsed_requires(self):
         return [r.split("::", 1) if "::" in r else (None, r) for r in self.requires]
 
-    def deduce_cps(self, pkg_type):
+    def deduce_locations(self, pkg_type):
+        if self._exe:   # exe is a new field, it should have the correct location
+            return
         if self._location or self._link_location:
             if self._type is None or self._type is PackageType.HEADER:
                 raise ConanException("Incorrect cpp_info defining location without type or header")
@@ -461,13 +491,16 @@ class _Component:
         if self._type not in [None, PackageType.SHARED, PackageType.STATIC, PackageType.APP]:
             return
 
-        # Recipe didn't specify things, need to auto deduce
-        libdirs = [x.replace("\\", "/") for x in self.libdirs]
-        bindirs = [x.replace("\\", "/") for x in self.bindirs]
+        if len(self.libs) == 0:
+            return
 
         if len(self.libs) != 1:
             raise ConanException("More than 1 library defined in cpp_info.libs, cannot deduce CPS")
 
+        # Recipe didn't specify things, need to auto deduce
+        libdirs = [x.replace("\\", "/") for x in self.libdirs]
+        bindirs = [x.replace("\\", "/") for x in self.bindirs]
+
         # TODO: Do a better handling of pre-defined type
         libname = self.libs[0]
         static_patterns = [f"{libname}.lib", f"{libname}.a", f"lib{libname}.a"]
@@ -519,6 +552,7 @@ class CppInfo:
 
     def __init__(self, set_defaults=False):
         self.components = defaultdict(lambda: _Component(set_defaults))
+        self.default_components = None
         self._package = _Component(set_defaults)
 
     def __getattr__(self, attr):
@@ -526,19 +560,22 @@ class CppInfo:
         return getattr(self._package, attr)
 
     def __setattr__(self, attr, value):
-        if attr in ("components", "_package", "_aggregated"):
+        if attr in ("components", "default_components", "_package", "_aggregated"):
             super(CppInfo, self).__setattr__(attr, value)
         else:
             setattr(self._package, attr, value)
 
     def serialize(self):
         ret = {"root": self._package.serialize()}
+        if self.default_components:
+            ret["default_components"] = self.default_components
         for component_name, info in self.components.items():
             ret[component_name] = info.serialize()
         return ret
 
     def deserialize(self, content):
         self._package = _Component.deserialize(content.pop("root"))
+        self.default_components = content.get("default_components")
         for component_name, info in content.items():
             self.components[component_name] = _Component.deserialize(info)
         return self
@@ -678,3 +715,37 @@ class CppInfo:
         # Then split the names
         ret = [r.split("::") if "::" in r else (None, r) for r in ret]
         return ret
+
+    def deduce_full_cpp_info(self, conanfile):
+        pkg_type = conanfile.package_type
+
+        result = CppInfo()  # clone it
+
+        if self.libs and len(self.libs) > 1:  # expand in multiple components
+            ConanOutput().warning(f"{conanfile}: The 'cpp_info.libs' contain more than 1 library. "
+                                  "Define 'cpp_info.components' instead.")
+            assert not self.components, f"{conanfile} cpp_info shouldn't have .libs and .components"
+            for lib in self.libs:
+                c = _Component()  # Do not do a full clone, we don't need the properties
+                c.type = self.type  # This should be a string
+                c.includedirs = self.includedirs
+                c.libdirs = self.libdirs
+                c.libs = [lib]
+                result.components[f"_{lib}"] = c
+
+            common = self._package.clone()
+            common.libs = []
+            common.type = str(PackageType.HEADER)  # the type of components is a string!
+            common.requires = list(result.components.keys()) + (self.requires or [])
+
+            result.components["_common"] = common
+        else:
+            result._package = self._package.clone()
+            result.default_components = self.default_components
+            result.components = {k: v.clone() for k, v in self.components.items()}
+
+        result._package.deduce_locations(pkg_type)
+        for comp in result.components.values():
+            comp.deduce_locations(pkg_type)
+
+        return result
diff --git a/conans/model/conf.py b/conans/model/conf.py
index cdbf0cb55..ebc41bc58 100644
--- a/conans/model/conf.py
+++ b/conans/model/conf.py
@@ -80,6 +80,7 @@ BUILT_IN_CONFS = {
     "tools.cmake.cmake_layout:build_folder": "(Experimental) Allow configuring the base folder of the build for local builds",
     "tools.cmake.cmake_layout:test_folder": "(Experimental) Allow configuring the base folder of the build for test_package",
     "tools.cmake:cmake_program": "Path to CMake executable",
+    "tools.cmake.cmakedeps:new": "Use the new CMakeDeps generator",
     "tools.cmake:install_strip": "Add --strip to cmake.install()",
     "tools.deployer:symlinks": "Set to False to disable deployers copying symlinks",
     "tools.files.download:retry": "Number of retries in case of failure when downloading",


Test patch:
diff --git a/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_new.py b/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_new.py
new file mode 100644
index 000000000..e2c3a84be
--- /dev/null
+++ b/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_new.py
@@ -0,0 +1,1104 @@
+import os
+import platform
+import re
+import textwrap
+
+import pytest
+
+from conan.test.assets.genconanfile import GenConanfile
+from conan.test.assets.sources import gen_function_h, gen_function_cpp
+from conan.test.utils.tools import TestClient
+
+
+new_value = "will_break_next"
+
+
+@pytest.mark.tool("cmake")
+class TestExes:
+    @pytest.mark.parametrize("tool_requires", [False, True])
+    def test_exe(self, tool_requires):
+        conanfile = textwrap.dedent(r"""
+            import os
+            from conan import ConanFile
+            from conan.tools.cmake import CMake
+
+            class Test(ConanFile):
+                name = "mytool"
+                version = "0.1"
+                package_type = "application"
+                settings = "os", "arch", "compiler", "build_type"
+                generators = "CMakeToolchain"
+                exports_sources = "*"
+
+                def build(self):
+                    cmake = CMake(self)
+                    cmake.configure()
+                    cmake.build()
+
+                def package(self):
+                    cmake = CMake(self)
+                    cmake.install()
+
+                def package_info(self):
+                    self.cpp_info.exe = "mytool"
+                    self.cpp_info.set_property("cmake_target_name", "MyTool::myexe")
+                    self.cpp_info.location = os.path.join("bin", "mytool")
+            """)
+        main = textwrap.dedent("""
+            #include <iostream>
+            #include <fstream>
+
+            int main() {
+                std::cout << "Mytool generating out.c!!!!!" << std::endl;
+                std::ofstream f("out.c");
+            }
+            """)
+        c = TestClient()
+        c.run("new cmake_exe -d name=mytool -d version=0.1")
+        c.save({"conanfile.py": conanfile,
+                "src/main.cpp": main})
+        c.run("create .")
+
+        requires = "tool_requires" if tool_requires else "requires"
+        consumer = textwrap.dedent(f"""
+            from conan import ConanFile
+            from conan.tools.cmake import CMakeDeps, CMakeToolchain, CMake, cmake_layout
+            class Consumer(ConanFile):
+                settings = "os", "compiler", "arch", "build_type"
+                {requires} = "mytool/0.1"
+
+                def generate(self):
+                    deps = CMakeDeps(self)
+                    deps.generate()
+                    tc = CMakeToolchain(self)
+                    tc.generate()
+
+                def layout(self):
+                    cmake_layout(self)
+                def build(self):
+                    cmake = CMake(self)
+                    cmake.configure()
+                    cmake.build()
+            """)
+        cmake = textwrap.dedent("""
+            cmake_minimum_required(VERSION 3.15)
+            project(consumer C)
+
+            find_package(mytool)
+            add_custom_command(OUTPUT out.c COMMAND MyTool::myexe)
+            add_library(myLib out.c)
+            """)
+        c.save({"conanfile.py": consumer,
+                "CMakeLists.txt": cmake}, clean_first=True)
+        c.run(f"build . -c tools.cmake.cmakedeps:new={new_value}")
+        assert "Conan: Target declared imported executable 'MyTool::myexe'" in c.out
+        assert "Mytool generating out.c!!!!!" in c.out
+
+    def test_exe_components(self):
+        conanfile = textwrap.dedent(r"""
+            import os
+            from conan import ConanFile
+            from conan.tools.cmake import CMake
+
+            class Test(ConanFile):
+                name = "mytool"
+                version = "0.1"
+                package_type = "application"
+                settings = "os", "arch", "compiler", "build_type"
+                generators = "CMakeToolchain"
+                exports_sources = "*"
+
+                def build(self):
+                    cmake = CMake(self)
+                    cmake.configure()
+                    cmake.build()
+
+                def package(self):
+                    cmake = CMake(self)
+                    cmake.install()
+
+                def package_info(self):
+                    self.cpp_info.components["my1exe"].exe = "mytool1"
+                    self.cpp_info.components["my1exe"].set_property("cmake_target_name", "MyTool::my1exe")
+                    self.cpp_info.components["my1exe"].location = os.path.join("bin", "mytool1")
+                    self.cpp_info.components["my2exe"].exe = "mytool2"
+                    self.cpp_info.components["my2exe"].set_property("cmake_target_name", "MyTool::my2exe")
+                    self.cpp_info.components["my2exe"].location = os.path.join("bin", "mytool2")
+            """)
+        main = textwrap.dedent("""
+            #include <iostream>
+            #include <fstream>
+
+            int main() {{
+                std::cout << "Mytool{number} generating out{number}.c!!!!!" << std::endl;
+                std::ofstream f("out{number}.c");
+            }}
+            """)
+        cmake = textwrap.dedent("""
+            set(CMAKE_CXX_COMPILER_WORKS 1)
+            set(CMAKE_CXX_ABI_COMPILED 1)
+            cmake_minimum_required(VERSION 3.15)
+            project(proj CXX)
+
+            add_executable(mytool1 src/main1.cpp)
+            add_executable(mytool2 src/main2.cpp)
+
+            install(TARGETS mytool1 DESTINATION "." RUNTIME DESTINATION bin)
+            install(TARGETS mytool2 DESTINATION "." RUNTIME DESTINATION bin)
+            """)
+        c = TestClient()
+        c.save({"conanfile.py": conanfile,
+                "CMakeLists.txt": cmake,
+                "src/main1.cpp": main.format(number=1),
+                "src/main2.cpp": main.format(number=2)
+                })
+        c.run("create .")
+
+        consumer = textwrap.dedent("""
+            from conan import ConanFile
+            from conan.tools.cmake import CMakeDeps, CMakeToolchain, CMake, cmake_layout
+            class Consumer(ConanFile):
+                settings = "os", "compiler", "arch", "build_type"
+                tool_requires = "mytool/0.1"
+
+                def generate(self):
+                    deps = CMakeDeps(self)
+                    deps.generate()
+                    tc = CMakeToolchain(self)
+                    tc.generate()
+                def layout(self):
+                    cmake_layout(self)
+                def build(self):
+                    cmake = CMake(self)
+                    cmake.configure()
+                    cmake.build()
+            """)
+        cmake = textwrap.dedent("""
+            cmake_minimum_required(VERSION 3.15)
+            project(consumer C)
+
+            find_package(mytool)
+            add_custom_command(OUTPUT out1.c COMMAND MyTool::my1exe)
+            add_custom_command(OUTPUT out2.c COMMAND MyTool::my2exe)
+            add_library(myLib out1.c out2.c)
+            """)
+        c.save({"conanfile.py": consumer,
+                "CMakeLists.txt": cmake}, clean_first=True)
+        c.run(f"build . -c tools.cmake.cmakedeps:new={new_value}")
+        assert "Conan: Target declared imported executable 'MyTool::my1exe'" in c.out
+        assert "Mytool1 generating out1.c!!!!!" in c.out
+        assert "Conan: Target declared imported executable 'MyTool::my2exe'" in c.out
+        assert "Mytool2 generating out2.c!!!!!" in c.out
+
+
+@pytest.mark.tool("cmake")
+class TestLibs:
+    def test_libs(self, matrix_client):
+        c = matrix_client
+        c.run("new cmake_lib -d name=app -d version=0.1 -d requires=matrix/1.0")
+        c.run(f"build . -c tools.cmake.cmakedeps:new={new_value}")
+        assert "Conan: Target declared imported STATIC library 'matrix::matrix'" in c.out
+
+    @pytest.mark.parametrize("shared", [False, True])
+    def test_libs_transitive(self, transitive_libraries, shared):
+        c = transitive_libraries
+        c.run("new cmake_lib -d name=app -d version=0.1 -d requires=engine/1.0")
+        shared = "-o engine/*:shared=True" if shared else ""
+        c.run(f"build . {shared} -c tools.cmake.cmakedeps:new={new_value}")
+        if shared:
+            assert "matrix::matrix" not in c.out  # It is hidden as static behind the engine
+            assert "Conan: Target declared imported SHARED library 'engine::engine'" in c.out
+        else:
+            assert "Conan: Target declared imported STATIC library 'matrix::matrix'" in c.out
+            assert "Conan: Target declared imported STATIC library 'engine::engine'" in c.out
+
+    def test_multilevel_shared(self):
+        # TODO: make this shared fixtures in conftest for multi-level shared testing
+        c = TestClient(default_server_user=True)
+        c.run("new cmake_lib -d name=matrix -d version=0.1")
+        c.run(f"create . -o *:shared=True -c tools.cmake.cmakedeps:new={new_value}")
+
+        c.save({}, clean_first=True)
+        c.run("new cmake_lib -d name=engine -d version=0.1 -d requires=matrix/0.1")
+        c.run(f"create . -o *:shared=True -c tools.cmake.cmakedeps:new={new_value}")
+
+        c.save({}, clean_first=True)
+        c.run("new cmake_lib -d name=gamelib -d version=0.1 -d requires=engine/0.1")
+        c.run(f"create . -o *:shared=True -c tools.cmake.cmakedeps:new={new_value}")
+
+        c.save({}, clean_first=True)
+        c.run("new cmake_exe -d name=game -d version=0.1 -d requires=gamelib/0.1")
+        c.run(f"create . -o *:shared=True -c tools.cmake.cmakedeps:new={new_value}")
+
+        assert "matrix/0.1: Hello World Release!"
+        assert "engine/0.1: Hello World Release!"
+        assert "gamelib/0.1: Hello World Release!"
+        assert "game/0.1: Hello World Release!"
+
+        # Make sure it works downloading to another cache
+        c.run("upload * -r=default -c")
+        c.run("remove * -c")
+
+        c2 = TestClient(servers=c.servers)
+        c2.run("new cmake_exe -d name=game -d version=0.1 -d requires=gamelib/0.1")
+        c2.run(f"create . -o *:shared=True -c tools.cmake.cmakedeps:new={new_value}")
+
+        assert "matrix/0.1: Hello World Release!"
+        assert "engine/0.1: Hello World Release!"
+        assert "gamelib/0.1: Hello World Release!"
+        assert "game/0.1: Hello World Release!"
+
+
+class TestLibsLinkageTraits:
+    def test_linkage_shared_static(self):
+        """
+        the static library is skipped
+        """
+        c = TestClient()
+        c.run("new cmake_lib -d name=matrix -d version=0.1")
+        c.run(f"create . -c tools.cmake.cmakedeps:new={new_value} -tf=")
+
+        c.save({}, clean_first=True)
+        c.run("new cmake_lib -d name=engine -d version=0.1 -d requires=matrix/0.1")
+        c.run(f"create . -o engine/*:shared=True -c tools.cmake.cmakedeps:new={new_value} -tf=")
+
+        c.save({}, clean_first=True)
+        c.run("new cmake_exe -d name=game -d version=0.1 -d requires=engine/0.1")
+        c.run(f"create . -o engine/*:shared=True -c tools.cmake.cmakedeps:new={new_value} "
+              "-c tools.compilation:verbosity=verbose")
+        assert re.search(r"Skipped binaries(\s*)matrix/0.1", c.out)
+        assert "matrix/0.1: Hello World Release!"
+        assert "engine/0.1: Hello World Release!"
+        assert "game/0.1: Hello World Release!"
+
+
+@pytest.mark.tool("cmake")
+class TestLibsComponents:
+    def test_libs_components(self, matrix_client_components):
+        """
+        explicit usage of components
+        """
+        c = matrix_client_components
+
+        # TODO: Check that find_package(.. COMPONENTS nonexisting) fails
+        c.run("new cmake_exe -d name=app -d version=0.1 -d requires=matrix/1.0")
+        cmake = textwrap.dedent("""
+            cmake_minimum_required(VERSION 3.15)
+            project(app CXX)
+
+            find_package(matrix CONFIG REQUIRED)
+            add_executable(app src/app.cpp)
+            # standard one, and a custom cmake_target_name one
+            target_link_libraries(app PRIVATE matrix::module MatrixHeaders)
+            """)
+        app_cpp = textwrap.dedent("""
+            #include "module.h"
+            #include "headers.h"
+            int main() { module(); headers();}
+            """)
+        c.save({"CMakeLists.txt": cmake,
+                "src/app.cpp": app_cpp})
+        c.run(f"build . -c tools.cmake.cmakedeps:new={new_value}")
+        assert "Conan: Target declared imported STATIC library 'matrix::vector'" in c.out
+        assert "Conan: Target declared imported STATIC library 'matrix::module'" in c.out
+        if platform.system() == "Windows":
+            c.run_command(r".\build\Release\app.exe")
+            assert "Matrix headers __cplusplus: __cplusplus2014" in c.out
+
+    def test_libs_components_default(self, matrix_client_components):
+        """
+        Test that the default components are used when no component is specified
+        """
+        c = matrix_client_components
+
+        c.run("new cmake_exe -d name=app -d version=0.1 -d requires=matrix/1.0")
+
+        app_cpp = textwrap.dedent("""
+            #include "module.h"
+            int main() { module();}
+            """)
+        cmake = textwrap.dedent("""
+            cmake_minimum_required(VERSION 3.15)
+            project(app CXX)
+
+            find_package(matrix CONFIG REQUIRED)
+            add_executable(app src/app.cpp)
+            target_link_libraries(app PRIVATE matrix::matrix)
+            """)
+        c.save({"src/app.cpp": app_cpp,
+                "CMakeLists.txt": cmake})
+        c.run(f"build . -c tools.cmake.cmakedeps:new={new_value}")
+        assert "Conan: Target declared imported STATIC library 'matrix::vector'" in c.out
+        assert "Conan: Target declared imported STATIC library 'matrix::module'" in c.out
+        assert "Conan: Target declared imported INTERFACE library 'MatrixHeaders'" in c.out
+
+    def test_libs_components_default_error(self, matrix_client_components):
+        """
+        Same as above, but it fails, because headers is not in the default components
+        """
+        c = matrix_client_components
+
+        c.run("new cmake_exe -d name=app -d version=0.1 -d requires=matrix/1.0")
+
+        app_cpp = textwrap.dedent("""
+            #include "module.h"
+            #include "headers.h"
+            int main() { module();}
+            """)
+        cmake = textwrap.dedent("""
+            cmake_minimum_required(VERSION 3.15)
+            project(app CXX)
+
+            find_package(matrix CONFIG REQUIRED)
+            add_executable(app src/app.cpp)
+            target_link_libraries(app PRIVATE matrix::matrix)
+            """)
+        c.save({"src/app.cpp": app_cpp,
+                "CMakeLists.txt": cmake})
+        c.run(f"build . -c tools.cmake.cmakedeps:new={new_value}", assert_error=True)
+        assert "Error in build() method, line 35" in c.out
+        assert "Conan: Target declared imported STATIC library 'matrix::vector'" in c.out
+        assert "Conan: Target declared imported STATIC library 'matrix::module'" in c.out
+        cmake = textwrap.dedent("""
+            cmake_minimum_required(VERSION 3.15)
+            project(app CXX)
+
+            find_package(matrix CONFIG REQUIRED)
+            add_executable(app src/app.cpp)
+            target_link_libraries(app PRIVATE matrix::matrix MatrixHeaders)
+            """)
+        c.save({"CMakeLists.txt": cmake})
+        c.run(f"build . -c tools.cmake.cmakedeps:new={new_value}")
+        assert "Running CMake.build()" in c.out  # Now it doesn't fail
+
+    def test_libs_components_transitive(self, matrix_client_components):
+        """
+        explicit usage of components
+        matrix::module -> matrix::vector
+
+        engine::bots -> engine::physix
+        engine::physix -> matrix::vector
+        engine::world -> engine::physix, matrix::module
+        """
+        c = matrix_client_components
+
+        from conan.test.assets.sources import gen_function_h
+        bots_h = gen_function_h(name="bots")
+        from conan.test.assets.sources import gen_function_cpp
+        bots_cpp = gen_function_cpp(name="bots", includes=["bots", "physix"], calls=["physix"])
+        physix_h = gen_function_h(name="physix")
+        physix_cpp = gen_function_cpp(name="physix", includes=["physix", "vector"], calls=["vector"])
+        world_h = gen_function_h(name="world")
+        world_cpp = gen_function_cpp(name="world", includes=["world", "physix", "module"],
+                                     calls=["physix", "module"])
+
+        conanfile = textwrap.dedent("""
+            from conan import ConanFile
+            from conan.tools.cmake import CMake
+            from conan.tools.files import copy
+
+            class Engine(ConanFile):
+              name = "engine"
+              version = "1.0"
+              settings = "os", "compiler", "build_type", "arch"
+              generators = "CMakeToolchain"
+              exports_sources = "src/*", "CMakeLists.txt"
+
+              requires = "matrix/1.0"
+              generators = "CMakeDeps", "CMakeToolchain"
+
+              def build(self):
+                  cmake = CMake(self)
+                  cmake.configure()
+                  cmake.build()
+
+              def package(self):
+                  cmake = CMake(self)
+                  cmake.install()
+
+              def package_info(self):
+                  self.cpp_info.components["bots"].libs = ["bots"]
+                  self.cpp_info.components["bots"].includedirs = ["include"]
+                  self.cpp_info.components["bots"].libdirs = ["lib"]
+                  self.cpp_info.components["bots"].requires = ["physix"]
+
+                  self.cpp_info.components["physix"].libs = ["physix"]
+                  self.cpp_info.components["physix"].includedirs = ["include"]
+                  self.cpp_info.components["physix"].libdirs = ["lib"]
+                  self.cpp_info.components["physix"].requires = ["matrix::vector"]
+
+                  self.cpp_info.components["world"].libs = ["world"]
+                  self.cpp_info.components["world"].includedirs = ["include"]
+                  self.cpp_info.components["world"].libdirs = ["lib"]
+                  self.cpp_info.components["world"].requires = ["physix", "matrix::module"]
+                  """)
+
+        cmakelists = textwrap.dedent("""
+               set(CMAKE_CXX_COMPILER_WORKS 1)
+               set(CMAKE_CXX_ABI_COMPILED 1)
+               cmake_minimum_required(VERSION 3.15)
+               project(matrix CXX)
+
+               find_package(matrix CONFIG REQUIRED)
+
+               add_library(physix src/physix.cpp)
+               add_library(bots src/bots.cpp)
+               add_library(world src/world.cpp)
+
+               target_link_libraries(physix PRIVATE matrix::vector)
+               target_link_libraries(bots PRIVATE physix)
+               target_link_libraries(world PRIVATE physix matrix::module)
+
+               set_target_properties(bots PROPERTIES PUBLIC_HEADER "src/bots.h")
+               set_target_properties(physix PROPERTIES PUBLIC_HEADER "src/physix.h")
+               set_target_properties(world PROPERTIES PUBLIC_HEADER "src/world.h")
+               install(TARGETS physix bots world)
+               """)
+        c.save({"src/physix.h": physix_h,
+                "src/physix.cpp": physix_cpp,
+                "src/bots.h": bots_h,
+                "src/bots.cpp": bots_cpp,
+                "src/world.h": world_h,
+                "src/world.cpp": world_cpp,
+                "CMakeLists.txt": cmakelists,
+                "conanfile.py": conanfile})
+        c.run("create .")
+
+        c.save({}, clean_first=True)
+        c.run("new cmake_exe -d name=app -d version=0.1 -d requires=engine/1.0")
+        cmake = textwrap.dedent("""
+            cmake_minimum_required(VERSION 3.15)
+            project(app CXX)
+
+            find_package(engine CONFIG REQUIRED)
+
+            add_executable(app src/app.cpp)
+            target_link_libraries(app PRIVATE engine::bots)
+
+            install(TARGETS app)
+            """)
+        app_cpp = textwrap.dedent("""
+            #include "bots.h"
+            int main() { bots();}
+            """)
+        c.save({"CMakeLists.txt": cmake,
+                "src/app.cpp": app_cpp})
+        c.run(f"create . -c tools.cmake.cmakedeps:new={new_value}")
+        assert "Conan: Target declared imported STATIC library 'matrix::vector'" in c.out
+        assert "Conan: Target declared imported STATIC library 'matrix::module'" in c.out
+        assert "Conan: Target declared imported INTERFACE library 'matrix::matrix'" in c.out
+        assert "Conan: Target declared imported STATIC library 'engine::bots'" in c.out
+        assert "Conan: Target declared imported STATIC library 'engine::physix'" in c.out
+        assert "Conan: Target declared imported STATIC library 'engine::world'" in c.out
+        assert "Conan: Target declared imported INTERFACE library 'engine::engine'" in c.out
+
+        assert "bots: Release!" in c.out
+        assert "physix: Release!" in c.out
+        assert "vector: Release!" in c.out
+
+    def test_libs_components_multilib(self):
+        """
+        cpp_info.libs = ["lib1", "lib2"]
+        """
+        c = TestClient()
+
+        from conan.test.assets.sources import gen_function_h
+        vector_h = gen_function_h(name="vector")
+        from conan.test.assets.sources import gen_function_cpp
+        vector_cpp = gen_function_cpp(name="vector", includes=["vector"])
+        module_h = gen_function_h(name="module")
+        module_cpp = gen_function_cpp(name="module", includes=["module"])
+
+        conanfile = textwrap.dedent("""
+            from conan import ConanFile
+            from conan.tools.cmake import CMake
+
+            class Matrix(ConanFile):
+                name = "matrix"
+                version = "1.0"
+                settings = "os", "compiler", "build_type", "arch"
+                generators = "CMakeToolchain"
+                exports_sources = "src/*", "CMakeLists.txt"
+
+                generators = "CMakeDeps", "CMakeToolchain"
+
+                def build(self):
+                    cmake = CMake(self)
+                    cmake.configure()
+                    cmake.build()
+
+                def package(self):
+                    cmake = CMake(self)
+                    cmake.install()
+
+                def package_info(self):
+                    self.cpp_info.set_property("cmake_target_name", "MyMatrix::MyMatrix")
+                    self.cpp_info.libs = ["module", "vector"]
+                  """)
+
+        cmakelists = textwrap.dedent("""
+            set(CMAKE_CXX_COMPILER_WORKS 1)
+            set(CMAKE_CXX_ABI_COMPILED 1)
+            cmake_minimum_required(VERSION 3.15)
+            project(matrix CXX)
+
+            add_library(module src/module.cpp)
+            add_library(vector src/vector.cpp)
+
+            set_target_properties(vector PROPERTIES PUBLIC_HEADER "src/vector.h")
+            set_target_properties(module PROPERTIES PUBLIC_HEADER "src/module.h")
+            install(TARGETS module vector)
+            """)
+        c.save({"src/module.h": module_h,
+                "src/module.cpp": module_cpp,
+                "src/vector.h": vector_h,
+                "src/vector.cpp": vector_cpp,
+                "CMakeLists.txt": cmakelists,
+                "conanfile.py": conanfile})
+        c.run("create .")
+
+        c.save({}, clean_first=True)
+        c.run("new cmake_exe -d name=app -d version=0.1 -d requires=matrix/1.0")
+        cmake = textwrap.dedent("""
+            cmake_minimum_required(VERSION 3.15)
+            project(app CXX)
+
+            find_package(matrix CONFIG REQUIRED)
+
+            add_executable(app src/app.cpp)
+            target_link_libraries(app PRIVATE MyMatrix::MyMatrix)
+
+            install(TARGETS app)
+            """)
+        app_cpp = textwrap.dedent("""
+            #include "vector.h"
+            #include "module.h"
+            int main() { vector();module();}
+            """)
+        c.save({"CMakeLists.txt": cmake,
+                "src/app.cpp": app_cpp})
+        c.run(f"create . -c tools.cmake.cmakedeps:new={new_value}")
+        assert "Conan: Target declared imported STATIC library 'matrix::_vector'" in c.out
+        assert "Conan: Target declared imported STATIC library 'matrix::_module'" in c.out
+        assert "Conan: Target declared imported INTERFACE library 'MyMatrix::MyMatrix'" in c.out
+        assert "matrix::matrix" not in c.out
+
+        assert "vector: Release!" in c.out
+        assert "module: Release!" in c.out
+        assert "vector: Release!" in c.out
+
+
+@pytest.mark.tool("cmake")
+class TestHeaders:
+    def test_header_lib(self, matrix_client):
+        c = matrix_client
+        conanfile = textwrap.dedent("""
+            from conan import ConanFile
+            from conan.tools.files import copy
+            class EngineHeader(ConanFile):
+                name = "engine"
+                version = "1.0"
+                requires = "matrix/1.0"
+                exports_sources = "*.h"
+                settings = "compiler"
+                def package(self):
+                    copy(self, "*.h", src=self.source_folder, dst=self.package_folder)
+                def package_id(self):
+                    self.info.clear()
+                def package_info(self):
+                    self.cpp_info.defines = ["MY_MATRIX_HEADERS_DEFINE=1",
+                                             "MY_MATRIX_HEADERS_DEFINE2=1"]
+                    # Few flags to cover that CMakeDeps doesn't crash with them
+                    if self.settings.compiler == "msvc":
+                        self.cpp_info.cxxflags = ["/Zc:__cplusplus"]
+                        self.cpp_info.cflags = ["/Zc:__cplusplus"]
+                        self.cpp_info.system_libs = ["ws2_32"]
+                    else:
+                        self.cpp_info.system_libs = ["m", "dl"]
+                        # Just to verify CMake don't break
+                    if self.settings.compiler == "gcc":
+                        self.cpp_info.sharedlinkflags = ["-z now", "-z relro"]
+                        self.cpp_info.exelinkflags = ["-z now", "-z relro"]
+             """)
+        engine_h = textwrap.dedent("""
+            #pragma once
+            #include <iostream>
+            #include "matrix.h"
+            #ifndef MY_MATRIX_HEADERS_DEFINE
+            #error "Fatal error MY_MATRIX_HEADERS_DEFINE not defined"
+            #endif
+            #ifndef MY_MATRIX_HEADERS_DEFINE2
+            #error "Fatal error MY_MATRIX_HEADERS_DEFINE2 not defined"
+            #endif
+            void engine(){ std::cout << "Engine!" <<std::endl; matrix(); }
+            """)
+
+        c.save({"conanfile.py": conanfile,
+                "include/engine.h": engine_h})
+        c.run("create .")
+
+        app = textwrap.dedent("""
+            from conan import ConanFile
+            from conan.tools.cmake import CMake
+            class EngineHeader(ConanFile):
+                settings = "os", "compiler", "build_type", "arch"
+                requires = "engine/1.0"
+                generators = "CMakeDeps", "CMakeToolchain"
+                def build(self):
+                    cmake = CMake(self)
+                    cmake.configure()
+                    cmake.build()
+             """)
+        cmake = textwrap.dedent("""
+            cmake_minimum_required(VERSION 3.15)
+            project(app CXX)
+            find_package(engine CONFIG REQUIRED)
+            add_executable(app src/app.cpp)
+            target_link_libraries(app PRIVATE engine::engine)
+            """)
+        c.save({"conanfile.py": app,
+                "CMakeLists.txt": cmake,
+                "src/app.cpp": gen_function_cpp(name="main", includes=["engine"], calls=["engine"])},
+               clean_first=True)
+        c.run(f"build . -c tools.cmake.cmakedeps:new={new_value}")
+        assert "Conan: Target declared imported STATIC library 'matrix::matrix'" in c.out
+        assert "Conan: Target declared imported INTERFACE library 'engine::engine'" in c.out
+
+    @pytest.mark.skipif(platform.system() != "Windows", reason="Only windows")
+    def test_conditional_header(self):
+        conanfile = textwrap.dedent("""
+            from conan import ConanFile
+            from conan.tools.files import copy
+            class EngineHeader(ConanFile):
+                name = "engine"
+                exports_sources = "*.h"
+                def package(self):
+                    copy(self, "*.h", src=self.source_folder, dst=self.package_folder)
+                def package_info(self):
+                    self.cpp_info.defines = ["MY_MATRIX_HEADERS_{version}_DEFINE=1"]
+            """)
+        engine_h = textwrap.dedent("""
+            #pragma once
+            #include <iostream>
+
+            #ifndef MY_MATRIX_HEADERS_{version}_DEFINE
+            #error "Fatal error MY_MATRIX_HEADERS_{version}_DEFINE not defined"
+            #endif
+            void engine(){{ std::cout << "Engine {version}!" <<std::endl; }}
+            """)
+
+        c = TestClient()
+        c.save({"conanfile.py": conanfile.format(version="1_0"),
+                "include/engine.h": engine_h.format(version="1_0")})
+        c.run("create . --version=1_0")
+        c.save({"conanfile.py": conanfile.format(version="1_1"),
+                "include/engine.h": engine_h.format(version="1_1")})
+        c.run("create . --version=1_1")
+
+        app = textwrap.dedent("""
+            import os
+            from conan import ConanFile
+            from conan.tools.cmake import CMake, cmake_layout
+            class EngineHeader(ConanFile):
+                settings = "os", "compiler", "build_type", "arch"
+                generators = "CMakeDeps", "CMakeToolchain"
+                def requirements(self):
+                    v = "1_0" if self.settings.build_type == "Debug" else "1_1"
+                    self.requires(f"engine/{v}")
+                def layout(self):
+                    cmake_layout(self)
+                def build(self):
+                    cmake = CMake(self)
+                    cmake.configure()
+                    cmake.build()
+                    self.run(os.path.join(self.cpp.build.bindir, "app"))
+             """)
+        cmake = textwrap.dedent("""
+            cmake_minimum_required(VERSION 3.15)
+            project(app CXX)
+            find_package(engine CONFIG REQUIRED)
+            add_executable(app src/app.cpp)
+            target_link_libraries(app PRIVATE engine::engine)
+            """)
+        c.save({"conanfile.py": app,
+                "CMakeLists.txt": cmake,
+                "src/app.cpp": gen_function_cpp(name="main", includes=["engine"], calls=["engine"])},
+               clean_first=True)
+        c.run(f"build . -c tools.cmake.cmakedeps:new={new_value}")
+        assert "engine/1_1" in c.out
+        assert "engine/1_0" not in c.out
+        assert "Conan: Target declared imported INTERFACE library 'engine::engine'" in c.out
+        assert "Engine 1_1!" in c.out
+
+        c.run(f"build . -c tools.cmake.cmakedeps:new={new_value} -s build_type=Debug")
+        assert "engine/1_1" not in c.out
+        assert "engine/1_0" in c.out
+        assert "Conan: Target declared imported INTERFACE library 'engine::engine'" in c.out
+        assert "Engine 1_0!" in c.out
+
+
+class TestToolRequires:
+    def test_tool_requires(self):
+        """ tool-requires should not define the try-compile or global variables
+        for includedirs, libraries, definitions, otherwise the build-context would
+        override the host context"""
+        c = TestClient()
+        c.save({"tool/conanfile.py": GenConanfile("tool", "0.1"),
+                "pkg/conanfile.py": GenConanfile("pkg", "0.1").with_settings("build_type")
+                                                              .with_tool_requires("tool/0.1")})
+        c.run("create tool")
+        c.run(f"install pkg -g CMakeDeps -c tools.cmake.cmakedeps:new={new_value}")
+        tool_config = c.load("pkg/tool-config.cmake")
+        assert 'set(tool_INCLUDE_DIRS' not in tool_config
+        assert 'set(tool_INCLUDE_DIR' not in tool_config
+        assert 'set(tool_LIBRARIES' not in tool_config
+
+
+@pytest.mark.tool("cmake")
+@pytest.mark.parametrize("tool_requires", [True, False])
+def test_build_modules_custom_script(tool_requires):
+    """
+    it works both as a tool_requires and as a regular requirement
+    """
+    client = TestClient()
+    conanfile = textwrap.dedent("""
+        import os
+        from conan import ConanFile
+        from conan.tools.files import copy
+
+        class Conan(ConanFile):
+            name = "myfunctions"
+            version = "1.0"
+            exports_sources = ["*.cmake"]
+
+            def package(self):
+                copy(self, "*.cmake", self.source_folder, self.package_folder)
+
+            def package_info(self):
+                self.cpp_info.set_property("cmake_build_modules", ["myfunction.cmake"])
+        """)
+
+    myfunction = textwrap.dedent("""
+        function(myfunction)
+            message("Hello myfunction!!!!")
+        endfunction()
+        """)
+    client.save({"conanfile.py": conanfile, "myfunction.cmake": myfunction})
+    client.run("create .")
+
+    requires = "tool_requires" if tool_requires else "requires"
+    consumer = textwrap.dedent(f"""
+        from conan import ConanFile
+        from conan.tools.cmake import CMake
+
+        class Conan(ConanFile):
+            settings = "os", "compiler", "build_type", "arch"
+            generators = "CMakeToolchain", "CMakeDeps"
+            {requires} = "myfunctions/1.0"
+
+            def build(self):
+                cmake = CMake(self)
+                cmake.configure()
+        """)
+    cmakelists = textwrap.dedent("""
+        cmake_minimum_required(VERSION 3.15)
+        project(test)
+        find_package(myfunctions CONFIG REQUIRED)
+        myfunction()
+        """)
+    client.save({"conanfile.py": consumer,
+                 "CMakeLists.txt": cmakelists},
+                clean_first=True)
+    client.run(f"build . -c tools.cmake.cmakedeps:new={new_value}")
+    assert "Hello myfunction!!!!" in client.out
+
+
+@pytest.mark.tool("cmake")
+class TestProtobuf:
+
+    @pytest.fixture()
+    def protobuf(self):
+        conanfile = textwrap.dedent(r"""
+            import os
+            from conan import ConanFile
+            from conan.tools.cmake import CMake
+
+            class Protobuf(ConanFile):
+                name = "protobuf"
+                version = "0.1"
+                settings = "os", "arch", "compiler", "build_type"
+                options = {"shared": [True, False]}
+                default_options = {"shared": False}
+
+                generators = "CMakeToolchain"
+                exports_sources = "*"
+
+                def build(self):
+                    cmake = CMake(self)
+                    cmake.configure()
+                    cmake.build()
+
+                def package(self):
+                    cmake = CMake(self)
+                    cmake.install()
+
+                def package_info(self):
+                    self.cpp_info.set_property("cmake_file_name", "MyProtobuf")
+                    self.cpp_info.components["protobuf"].libs = ["protobuf"]
+                    self.cpp_info.components["protoc"].exe = "protoc"
+                    self.cpp_info.components["protoc"].set_property("cmake_target_name",
+                                                                    "Protobuf::Protocompile")
+                    self.cpp_info.components["protoc"].location = os.path.join("bin", "protoc")
+            """)
+        main = textwrap.dedent("""
+            #include <iostream>
+            #include <fstream>
+            #include "protobuf.h"
+
+            int main() {
+                protobuf();
+                #ifdef NDEBUG
+                std::cout << "Protoc RELEASE generating out.c!!!!!" << std::endl;
+                #else
+                std::cout << "Protoc DEBUG generating out.c!!!!!" << std::endl;
+                #endif
+                std::ofstream f("out.c");
+            }
+            """)
+        cmake = textwrap.dedent("""
+            cmake_minimum_required(VERSION 3.15)
+            project(protobuf CXX)
+
+            add_library(protobuf src/protobuf.cpp)
+            add_executable(protoc src/main.cpp)
+            target_link_libraries(protoc PRIVATE protobuf)
+            set_target_properties(protobuf PROPERTIES PUBLIC_HEADER "src/protobuf.h")
+
+            install(TARGETS protoc protobuf)
+            """)
+        c = TestClient()
+        c.save({"conanfile.py": conanfile,
+                "CMakeLists.txt": cmake,
+                "src/protobuf.h": gen_function_h(name="protobuf"),
+                "src/protobuf.cpp": gen_function_cpp(name="protobuf", includes=["protobuf"]),
+                "src/main.cpp": main})
+        c.run("export .")
+
+        consumer = textwrap.dedent("""
+            import os
+            from conan import ConanFile
+            from conan.tools.cmake import CMake, cmake_layout
+            class Consumer(ConanFile):
+                settings = "os", "compiler", "arch", "build_type"
+                requires = "protobuf/0.1"
+                generators = "CMakeToolchain", "CMakeDeps"
+
+                def layout(self):
+                    cmake_layout(self)
+                def build(self):
+                    cmake = CMake(self)
+                    cmake.configure()
+                    cmake.build()
+                    self.run(os.path.join(self.cpp.build.bindir, "myapp"))
+            """)
+        cmake = textwrap.dedent("""
+            cmake_minimum_required(VERSION 3.15)
+            project(consumer CXX)
+
+            find_package(MyProtobuf CONFIG REQUIRED)
+            add_custom_command(OUTPUT out.c COMMAND Protobuf::Protocompile)
+            add_executable(myapp myapp.cpp out.c)
+            target_link_libraries(myapp PRIVATE protobuf::protobuf)
+            get_target_property(imported_configs Protobuf::Protocompile IMPORTED_CONFIGURATIONS)
+            message(STATUS "Protoc imported configurations: ${imported_configs}!!!")
+            """)
+        myapp = textwrap.dedent("""
+            #include <iostream>
+            #include "protobuf.h"
+
+            int main() {
+                protobuf();
+                std::cout << "MyApp" << std::endl;
+            }
+            """)
+        c.save({"conanfile.py": consumer,
+                "CMakeLists.txt": cmake,
+                "myapp.cpp": myapp}, clean_first=True)
+        return c
+
+    def test_requires(self, protobuf):
+        c = protobuf
+        c.run(f"build . --build=missing -c tools.cmake.cmakedeps:new={new_value}")
+        assert "Conan: Target declared imported STATIC library 'protobuf::protobuf'" in c.out
+        assert "Conan: Target declared imported executable 'Protobuf::Protocompile'" in c.out
+        assert "Protoc RELEASE generating out.c!!!!!" in c.out
+        assert 'Protoc imported configurations: RELEASE!!!' in c.out
+
+    def test_both(self, protobuf):
+        consumer = textwrap.dedent("""
+            import os
+            from conan import ConanFile
+            from conan.tools.cmake import CMake, cmake_layout
+            class Consumer(ConanFile):
+                settings = "os", "compiler", "arch", "build_type"
+                requires = "protobuf/0.1"
+                tool_requires = "protobuf/0.1"
+                generators = "CMakeToolchain", "CMakeDeps"
+
+                def layout(self):
+                    cmake_layout(self)
+                def build(self):
+                    cmake = CMake(self)
+                    cmake.configure()
+                    cmake.build()
+            """)
+        c = protobuf
+        c.save({"conanfile.py": consumer})
+        c.run("build . -s:h build_type=Debug --build=missing "
+              f"-c tools.cmake.cmakedeps:new={new_value}")
+
+        assert "Conan: Target declared imported STATIC library 'protobuf::protobuf'" in c.out
+        assert "Conan: Target declared imported executable 'Protobuf::Protocompile'" in c.out
+        assert "Protoc RELEASE generating out.c!!!!!" in c.out
+        assert "protobuf: Release!" in c.out
+        assert "protobuf: Debug!" not in c.out
+        assert 'Protoc imported configurations: RELEASE!!!' in c.out
+
+        cmd = "./build/Debug/myapp" if platform.system() != "Windows" else r"build\Debug\myapp"
+        c.run_command(cmd)
+        assert "protobuf: Debug!" in c.out
+        assert "protobuf: Release!" not in c.out
+
+        c.run("build . --build=missing "
+              f"-c tools.cmake.cmakedeps:new={new_value}")
+
+        assert "Conan: Target declared imported STATIC library 'protobuf::protobuf'" in c.out
+        assert "Conan: Target declared imported executable 'Protobuf::Protocompile'" in c.out
+        assert "Protoc RELEASE generating out.c!!!!!" in c.out
+        assert "protobuf: Release!" in c.out
+        assert "protobuf: Debug!" not in c.out
+        assert 'Protoc imported configurations: RELEASE!!!' in c.out
+
+        cmd = "./build/Release/myapp" if platform.system() != "Windows" else r"build\Release\myapp"
+        c.run_command(cmd)
+        assert "protobuf: Debug!" not in c.out
+        assert "protobuf: Release!" in c.out
+
+
+@pytest.mark.tool("cmake", "3.23")
+class TestConfigs:
+    @pytest.mark.skipif(platform.system() != "Windows", reason="Only MSVC multi-conf")
+    def test_multi_config(self, matrix_client):
+        c = matrix_client
+        c.run("new cmake_exe -d name=app -d version=0.1 -d requires=matrix/1.0")
+        c.run(f"install . -c tools.cmake.cmakedeps:new={new_value}")
+        c.run("install . -s build_type=Debug --build=missing "
+              f"-c tools.cmake.cmakedeps:new={new_value}")
+
+        c.run_command("cmake --preset conan-default")
+        c.run_command("cmake --build --preset conan-release")
+        c.run_command("cmake --build --preset conan-debug")
+
+        c.run_command("build\\Release\\app")
+        assert "matrix/1.0: Hello World Release!" in c.out
+        assert "app/0.1: Hello World Release!" in c.out
+        c.run_command("build\\Debug\\app")
+        assert "matrix/1.0: Hello World Debug!" in c.out
+        assert "app/0.1: Hello World Debug!" in c.out
+
+    def test_cross_config(self, matrix_client):
+        # Release dependencies, but compiling app in Debug
+        c = matrix_client
+        c.run("new cmake_exe -d name=app -d version=0.1 -d requires=matrix/1.0")
+        c.run(f"install . -s &:build_type=Debug -c tools.cmake.cmakedeps:new={new_value}")
+
+        # With modern CMake > 3.26 not necessary set(CMAKE_MAP_IMPORTED_CONFIG_DEBUG Release)
+        cmake = textwrap.dedent("""
+            cmake_minimum_required(VERSION 3.15)
+            project(app CXX)
+            set(CMAKE_MAP_IMPORTED_CONFIG_DEBUG Release)
+            find_package(matrix CONFIG REQUIRED)
+
+            add_executable(app src/app.cpp src/main.cpp)
+            target_link_libraries(app PRIVATE matrix::matrix)
+            """)
+        c.save({"CMakeLists.txt": cmake})
+
+        preset = "conan-default" if platform.system() == "Windows" else "conan-debug"
+        c.run_command(f"cmake --preset {preset}")
+        c.run_command("cmake --build --preset conan-debug")
+
+        c.run_command(os.path.join("build", "Debug", "app"))
+        assert "matrix/1.0: Hello World Release!" in c.out
+        assert "app/0.1: Hello World Debug!" in c.out
+
+    @pytest.mark.skipif(platform.system() == "Windows", reason="This doesn't work in MSVC")
+    def test_cross_config_implicit(self, matrix_client):
+        # Release dependencies, but compiling app in Debug, without specifying it
+        c = matrix_client
+        c.run("new cmake_exe -d name=app -d version=0.1 -d requires=matrix/1.0")
+        c.run(f"install . -c tools.cmake.cmakedeps:new={new_value}")
+
+        # With modern CMake > 3.26 not necessary set(CMAKE_MAP_IMPORTED_CONFIG_DEBUG Release)
+        cmake = textwrap.dedent("""
+            cmake_minimum_required(VERSION 3.15)
+            project(app CXX)
+            set(CMAKE_MAP_IMPORTED_CONFIG_DEBUG Release)
+            find_package(matrix CONFIG REQUIRED)
+
+            add_executable(app src/app.cpp src/main.cpp)
+            target_link_libraries(app PRIVATE matrix::matrix)
+            """)
+
+        c.save({"CMakeLists.txt": cmake})
+        # Now we can force the Debug build, even if dependencies are Release
+        c.run_command("cmake . -DCMAKE_BUILD_TYPE=Debug -B build "
+                      "-DCMAKE_PREFIX_PATH=build/Release/generators")
+        c.run_command("cmake --build build")
+        c.run_command("./build/app")
+        assert "matrix/1.0: Hello World Release!" in c.out
+        assert "app/0.1: Hello World Debug!" in c.out
+
+
+@pytest.mark.tool("cmake", "3.23")
+class TestCMakeTry:
+
+    def test_check_c_source_compiles(self, matrix_client):
+        """
+        https://github.com/conan-io/conan/issues/12012
+        """
+        c = matrix_client  # it brings the "matrix" package dependency pre-built
+
+        consumer = textwrap.dedent("""
+            from conan import ConanFile
+            from conan.tools.cmake import CMakeDeps
+            class PkgConan(ConanFile):
+                settings = "os", "arch", "compiler", "build_type"
+                requires = "matrix/1.0"
+                generators = "CMakeToolchain",
+                def generate(self):
+                    deps = CMakeDeps(self)
+                    deps.set_property("matrix", "cmake_additional_variables_prefixes", ["MyMatrix"])
+                    deps.generate()
+            """)
+
+        cmakelist = textwrap.dedent("""\
+            cmake_minimum_required(VERSION 3.15)
+            project(Hello LANGUAGES CXX)
+
+            find_package(matrix CONFIG REQUIRED)
+            include(CheckCXXSourceCompiles)
+
+            set(CMAKE_REQUIRED_INCLUDES ${MyMatrix_INCLUDE_DIRS})
+            set(CMAKE_REQUIRED_LIBRARIES ${MyMatrix_LIBRARIES})
+            check_cxx_source_compiles("#include <matrix.h>
+                                      int main(void) { matrix();return 0; }" IT_COMPILES)
+            """)
+
+        c.save({"conanfile.py": consumer,
+                "CMakeLists.txt": cmakelist}, clean_first=True)
+        c.run(f"install . -c tools.cmake.cmakedeps:new={new_value}")
+
+        preset = "conan-default" if platform.system() == "Windows" else "conan-release"
+        c.run_command(f"cmake --preset {preset} ")
+        assert "Performing Test IT_COMPILES - Success" in c.out
diff --git a/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_new_cpp_linkage.py b/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_new_cpp_linkage.py
new file mode 100644
index 000000000..0932a77fa
--- /dev/null
+++ b/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_new_cpp_linkage.py
@@ -0,0 +1,54 @@
+import platform
+import textwrap
+import pytest
+
+
+new_value = "will_break_next"
+
+
+@pytest.mark.skipif(platform.system() == "Windows", reason="Windows doesn't fail to link")
+def test_auto_cppstd(matrix_c_interface_client):
+    c = matrix_c_interface_client
+    # IMPORTANT: This must be a C and CXX CMake project!!
+    consumer = textwrap.dedent("""
+        cmake_minimum_required(VERSION 3.15)
+        project(myapp C CXX)
+
+        find_package(matrix REQUIRED)
+
+        add_executable(app app.c)
+        target_link_libraries(app PRIVATE matrix::matrix)
+        """)
+
+    conanfile = textwrap.dedent("""\
+        import os
+        from conan import ConanFile
+        from conan.tools.cmake import CMake, cmake_layout
+
+        class Recipe(ConanFile):
+            settings = "os", "compiler", "build_type", "arch"
+            package_type = "application"
+            generators = "CMakeToolchain", "CMakeDeps"
+            requires = "matrix/0.1"
+
+            def layout(self):
+                cmake_layout(self)
+
+            def build(self):
+                cmake = CMake(self)
+                cmake.configure()
+                cmake.build()
+                self.run(os.path.join(self.cpp.build.bindir, "app"), env="conanrun")
+        """)
+    app = textwrap.dedent("""
+        #include "matrix.h"
+        int main(){
+            matrix();
+            return 0;
+        }
+        """)
+    c.save({"conanfile.py": conanfile,
+            "CMakeLists.txt": consumer,
+            "app.c": app}, clean_first=True)
+    c.run(f"build . -c tools.cmake.cmakedeps:new={new_value}")
+    assert "Hello Matrix!" in c.out
diff --git a/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_new_paths.py b/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_new_paths.py
new file mode 100644
index 000000000..f3c04e165
--- /dev/null
+++ b/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_new_paths.py
@@ -0,0 +1,97 @@
+import re
+import textwrap
+
+import pytest
+
+from conan.test.assets.genconanfile import GenConanfile
+from conan.test.utils.tools import TestClient
+
+new_value = "will_break_next"
+
+
+@pytest.fixture
+def client():
+    c = TestClient()
+    pkg = textwrap.dedent("""
+        from conan import ConanFile
+        from conan.tools.cmake import CMake, cmake_layout
+        import os
+        class Pkg(ConanFile):
+            settings = "build_type", "os", "arch", "compiler"
+            requires = "dep/0.1"
+            generators = "CMakeDeps", "CMakeToolchain"
+            def layout(self):  # Necessary to force config files in another location
+                cmake_layout(self)
+            def build(self):
+                cmake = CMake(self)
+                cmake.configure(variables={"CMAKE_FIND_DEBUG_MODE": "ON"})
+       """)
+    cmake = textwrap.dedent("""
+       cmake_minimum_required(VERSION 3.15)
+       project(pkgb LANGUAGES NONE)
+       find_package(dep CONFIG REQUIRED)
+       """)
+    c.save({"dep/conanfile.py": GenConanfile("dep", "0.1"),
+            "pkg/conanfile.py": pkg,
+            "pkg/CMakeLists.txt": cmake})
+    return c
+
+
+@pytest.mark.tool("cmake")
+def test_cmake_generated(client):
+    c = client
+    c.run("create dep")
+    c.run(f"build pkg -c tools.cmake.cmakedeps:new={new_value}")
+    assert "Conan toolchain: Including CMakeDeps generated conan_find_paths.cmake" in c.out
+    assert "Conan: Target declared imported INTERFACE library 'dep::dep'" in c.out
+
+
+@pytest.mark.tool("cmake")
+def test_cmake_in_package(client):
+    c = client
+    # same, but in-package
+    dep = textwrap.dedent("""
+        import os
+        from conan import ConanFile
+        from conan.tools.files import save
+        class Pkg(ConanFile):
+            name = "dep"
+            version = "0.1"
+
+            def package(self):
+                content = 'message(STATUS "Hello from dep dep-Config.cmake!!!!!")'
+                save(self, os.path.join(self.package_folder, "cmake", "dep-config.cmake"), content)
+            def package_info(self):
+                self.cpp_info.set_property("cmake_find_mode", "none")
+                self.cpp_info.builddirs = ["cmake"]
+        """)
+
+    c.save({"dep/conanfile.py": dep})
+    c.run("create dep")
+    c.run(f"build pkg -c tools.cmake.cmakedeps:new={new_value}")
+    assert "Conan toolchain: Including CMakeDeps generated conan_find_paths.cmake" in c.out
+    assert "Hello from dep dep-Config.cmake!!!!!" in c.out
+
+
+class TestRuntimeDirs:
+
+    def test_runtime_lib_dirs_multiconf(self):
+        client = TestClient()
+        app = GenConanfile().with_requires("dep/1.0").with_generator("CMakeDeps")\
+            .with_settings("build_type")
+        client.save({"lib/conanfile.py": GenConanfile(),
+                     "dep/conanfile.py": GenConanfile("dep").with_requires("onelib/1.0",
+                                                                           "twolib/1.0"),
+                     "app/conanfile.py": app})
+        client.run("create lib --name=onelib --version=1.0")
+        client.run("create lib --name=twolib --version=1.0")
+        client.run("create dep  --version=1.0")
+
+        client.run(f'install app -s build_type=Release -c tools.cmake.cmakedeps:new={new_value}')
+        client.run(f'install app -s build_type=Debug -c tools.cmake.cmakedeps:new={new_value}')
+
+        contents = client.load("app/conan_cmakedeps_paths.cmake")
+        pattern_lib_dirs = r"set\(CONAN_RUNTIME_LIB_DIRS ([^)]*)\)"
+        runtime_lib_dirs = re.search(pattern_lib_dirs, contents).group(1)
+        assert "<CONFIG:Release>" in runtime_lib_dirs
+        assert "<CONFIG:Debug>" in runtime_lib_dirs
diff --git a/test/functional/toolchains/conftest.py b/test/functional/toolchains/conftest.py
index e1f294b62..b81671e87 100644
--- a/test/functional/toolchains/conftest.py
+++ b/test/functional/toolchains/conftest.py
@@ -1,8 +1,10 @@
 import os
 import shutil
+import textwrap
 
 import pytest
 
+from conan.test.assets.sources import gen_function_h, gen_function_cpp
 from conan.test.utils.test_files import temp_folder
 from conan.test.utils.tools import TestClient
 
@@ -48,3 +50,188 @@ def transitive_libraries(_transitive_libraries):
     c.cache_folder = os.path.join(temp_folder(), ".conan2")
     shutil.copytree(_transitive_libraries.cache_folder, c.cache_folder)
     return c
+
+
+@pytest.fixture(scope="session")
+def _matrix_client_components():
+    """
+    2 components, different than the package name
+    """
+    c = TestClient()
+    headers_h = textwrap.dedent("""
+        #include <iostream>
+        #ifndef MY_MATRIX_HEADERS_DEFINE
+        #error "Fatal error MY_MATRIX_HEADERS_DEFINE not defined"
+        #endif
+        void headers(){ std::cout << "Matrix headers: Release!" << std::endl;
+            #if __cplusplus
+            std::cout << "  Matrix headers __cplusplus: __cplusplus" << __cplusplus << std::endl;
+            #endif
+        }
+        """)
+    vector_h = gen_function_h(name="vector")
+    vector_cpp = gen_function_cpp(name="vector", includes=["vector"])
+    module_h = gen_function_h(name="module")
+    module_cpp = gen_function_cpp(name="module", includes=["module", "vector"], calls=["vector"])
+
+    conanfile = textwrap.dedent("""
+        from conan import ConanFile
+        from conan.tools.cmake import CMake
+
+        class Matrix(ConanFile):
+            name = "matrix"
+            version = "1.0"
+            settings = "os", "compiler", "build_type", "arch"
+            generators = "CMakeToolchain"
+            exports_sources = "src/*", "CMakeLists.txt"
+
+            def build(self):
+                cmake = CMake(self)
+                cmake.configure()
+                cmake.build()
+
+            def package(self):
+                cmake = CMake(self)
+                cmake.install()
+
+            def package_info(self):
+                self.cpp_info.default_components = ["vector", "module"]
+
+                self.cpp_info.components["headers"].includedirs = ["include/headers"]
+                self.cpp_info.components["headers"].set_property("cmake_target_name", "MatrixHeaders")
+                self.cpp_info.components["headers"].defines = ["MY_MATRIX_HEADERS_DEFINE=1"]
+                # Few flags to cover that CMakeDeps doesn't crash with them
+                if self.settings.compiler == "msvc":
+                    self.cpp_info.components["headers"].cxxflags = ["/Zc:__cplusplus"]
+                    self.cpp_info.components["headers"].cflags = ["/Zc:__cplusplus"]
+                    self.cpp_info.components["headers"].system_libs = ["ws2_32"]
+                else:
+                    self.cpp_info.components["headers"].system_libs = ["m"]
+                    # Just to verify CMake don't break
+                    self.cpp_info.sharedlinkflags = ["-z now", "-z relro"]
+                    self.cpp_info.exelinkflags = ["-z now", "-z relro"]
+
+                self.cpp_info.components["vector"].libs = ["vector"]
+                self.cpp_info.components["vector"].includedirs = ["include"]
+                self.cpp_info.components["vector"].libdirs = ["lib"]
+
+                self.cpp_info.components["module"].libs = ["module"]
+                self.cpp_info.components["module"].includedirs = ["include"]
+                self.cpp_info.components["module"].libdirs = ["lib"]
+                self.cpp_info.components["module"].requires = ["vector"]
+          """)
+
+    cmakelists = textwrap.dedent("""
+       set(CMAKE_CXX_COMPILER_WORKS 1)
+       set(CMAKE_CXX_ABI_COMPILED 1)
+       cmake_minimum_required(VERSION 3.15)
+       project(matrix CXX)
+
+       add_library(vector src/vector.cpp)
+       add_library(module src/module.cpp)
+       add_library(headers INTERFACE)
+       target_link_libraries(module PRIVATE vector)
+
+       set_target_properties(headers PROPERTIES PUBLIC_HEADER "src/headers.h")
+       set_target_properties(module PROPERTIES PUBLIC_HEADER "src/module.h")
+       set_target_properties(vector PROPERTIES PUBLIC_HEADER "src/vector.h")
+       install(TARGETS vector module)
+       install(TARGETS headers PUBLIC_HEADER DESTINATION include/headers)
+       """)
+    c.save({"src/headers.h": headers_h,
+            "src/vector.h": vector_h,
+            "src/vector.cpp": vector_cpp,
+            "src/module.h": module_h,
+            "src/module.cpp": module_cpp,
+            "CMakeLists.txt": cmakelists,
+            "conanfile.py": conanfile})
+    c.run("create .")
+    return c
+
+
+@pytest.fixture()
+def matrix_client_components(_matrix_client_components):
+    c = TestClient()
+    c.cache_folder = os.path.join(temp_folder(), ".conan2")
+    shutil.copytree(_matrix_client_components.cache_folder, c.cache_folder)
+    return c
+
+
+@pytest.fixture(scope="session")
+def _matrix_c_interface_client():
+    c = TestClient()
+    matrix_h = textwrap.dedent("""\
+        #pragma once
+        #ifdef __cplusplus
+        extern "C" {
+        #endif
+            void matrix();
+        #ifdef __cplusplus
+        }
+        #endif
+        """)
+    matrix_cpp = textwrap.dedent("""\
+        #include "matrix.h"
+        #include <iostream>
+        #include <string>
+        void matrix(){
+            std::cout<< std::string("Hello Matrix!") <<std::endl;
+        }
+        """)
+    # Having here the config.cmake code to be able to manually check what CMake generates
+    cmake = textwrap.dedent("""\
+        cmake_minimum_required(VERSION 3.15)
+        project(matrix C CXX)
+        add_library(matrix STATIC src/matrix.cpp)
+        target_include_directories(matrix PUBLIC
+          $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+          $<INSTALL_INTERFACE:include>
+        )
+        set_target_properties(matrix PROPERTIES PUBLIC_HEADER "include/matrix.h")
+        install(TARGETS matrix EXPORT matrixConfig)
+        export(TARGETS matrix
+            NAMESPACE matrix::
+            FILE "${CMAKE_CURRENT_BINARY_DIR}/matrixConfig.cmake"
+        )
+        install(EXPORT matrixConfig
+            DESTINATION "${CMAKE_INSTALL_PREFIX}/matrix/cmake"
+            NAMESPACE matrix::
+        )
+        """)
+    conanfile = textwrap.dedent("""\
+        from conan import ConanFile
+        from conan.tools.cmake import CMake, cmake_layout
+        class Recipe(ConanFile):
+            name = "matrix"
+            version = "0.1"
+            settings = "os", "compiler", "build_type", "arch"
+            package_type = "static-library"
+            generators = "CMakeToolchain"
+            exports_sources = "CMakeLists.txt", "src/*", "include/*"
+            languages = "C++"
+            def build(self):
+                cmake = CMake(self)
+                cmake.configure()
+                cmake.build()
+            def layout(self):
+                cmake_layout(self)
+            def package(self):
+                cmake = CMake(self)
+                cmake.install()
+            def package_info(self):
+                self.cpp_info.libs = ["matrix"]
+        """)
+    c.save({"include/matrix.h": matrix_h,
+            "src/matrix.cpp": matrix_cpp,
+            "conanfile.py": conanfile,
+            "CMakeLists.txt": cmake})
+    c.run("create .")
+    return c
+
+
+@pytest.fixture()
+def matrix_c_interface_client(_matrix_c_interface_client):
+    c = TestClient()
+    c.cache_folder = os.path.join(temp_folder(), ".conan2")
+    shutil.copytree(_matrix_c_interface_client.cache_folder, c.cache_folder)
+    return c