Repository: conan-io/conan
Pull request: CMakeDeps build_requires full support
Changelog: Feature: Introduced new options for the `CMakeDeps` generator allowing to manage `build_requires` even declaring the same package as a `require` and `build_require` avoiding the collision of the `config` cmake files and enabling to specify which `build_modules` should be included (e.g protobuf issue)
Docs: https://github.com/conan-io/docs/pull/2104

Closes #8303
Closes #7719

Problem statement:
[question] 'build_modules' of `build_requires` are not included when building consumers with build/host profiles
I'm experimenting with the build and host context profiles and many of my builds are breaking due to the changes in how `build_requires` are handled.  So I'm just trying to understand if this is intentional and whether I need to update my recipes.

For example, I have a tool which is used to generate source code from .xml files in the consumer's repository.  The sources are then compiled into a static library and packaged.  Since consumers only need this tool when building from sources, they have it defined as a `build_requires`.  (Though since the code generator version can have an affect on the code, I'm wondering if it should actually be a normal `requires`? )

To simplify it's usage for consumers, the tool package provides functions to consumers through a `build_module`.  But now it seems that `build_module`s of `build_requires` dependencies are not included by _conan_basic_setup()_.

My current workaround is to `force_host_context=true` for these dependencies, but I'm not sure if this is the correct way to go about it.

[bug] cmake generator does not write build requirements info when using dual profiles
### Environment Details (include every applicable attribute)
  * Operating System+version: macOS Big Sur
  * Conan version: develop (1.33.0-dev)
  * Python version: 3.8.5

### Steps to reproduce (Include if Applicable)

With this `conanfile.py`:

```python
from conans import ConanFile, CMake, tools


class BugConan(ConanFile):
    name = "bug"
    version = "0.1"
    license = "<Put the package license here>"
    author = "<Put your name here> <And your email here>"
    url = "<Package recipe repository url here, for issues about the package>"
    description = "<Description of Bug here>"
    topics = ("<Put some tag here>", "<here>", "<and here>")
    settings = "os", "compiler", "build_type", "arch"
    options = {"shared": [True, False], "fPIC": [True, False]}
    default_options = {"shared": False, "fPIC": True}
    generators = "cmake"

    def config_options(self):
        if self.settings.os == "Windows":
            del self.options.fPIC

    def build_requirements(self):
        self.build_requires("doctest/2.3.8")

    def source(self):
        pass

    def build(self):
        pass

    def package(self):
        pass

    def package_info(self):
        pass
```

Run `conan install . --profile:host=default --profile:build=default`

The generated `conanbuildinfo.cmake` does not contain `doctest` targets, but it does when `conan install . --profile=default` is used.

Hints from issue discussion:
Hi @GordonJess 

In theory, if that tool is an executable that is running in the current build machine, then it should be in the build context, not the host context.

You are right, it seems you hit some missing functionality. So far, the ``build_modules`` feature only works without contexts. When using contexts, the ``cpp_info`` is propagated only through the "host" context, but not the "build" one.

We already separated ``settings_build`` and ``settings_target``, it seems that we should keep extending the model for this use case. Having a first look, doesn't look immediate or obvious, we need to investigate what could be the best solution.
Hi @GordonJess 

We are still polishing this feature and we are learning a lot from all these issues and your use-cases, so nothing is written in stone. Said that, this is how I see this scenario:

 * `build_modules` are included by default in the files that are consumed by the build-system, these `build_modules` usually contain information about the package being included in the build: path to libraries, includes, definitions,... so it makes sense that only those from the _host_ context are available and included by default.

 * your tool, like any other source generator, is a perfect example for a `build_requires`, it runs in the _build_ machine and it needs to take the settings from the `--profile:build` while generating the consumer's library. It will be executed in the `build()` method of the Conan recipe, using `self.run("your-tool")` or inside the build-system scripts. Conan will add the path to your executable to the `PATH` and the tool should run without any problem.

And now there are two important things that deserve more attention:

 * **how your tool affects the packageID**: I would say that the XML files your tool uses to generate source files should be contained in the library itself, it is like a `.proto` definition (from protocol buffers): the file that describes the message is inside the library and the `protoc` tool used to generate the actual `.h/.cpp` files is a `build_requires`. 

   In your case, if those XML files are stored together with the rest of the `.cpp/.h` files from your library, then it is clear how to manage them, like any other source file.

   If those XML files are stored together with the tool, then it belongs to a broader discussion about `build_requires`: if they should or not affect the packageID, if it is configurable,... 

 * let's say **your tool provides something** that the build-system is going to consume (probably the most typical scenario here is a compiler that provides a toolchain). This is still an open question and there are different approaches:

   + some packages takes advantage of one environment variable Conan is using: `CONAN_CMAKE_EXECUTABLE`, they populate this variable to their own CMake wrapper and use it to inject the toolchain. You can find this approach working in the [Android NDK recipe by bincrafters](https://github.com/bincrafters/conan-android_ndk_installer). I really don't like this approach, it is coupling the tool with the environment variable and it doesn't scale (it works only for CMake).

   + other packages have moved this file/functions to a `requires`, like the `protobuf` package in ConanCenter. This approach works because the recipe consuming it will **always** require and build-require the `protobuf` package. You need the tool `protoc` and you need to link with the `libprotobuf` library, both of them are inside the `protobuf` package.

   + a more flexible alternative is provided via the `user_info` attribute. The tool can add the path to the assets/resources/files it is providing in the [`package_info()` method](https://docs.conan.io/en/latest/reference/conanfile/attributes.html?highlight=user_info#user-info), and consumers can take that information from the [`self.user_info_build` attribute](https://docs.conan.io/en/latest/reference/conanfile/attributes.html?highlight=user_info#user-info-build).

----

I know this is not an answer, I'm just enumerating alternatives, but without further information about your exact use-case I really don't know which one fits better with your libraries and your tool. Feel free to ask more details about any of these approaches, and share the challenges or alternatives you face in your way, I'll be pleased to help (...be patient, I won't be available next week).

Thanks!
 
The thing I most liked about `build_modules` is that consumers automatically got access to any variables/functions provided by their `build_requires` dependencies without having to worry about checking certain attributes and passing them into cmake myself.  I'm not sure that I agree that these should only be for dependencies in the `host` context.  Something like the [FindDoxygen](https://cmake.org/cmake/help/latest/module/FindDoxygen.html) module for example is only providing helper-functions for a tool run on the build machine - much like my use case.

> Feel free to ask more details about any of these approaches, and share the challenges or alternatives you face in your way

Thanks!  I've opened some issues  (#7737, #7742) for the other problems I've come across so far using build/host profile.  I've not yet found any workaround for these yet to be able to have something usable, but feels like it's almost there!

`FindDoxygen` is a really good example where CMake relies on the functionality of the `find_package` to get information about tools, basically, any code-generator tool is inside this category and we are suffering the problem with all of them: `protobuf (protoc)` probably is the other big player here.

Here are my thoughts, and I really don't know how to solve the situation without transferring all the responsibility to the user. For example, `doxygen` depends on `zlib`, we agree that the project you are generating can depend on `zlib` too. Conan generates all the `FindXXXX.cmake` files for all the dependencies in your _host_ context, so your project can find the `zlib` packages and link with it. 

Your `CMakeLists.txt` contains something like this:

```cmake
# Get components for some tools
find_package(Doxygen)

# These are your actual dependencies and project
find_package(zlib)
...
target_link_libraries(yourlib PUBLIC zlib:zlib)
```

...but in the filesystem we can have only one file named `FindZLIB.cmake`, if we were running the generators for the packages in the _build_ context, we will override the `zlib` one.

Can we generate only `FindDoxygen.cmake` and forget about the dependencies? It could be a solution, but it won't work with the `protobuf` use case, here the package is the same for the library and the executable, both would generate `FindProtobuf.cmake`, each of them with different/incompatible content.

---

I really think this is a limitation in CMake, and there are some questions asking how they can work around this situation. CMake needs some kind of `find_tool` macro to disambiguate this scenario, that macro would return only tools like `tool::doxygen`, `tool::protoc` and not components you can link with.... and it should use a different `FindToolXXXX.cmake` file (very naïve proposal).

Being a limitation of CMake I wonder if we should totally forget about it and generate all the files, some will override others and the build will fail, but it is the consumer's responsibility to take it into account and take the actions needed to bypass the problem. 

---

For `protobuf` we were able to work around the limitation because the package in the _host_ context contains the functionality to detect `protoc` and return the executable that is already available in the PATH. But this situation doesn't hold for Doxygen, here we are not generating any `FindDoxygen.cmake` file (no `doxygen` package in the _host_ context) that could do the trick.



Hi, I think I'm struggling with the same issue when trying to crosscompile. I want to use x86 `protoc` binary , my `conanfile.txt` looks something along the lines of: 
```
[build_requires]
protobuf/3.11.4

[requires]
protobuf/3.11.4

[generators]
make

[options]
```
From what I can tell, there is no way to access the `protoc` binary programatically after running:
`conan install . --profile:host .conan/profiles/arm --profile:build .conan/profiles/x86_64`. 

I tried adding this to the conan file, but the copied `protoc` is an arm version from the `requires` section and not from the `build_requires` one
```
[imports]
bin, *-> ./bin
```
 Any thoughts? Am I missing here something?
Hi, @tomerlevv 

Build requires in your example (with a `conanfile.txt` and using two-profiles) should be considered as tools provided by the environment like the `cmake`, `gcc`,... that you can already run using them from the command line (they are already in the PATH).

Conan provides some generators to get the information from those build-requires and provide you with a couple of files to activate and deactivate them, use `-g virtualenv` (or add it to your generators):

```
conan install . --profile:host .conan/profiles/arm --profile:build .conan/profiles/x86_64 -g virtualenv
```

Conan will generate files `activate.sh/bat/ps1` and `deactivate.sh/bat/ps1` that will _activate_ an environment with all the environment variables (and PATH) provided by your build-requires.

With this, you can add to your environment the executables for `protoc` (build machine) or any other build-require you might want to use in your build process, like a different CMake version or the compiler itself.
Thank you @jgsogo , It seems to be the direction I should take. Currently I am invoking `conan install` from my Makefile, generating a `conan.mak` file. In order to make the suggested solution work I would have to write my own generator which I think I'll pass for now. 

Thanks anyway!
Back to the original question in this issue. Copying here the comment in https://github.com/conan-io/conan/issues/8303#issuecomment-757894304

> We've been talking about this issue (and related ones) and the path will be as follows:
> 
> * Conan will (1.34?) generate a file with all the information from `cpp_info` in plain CMake format. This file will contain the information as plain as possible. It will be hard to define the name of all the variables, but the file will contain information from all the packages in _host_ and _build_ context that are needed to build the package. (Note.- Maybe it is not only one file, but one per requirement, TBD).
> * This file will be accessible only if using generator `CMakeDeps` (in fact, this generator will use that file/s to populate the targets). Generator `CMakeDeps` will be the recommended (only?) one in Conan 2.0 and we encourage everyone to try it and start using it to smooth the migration.
> * User can `include` that file from their `CMakeLists.txt` and will have access to all these variables.
> * Eventually, Conan will provide some abstraction layers on top of this file to provide targets for the components coming from the _build_ context (protoc, doxygen,...). And some convenient CMake functions (`find_package_build`) or overrides (new definition of `find_package`) that will help with these scenarios and make it possible some transparent integration of Conan with existing CMake files.

With this approach, build-modules of packages coming from _build_ context will be available in that file. Those build-modules from the _build_ context won't (probably) be automatically included, but the paths to those build-modules will be available in a CMake variable.
In our case we avoided the above protobuf issue by splitting protobuf into two packages: `libprotobuf/<version>@company/stable`, containing only the static libraries (libprotobuf) and `protoc/<version>@company/stable`, containing only the `protoc` executable and cmake helper that consumers can use to simply use `protoc` executable to convert their `proto` files into source/header pairs and compile them.

Then, we add `libprotobuf` to the `requires` and `protoc` to `build_requires`.

This works pretty well - the only issue is that `protoc` package still needs to use the old `arch_build/os_build` mechanism in order for the cmake helper to be available for usage in cross-compile scenario. I've reported this bug [here](https://github.com/conan-io/conan/issues/8488) and also provided a simple example that reproduces the issue.
Regarding the affection of `package_id` by `build_requires` - maybe the package should tell for itself whether it can influence other packages' ID?

For example, a conan package containing tools like `cmake` or `doxygen` would not alter ID of the package that `build_requires` it.
On the other hand, a conan package containing the toolchain, like `android-ndk` or `emscripten` would alter ID of the package that `build_requires` it (it's not the same if you build your package with NDK r22 or NDK r21). However, such packages would also need to have the ability to impose settings on the build graph and maybe influence the package ID in that way.
This is exactly what I proposed [here](https://github.com/conan-io/conan/issues/8274).

This is because of the line `all_flags = cmake_dependencies(dependencies=self.deps_build_info.deps)`.

`self.deps_build_info` is empty when using dual profiles
I've added logs in `model/conan_generator.py:

With `--profile=default`:

>self._deps_build_info: <conans.model.env_info.DepsEnvInfo object at 0x105c68b50>
>self._deps_env_info <conans.model.env_info.DepsEnvInfo object at 0x105c68b50>
>self._env_info None
>self._deps_user_info DepsUserInfo(<class 'conans.model.user_info.UserInfo'>, {'doctest': {}})
>self._user_info_build None

With dual profiles:

>self._deps_build_info: <conans.model.env_info.DepsEnvInfo object at 0x1061e58b0>
>self._deps_env_info <conans.model.env_info.DepsEnvInfo object at 0x1061e58b0>
>self._env_info None
>self._deps_user_info DepsUserInfo(<class 'conans.model.user_info.UserInfo'>, {})
>self._user_info_build DepsUserInfo(<class 'conans.model.user_info.UserInfo'>, {'doctest': {}})

Seems that generators do not support `user_info_build`
Hi, @theodelrieu 

This is probably a limitation of the `cmake` generator. With the current syntax there is no way to differentiate between a package coming from _host_ context and the same package from _build_ context if both have the same name (i.e.: `protobuf`). It would require variables like `CONAN_USER_<PKG-NAME>_<VAR-NAME>` and `CONAN_USER_<CONTEXT>_<PKG-NAME>_<VAR-NAME>`.

Doable, but not sure if we want to go that way. If the preferred generator `cmake_find_package[_multi]` doesn't provide this functionality, IMHO we shouldn't add it to a generator that might be removed in Conan v2.0.... or at least we shouldn't add it before implementing it in the recommended generator.

But we totally need to unblock this issue, there are many related to this same problem or closer ones. I really think there is something missing in CMake itself, but we need to bet big and offer a way to work around current limitations. I'm thinking about opening an RFC with some risky proposal.
> If the preferred generator cmake_find_package[_multi] doesn't provide this functionality

Indeed, the Finddoctest.cmake is only generated when `--profile default` is used.

I don't know how I can workaround this issue, I don't want to revert to `os_build/arch_build` but I might not have a choice here...
@theodelrieu 
Why do you add doctest as a build requirement?
doctest is a header-only library. Shouldn't it be a requirement?
Hi, @theodelrieu 

We've been talking about this issue (and related ones) and the path will be as follows: 
 * Conan will (1.34?) generate a file with all the information from `cpp_info` in plain CMake format. This file will contain the information as plain as possible. It will be hard to define the name of all the variables, but the file will contain information from all the packages in _host_ and _build_ context that are needed to build the package. (Note.- Maybe it is not only one file, but one per requirement, TBD).
 * This file will be accessible only if using generator `CMakeDeps` (in fact, this generator will use that file/s to populate the targets). Generator `CMakeDeps` will be the recommended (only?) one in Conan 2.0 and we encourage everyone to try it and start using it to smooth the migration.
 * User can `include` that file from their `CMakeLists.txt` and will have access to all these variables.
 * Eventually, Conan will provide some abstraction layers on top of this file to provide targets for the components coming from the _build_ context (protoc, doxygen,...). And some convenient CMake functions (`find_package_build`) or overrides (new definition of `find_package`) that will help with these scenarios and make it possible some transparent integration of Conan with existing CMake files.


In my case I need [CapnProto ](https://conan.io/center/capnp?tab=overview) to be compiled for the build system, generate sources, and then be available as `find_package` for building the host binaries.

Is there any workaround for cross compilation right now?

EDIT: maybe a two step `conan install`, so instead of
`conan install .. --profile:build build_profile --profile:host host_profile`
we split it up and call
`conan install package_A package_B --profile build_profile`
--> copy away the files you need...
`conan install package_C package_D --profile host_profile`
--> ... and restore them again
but for that I would need to evaluate the `conanfile.py` manually I guess 😞 

As seen below, `--profile:build` just completely skips the generation of any `*.cmake` files for packages listed as `build_requirements`. For `cmake_paths`, `conan_paths.cmake` does not contain any info about them as well.

For this `conanfile.py`:
```python
    generators = "cmake_find_package"
    ...
    def build_requirements(self):
        self.build_requires("capnproto/0.8.0")

    def requirements(self):
        self.requires("catch2/2.13.3")
```

`conan install .. --profile:build default`:
```python
conanfile.py (LumPDK/None): Applying build-requirement: capnproto/0.8.0
conanfile.py (LumPDK/None): Generator cmake_find_package created FindCatch2.cmake
```

`conan install .. --profile:host default`:
```python
conanfile.py (LumPDK/None): Applying build-requirement: capnproto/0.8.0
conanfile.py (LumPDK/None): Generator cmake_find_package created FindCapnProto.cmake
conanfile.py (LumPDK/None): Generator cmake_find_package created FindCatch2.cmake
```

`conan install .. --profile default`:
```python
conanfile.py (LumPDK/None): Applying build-requirement: capnproto/0.8.0
conanfile.py (LumPDK/None): Generator cmake_find_package created FindCapnProto.cmake
conanfile.py (LumPDK/None): Generator cmake_find_package created FindCatch2.cmake
```
@blackliner The way to go is to add `capnproto` to requires and build-requires:

```python

    generators = "cmake_find_package"
    ...
    def build_requirements(self):
        self.build_requires("capnproto/0.8.0")

    def requirements(self):
        self.requires("capnproto/2.13.3")
        self.requires("catch2/2.13.3")

    def build(self):
        # All the environment provided by `capnproto` from the build context is available here.

```

and then use the two-profiles approach:

```
conan create conanfile.py --profile:host=host --profile:build=default
```

Conan will populate the environment before entering `build()` method with the information provided in the `env_info` of the `capnproto` recipe.
Unfortunately we do not use conan to build our own package, we just use it to consume dependencies. I went for this solution/workaround for now:
```python
def conan(args):
    if not (BASE_DIR / "conanfile.py").is_file():
        logging.info("Skipping conan step")
        return

    export_recipes(args)

    conan_command = [
        "conan",
        "install",
        "..",
        "--settings",
        "build_type=" + args.build_type,
        "--build=missing",
        "--build=acado",
    ]

    if args.conan_profile:
        conan_command.append(f"--profile={CALLER_DIR / args.conan_profile}")
    else:        
        if args.conan_build_profile:
            conan_command_build_profile = conan_command.copy()
            conan_command_build_profile.append(f"--profile={CALLER_DIR / args.conan_build_profile}")
            subprocess.check_call(conan_command_build_profile, cwd=BUILD_DIR)
            for cmake_file in BUILD_DIR.glob("*.cmake"):
                cmake_file.rename(cmake_file.with_suffix(".build_bak"))

            conan_command.append(f"--profile:build={CALLER_DIR / args.conan_build_profile}")

        if args.conan_host_profile:
            conan_command.append(f"--profile:host={CALLER_DIR / args.conan_host_profile}")

    logging.info("Conan command:")
    logging.info(" ".join(conan_command))

    subprocess.check_call(conan_command, cwd=BUILD_DIR)

    for cmake_bak_file in BUILD_DIR.glob("*.build_bak"):
        new_name = cmake_bak_file.with_suffix(".cmake")
        if not new_name.is_file():
            cmake_bak_file.rename(new_name)
```
So for now I save all the `FindXXX.cmake` from the build context and restore them later 🤷

Commit message: fix win

Patch to review:
diff --git a/conan/tools/cmake/cmakedeps/cmakedeps.py b/conan/tools/cmake/cmakedeps/cmakedeps.py
index a1619a68a4d..1deb5553237 100644
--- a/conan/tools/cmake/cmakedeps/cmakedeps.py
+++ b/conan/tools/cmake/cmakedeps/cmakedeps.py
@@ -6,6 +6,7 @@
 from conan.tools.cmake.cmakedeps.templates.target_configuration import TargetConfigurationTemplate
 from conan.tools.cmake.cmakedeps.templates.target_data import ConfigDataTemplate
 from conan.tools.cmake.cmakedeps.templates.targets import TargetsTemplate
+from conans.errors import ConanException
 from conans.util.files import save
 
 
@@ -16,6 +17,11 @@ def __init__(self, conanfile):
         self.arch = self._conanfile.settings.get_safe("arch")
         self.configuration = str(self._conanfile.settings.build_type)
         self.configurations = [v for v in conanfile.settings.build_type.values_range if v != "None"]
+        # By default, the build modules are generated for host context only
+        self.build_context_build_modules = []
+        # If specified, the files/targets/variables for the build context will be renamed appeding
+        # a suffix. It is necessary in case of same require and build_require and will cause an error
+        self.build_context_suffix = {}
 
     def generate(self):
         # Current directory is the generators_folder
@@ -28,10 +34,20 @@ def content(self):
         macros = MacrosTemplate()
         ret = {macros.filename: macros.render()}
 
-        host_requires = {r.ref.name: r for r in
-                         self._conanfile.dependencies.transitive_host_requires}
+        host_req = self._conanfile.dependencies.transitive_host_requires
+        build_req = self._conanfile.dependencies.build_requires_build_context
+
+        # Check if the same package is at host and build and the same time
+        common = {r.ref.name for r in host_req}.intersection({r.ref.name for r in build_req})
+        for name in common:
+            if name not in self.build_context_suffix:
+                raise ConanException("The package '{}' exists both as 'require' and as "
+                                     "'build require'. You need to specify a suffix using the "
+                                     "'build_context_suffix' attribute at the CMakeDeps "
+                                     "generator.".format(name))
+
         # Iterate all the transitive requires
-        for req in host_requires.values():
+        for req in host_req + build_req:
 
             config_version = ConfigVersionTemplate(self, req)
             ret[config_version.filename] = config_version.render()
diff --git a/conan/tools/cmake/cmakedeps/templates/__init__.py b/conan/tools/cmake/cmakedeps/templates/__init__.py
index e6de41bffaf..bc8c0fb5a97 100644
--- a/conan/tools/cmake/cmakedeps/templates/__init__.py
+++ b/conan/tools/cmake/cmakedeps/templates/__init__.py
@@ -8,13 +8,37 @@ class CMakeDepsFileTemplate(object):
 
     def __init__(self, cmakedeps, req):
         self.cmakedeps = cmakedeps
-        if req is not None:
-            self.conanfile = req
-            self.pkg_name = req.ref.name
-            self.package_folder = req.package_folder.\
-                replace('\\', '/').replace('$', '\\$').replace('"', '\\"')
-            self.target_namespace = get_target_namespace(self.conanfile)
-            self.file_name = get_file_name(self.conanfile)
+        self.conanfile = req
+
+    @property
+    def pkg_name(self):
+        return self.conanfile.ref.name + self.suffix
+
+    @property
+    def package_folder(self):
+        return self.conanfile.package_folder.\
+            replace('\\', '/').replace('$', '\\$').replace('"', '\\"')
+
+    @property
+    def target_namespace(self):
+        return get_target_namespace(self.conanfile) + self.suffix
+
+    @property
+    def file_name(self):
+        return get_file_name(self.conanfile) + self.suffix
+
+    @property
+    def suffix(self):
+        if not self.conanfile.is_build_context:
+            return ""
+        return self.cmakedeps.build_context_suffix.get(self.conanfile.ref.name, "")
+
+    @property
+    def build_modules_activated(self):
+        if self.conanfile.is_build_context:
+            return self.conanfile.ref.name in self.cmakedeps.build_context_build_modules
+        else:
+            return self.conanfile.ref.name not in self.cmakedeps.build_context_build_modules
 
     def render(self):
         context = self.context
diff --git a/conan/tools/cmake/cmakedeps/templates/target_configuration.py b/conan/tools/cmake/cmakedeps/templates/target_configuration.py
index 9fb54afa966..90ab8f4d203 100644
--- a/conan/tools/cmake/cmakedeps/templates/target_configuration.py
+++ b/conan/tools/cmake/cmakedeps/templates/target_configuration.py
@@ -14,7 +14,8 @@ class TargetConfigurationTemplate(CMakeDepsFileTemplate):
 
     @property
     def filename(self):
-        return "{}Target-{}.cmake".format(self.file_name, self.cmakedeps.configuration.lower())
+        return "{}Target-{}.cmake".format(self.file_name,
+                                            self.cmakedeps.configuration.lower())
 
     @property
     def context(self):
diff --git a/conan/tools/cmake/cmakedeps/templates/target_data.py b/conan/tools/cmake/cmakedeps/templates/target_data.py
index 1b28e6e61ac..fd309a19aa7 100644
--- a/conan/tools/cmake/cmakedeps/templates/target_data.py
+++ b/conan/tools/cmake/cmakedeps/templates/target_data.py
@@ -24,6 +24,9 @@ def filename(self):
     @property
     def context(self):
         global_cpp = self.get_global_cpp_cmake()
+        if not self.build_modules_activated:
+            global_cpp.build_modules_paths = ""
+
         components_cpp = self.get_required_components_cpp()
         components_renames = " ".join([component_rename for component_rename, _ in
                                        reversed(components_cpp)])
diff --git a/conans/client/graph/conanfile_dependencies.py b/conans/client/graph/conanfile_dependencies.py
index e1a3f952b51..c9379acd2bd 100644
--- a/conans/client/graph/conanfile_dependencies.py
+++ b/conans/client/graph/conanfile_dependencies.py
@@ -1,4 +1,4 @@
-from conans.client.graph.graph import CONTEXT_HOST
+from conans.client.graph.graph import CONTEXT_HOST, CONTEXT_BUILD
 from conans.errors import ConanException
 from conans.model.conanfile_interface import ConanFileInterface
 
@@ -26,6 +26,9 @@ def __getitem__(self, name):
             raise ConanException("No dependency found")
         return result[0]
 
+    def __add__(self, other):
+        return DependencyOrderedSet(self._deps + other._deps)
+
 
 class ConanFileDependencies:
 
@@ -40,6 +43,18 @@ def build_requires(self):
         return DependencyOrderedSet([ConanFileInterface(edge.dst.conanfile)
                                      for edge in self._node.dependencies if edge.build_require])
 
+    @property
+    def build_requires_build_context(self):
+        """
+        :return: list of immediate direct build_requires, on build context.
+        FIXME: Why this method? To overcome the legacy use case without 2 profiles where everthing
+               is host, otherwise we can receive the same build require twice, one in
+               .transitive_host_requires and one in .build_requires
+        """
+        return DependencyOrderedSet([ConanFileInterface(edge.dst.conanfile)
+                                     for edge in self._node.dependencies if edge.build_require and
+                                     edge.dst.context == CONTEXT_BUILD])
+
     @property
     def requires(self):
         """
diff --git a/conans/model/conanfile_interface.py b/conans/model/conanfile_interface.py
index 7521ed4f01c..94f157f67a5 100644
--- a/conans/model/conanfile_interface.py
+++ b/conans/model/conanfile_interface.py
@@ -1,3 +1,4 @@
+from conans.client.graph.graph import CONTEXT_BUILD
 
 
 class ConanFileInterface:
@@ -60,3 +61,7 @@ def context(self):
     @property
     def dependencies(self):
         return self._conanfile.dependencies
+
+    @property
+    def is_build_context(self):
+        return self._conanfile.context == CONTEXT_BUILD
diff --git a/conans/test/functional/toolchains/cmake/cmakedeps/test_build_context_protobuf.py b/conans/test/functional/toolchains/cmake/cmakedeps/test_build_context_protobuf.py
new file mode 100644
index 00000000000..aafbf0feb2a
--- /dev/null
+++ b/conans/test/functional/toolchains/cmake/cmakedeps/test_build_context_protobuf.py
@@ -0,0 +1,233 @@
+import textwrap
+
+import pytest
+
+from conans.test.utils.tools import TestClient
+
+
+@pytest.fixture
+def client():
+    c = TestClient()
+    conanfile = textwrap.dedent('''
+    from conans import ConanFile
+    from conans.tools import save, chdir
+    import os
+
+    class Protobuf(ConanFile):
+        settings = "build_type", "os", "arch", "compiler"
+
+        def package(self):
+            my_cmake_module = """
+                  function(foo_generate)
+                     write_file(foo_generated.h "int from_context = %s;")
+                  endfunction()
+            """
+
+            with chdir(self.package_folder):
+                save("include_build/protobuff.h", "int protubuff_stuff(){ return 1; }")
+                save("include_host/protobuff.h", "int protubuff_stuff(){ return 2; }")
+                save("build/my_tools_build.cmake", my_cmake_module % "1")
+                save("build/my_tools_host.cmake", my_cmake_module % "2")
+
+        def package_info(self):
+            # This info depends on self.context !!
+            self.cpp_info.includedirs = ["include_{}".format(self.context)]
+            path_build_modules = os.path.join("build", "my_tools_{}.cmake".format(self.context))
+            self.cpp_info.set_property("cmake_build_modules", [path_build_modules])
+
+    ''')
+    c.save({"conanfile.py": conanfile})
+    c.run("create . protobuff/1.0@")
+    return c
+
+
+main = textwrap.dedent("""
+    #include <iostream>
+    #include "protobuff.h"
+    #include "foo_generated.h"
+
+
+    int main(){
+        int ret = protubuff_stuff();
+
+        if(ret == 1){
+            std::cout << " Library from build context!" << std::endl;
+        }
+        else if(ret == 2){
+            std::cout << " Library from host context!" << std::endl;
+        }
+
+        // Variable declared at the foo_generated
+        if(from_context == 1){
+            std::cout << " Generated code in build context!" << std::endl;
+        }
+        else if(from_context == 2){
+            std::cout << " Generated code in host context!" << std::endl;
+        }
+        return 0;
+    }
+    """)
+
+consumer_conanfile = textwrap.dedent("""
+        import os
+        from conans import ConanFile
+        from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps
+
+        class Consumer(ConanFile):
+            settings = "build_type", "os", "arch", "compiler"
+            exports_sources = "CMakeLists.txt", "main.cpp"
+            requires = "protobuff/1.0"
+            build_requires = "protobuff/1.0"
+
+            def generate(self):
+                toolchain = CMakeToolchain(self)
+                toolchain.generate()
+
+                deps = CMakeDeps(self)
+                {}
+                deps.generate()
+
+            def build(self):
+                cmake = CMake(self)
+                cmake.configure()
+                cmake.build()
+                folder = str(self.settings.build_type) if self.settings.os == "Windows" else "."
+                self.run(os.sep.join([folder, "app"]))
+        """)
+
+
+def test_build_modules_from_build_context(client):
+    consumer_cmake = textwrap.dedent("""
+        set(CMAKE_CXX_COMPILER_WORKS 1)
+        set(CMAKE_CXX_ABI_COMPILED 1)
+        cmake_minimum_required(VERSION 3.15)
+        project(MyApp CXX)
+
+        find_package(protobuff)
+        find_package(protobuff_KK)
+        add_executable(app main.cpp)
+        foo_generate()
+        target_link_libraries(app protobuff::protobuff)
+        """)
+
+    cmake_deps_conf = """
+        deps.build_context_build_modules = ["protobuff"]
+        deps.build_context_suffix = {"protobuff": "_KK"}
+    """
+
+    client.save({"conanfile.py": consumer_conanfile.format(cmake_deps_conf),
+                 "CMakeLists.txt": consumer_cmake.format(cmake_deps_conf),
+                 "main.cpp": main})
+
+    client.run("create . app/1.0@ -pr:b default -pr:h default")
+    assert "Library from host context!" in client.out
+    assert "Generated code in build context!" in client.out
+
+
+def test_build_modules_and_target_from_build_context(client):
+    consumer_cmake = textwrap.dedent("""
+        set(CMAKE_CXX_COMPILER_WORKS 1)
+        set(CMAKE_CXX_ABI_COMPILED 1)
+        cmake_minimum_required(VERSION 3.15)
+        project(MyApp CXX)
+
+        find_package(protobuff)
+        find_package(protobuff_KK)
+        add_executable(app main.cpp)
+        foo_generate()
+        target_link_libraries(app protobuff_KK::protobuff_KK)
+        """)
+
+    cmake_deps_conf = """
+        deps.build_context_build_modules = ["protobuff"]
+        deps.build_context_suffix = {"protobuff": "_KK"}
+    """
+
+    client.save({"conanfile.py": consumer_conanfile.format(cmake_deps_conf),
+                 "CMakeLists.txt": consumer_cmake.format(cmake_deps_conf),
+                 "main.cpp": main})
+
+    client.run("create . app/1.0@ -pr:b default -pr:h default")
+    assert "Library from build context!" in client.out
+    assert "Generated code in build context!" in client.out
+
+
+def test_build_modules_from_host_and_target_from_build_context(client):
+    consumer_cmake = textwrap.dedent("""
+        set(CMAKE_CXX_COMPILER_WORKS 1)
+        set(CMAKE_CXX_ABI_COMPILED 1)
+        cmake_minimum_required(VERSION 3.15)
+        project(MyApp CXX)
+
+        find_package(protobuff)
+        find_package(protobuff_KK)
+        add_executable(app main.cpp)
+        foo_generate()
+        target_link_libraries(app protobuff_KK::protobuff_KK)
+        """)
+
+    cmake_deps_conf = """
+        deps.build_context_suffix = {"protobuff": "_KK"}
+    """
+
+    client.save({"conanfile.py": consumer_conanfile.format(cmake_deps_conf),
+                 "CMakeLists.txt": consumer_cmake.format(cmake_deps_conf),
+                 "main.cpp": main})
+
+    client.run("create . app/1.0@ -pr:b default -pr:h default")
+    assert "Library from build context!" in client.out
+    assert "Generated code in host context!" in client.out
+
+
+def test_build_modules_and_target_from_host_context(client):
+    consumer_cmake = textwrap.dedent("""
+        set(CMAKE_CXX_COMPILER_WORKS 1)
+        set(CMAKE_CXX_ABI_COMPILED 1)
+        cmake_minimum_required(VERSION 3.15)
+        project(MyApp CXX)
+
+        find_package(protobuff)
+        find_package(protobuff_KK)
+        add_executable(app main.cpp)
+        foo_generate()
+        target_link_libraries(app protobuff::protobuff)
+        """)
+
+    cmake_deps_conf = """
+        deps.build_context_build_modules = []
+        deps.build_context_suffix = {"protobuff": "_KK"}
+    """
+
+    client.save({"conanfile.py": consumer_conanfile.format(cmake_deps_conf),
+                 "CMakeLists.txt": consumer_cmake.format(cmake_deps_conf),
+                 "main.cpp": main})
+
+    client.run("create . app/1.0@ -pr:b default -pr:h default")
+    assert "Library from host context!" in client.out
+    assert "Generated code in host context!" in client.out
+
+
+def test_exception_when_not_prefix_specified(client):
+    consumer_cmake = textwrap.dedent("""
+        set(CMAKE_CXX_COMPILER_WORKS 1)
+        set(CMAKE_CXX_ABI_COMPILED 1)
+        cmake_minimum_required(VERSION 3.15)
+        project(MyApp CXX)
+
+        find_package(protobuff)
+        add_executable(app main.cpp)
+        foo_generate()
+        target_link_libraries(app protobuff::protobuff)
+        """)
+
+    cmake_deps_conf = """
+    """
+
+    client.save({"conanfile.py": consumer_conanfile.format(cmake_deps_conf),
+                 "CMakeLists.txt": consumer_cmake.format(cmake_deps_conf),
+                 "main.cpp": main})
+
+    client.run("create . app/1.0@ -pr:b default -pr:h default", assert_error=True)
+    assert "The package 'protobuff' exists both as 'require' and as 'build require'. " \
+           "You need to specify a suffix using the 'build_context_suffix' attribute at the " \
+           "CMakeDeps generator." in client.out
diff --git a/conans/test/unittests/tools/cmake/test_cmakedeps.py b/conans/test/unittests/tools/cmake/test_cmakedeps.py
index ad9249998f8..c897ff36f1a 100644
--- a/conans/test/unittests/tools/cmake/test_cmakedeps.py
+++ b/conans/test/unittests/tools/cmake/test_cmakedeps.py
@@ -13,6 +13,8 @@
 @pytest.mark.parametrize("using_properties", [True, False])
 def test_cpp_info_name_cmakedeps(using_properties):
     conanfile = ConanFile(Mock(), None)
+    conanfile._conan_node = Mock()
+    conanfile._conan_node.context = "host"
     conanfile.settings = "os", "compiler", "build_type", "arch"
     conanfile.initialize(Settings({"os": ["Windows"],
                                    "compiler": ["gcc"],
@@ -31,6 +33,8 @@ def test_cpp_info_name_cmakedeps(using_properties):
 
     conanfile_dep = ConanFile(Mock(), None)
     conanfile_dep.cpp_info = cpp_info
+    conanfile_dep._conan_node = Mock()
+    conanfile_dep._conan_node.context = "host"
 
     with mock.patch('conans.ConanFile.ref', new_callable=mock.PropertyMock) as mock_ref:
         with mock.patch('conans.ConanFile.dependencies', new_callable=mock.PropertyMock) as mock_deps:
@@ -40,6 +44,7 @@ def test_cpp_info_name_cmakedeps(using_properties):
             conanfile_dep.package_folder = "/path/to/folder_dep"
             conanfile.dependencies.transitive_host_requires = [ConanFileInterface(conanfile_dep)]
             conanfile.dependencies.host_requires = [ConanFileInterface(conanfile_dep)]
+            conanfile.dependencies.build_requires_build_context = []
 
             cmakedeps = CMakeDeps(conanfile)
             files = cmakedeps.content
@@ -52,6 +57,8 @@ def test_cpp_info_name_cmakedeps(using_properties):
 @pytest.mark.parametrize("using_properties", [True, False])
 def test_cpp_info_name_cmakedeps_components(using_properties):
     conanfile = ConanFile(Mock(), None)
+    conanfile._conan_node = Mock()
+    conanfile._conan_node.context = "host"
     conanfile.settings = "os", "compiler", "build_type", "arch"
     conanfile.initialize(Settings({"os": ["Windows"],
                                    "compiler": ["gcc"],
@@ -72,6 +79,8 @@ def test_cpp_info_name_cmakedeps_components(using_properties):
 
     conanfile_dep = ConanFile(Mock(), None)
     conanfile_dep.cpp_info = cpp_info
+    conanfile_dep._conan_node = Mock()
+    conanfile_dep._conan_node.context = "host"
 
     with mock.patch('conans.ConanFile.ref', new_callable=mock.PropertyMock) as mock_ref:
         with mock.patch('conans.ConanFile.dependencies', new_callable=mock.PropertyMock) as mock_deps:
@@ -81,6 +90,7 @@ def test_cpp_info_name_cmakedeps_components(using_properties):
             conanfile_dep.package_folder = "/path/to/folder_dep"
             conanfile.dependencies.transitive_host_requires = [ConanFileInterface(conanfile_dep)]
             conanfile.dependencies.host_requires = [ConanFileInterface(conanfile_dep)]
+            conanfile.dependencies.build_requires_build_context = []
 
             cmakedeps = CMakeDeps(conanfile)
             files = cmakedeps.content
@@ -96,6 +106,8 @@ def test_cpp_info_name_cmakedeps_components(using_properties):
 def test_cmake_deps_links_flags():
     # https://github.com/conan-io/conan/issues/8703
     conanfile = ConanFile(Mock(), None)
+    conanfile._conan_node = Mock()
+    conanfile._conan_node.context = "host"
     conanfile.settings = "os", "compiler", "build_type", "arch"
     conanfile.initialize(Settings({"os": ["Windows"],
                                    "compiler": ["gcc"],
@@ -110,6 +122,8 @@ def test_cmake_deps_links_flags():
     cpp_info.exelinkflags = ["-OPT:NOICF"]
     conanfile_dep = ConanFile(Mock(), None)
     conanfile_dep.cpp_info = cpp_info
+    conanfile_dep._conan_node = Mock()
+    conanfile_dep._conan_node.context = "host"
 
     with mock.patch('conans.ConanFile.ref', new_callable=mock.PropertyMock) as mock_ref:
         with mock.patch('conans.ConanFile.dependencies',
@@ -122,6 +136,7 @@ def test_cmake_deps_links_flags():
             conanfile_dep.package_folder = "/path/to/folder_dep"
             conanfile.dependencies.transitive_host_requires = [ConanFileInterface(conanfile_dep)]
             conanfile.dependencies.host_requires = [ConanFileInterface(conanfile_dep)]
+            conanfile.dependencies.build_requires_build_context = []
 
             cmakedeps = CMakeDeps(conanfile)
             files = cmakedeps.content


Code review comments:
diff_hunk: @@ -8,13 +8,37 @@ class CMakeDepsFileTemplate(object):
 
     def __init__(self, cmakedeps, req):
         self.cmakedeps = cmakedeps
-        if req is not None:
-            self.conanfile = req
-            self.pkg_name = req.ref.name
-            self.package_folder = req.package_folder.\
-                replace('\\', '/').replace('$', '\\$').replace('"', '\\"')
-            self.target_namespace = get_target_namespace(self.conanfile)
-            self.file_name = get_file_name(self.conanfile)
+        self.conanfile = req
+
+    @property
+    def pkg_name(self):
+        return self.conanfile.ref.name + self.suffix
+
+    @property
+    def package_folder(self):
+        return self.conanfile.package_folder.\
path: conan/tools/cmake/cmakedeps/templates/__init__.py
text: @user1:
This name is a bit confusing, it will return a escaped package_folder