Repository: conan-io/conan

Issue:
[question] Is new cmake_layout compatible with cpp_info.components ?
Hi, I've been using CMakeToolchain for a while with the CMake build helper that comes with it.
But after updating today I saw that `CMake` build helper does not accept a `build_folder` parameter anymore.

Looking at why it happened I arrived at https://github.com/conan-io/conan/pull/8554/files#diff-d72013a45b00a0adf06f4536d6a8c8844461e51b72911937d63e6dda9a3d440aR64 this means that the new way of providing the folder topology is via `def layout(self)` right?

My first move was to employ the new `cmake_layout` utility, but I was unable to create a package if this one used `self.cpp_info.components`

```
ERROR: 
	ConanException: say/0.1 package_info(): self.cpp_info.components cannot be used with self.cpp_info global values at the same time
```

Conanfile example:
```
from conans import ConanFile, CMake
from conan.tools.layout import cmake_layout, LayoutPackager

class Pkg(ConanFile):
    name = "say"
    version = "0.1"
    settings = "os", "compiler", "arch", "build_type"
    generators = "cmake"
    exports_sources = "src/*"

    def layout(self):
        cmake_layout(self)

    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()

    def package(self):
        LayoutPackager(self).package()

    def package_info(self):
        self.cpp_info.components["say"].libs = ["say"]
```

So, I am doing something wrong? Is this intended or just a bug/missing feature?

Thanks!

- [x] I've read the [CONTRIBUTING guide](https://github.com/conan-io/conan/blob/develop/.github/CONTRIBUTING.md).


Discussion:
Hi @Hopobcn 

I have managed to reproduce this, indeed seems a bug. Thanks for the complete ``conanfile.py`` to reproduce, we'll check it asap.
Apparently doing:

```python
            settings = "os", "arch", "compiler", "build_type"

            def layout(self):
                self.cpp.package.components["say"].includedirs = ["include"]
```
Fixes the issue. However, I think we intended to keep supporting the other ``package_info()`` definition as well for ``self.cpp_info`` that would be equivalent to ``self.cpp.package``. Probably need the input of @lasote here.
BTW, the test to reproduce is:

```python
def test_components_error():
    # https://github.com/conan-io/conan/issues/9331
    client = TestClient()

    conan_hello = textwrap.dedent("""
        import os
        from conans import ConanFile

        from conan.tools.files import save
        class Pkg(ConanFile):
            settings = "os", "arch", "compiler", "build_type"

            def layout(self):
                pass

            def package_info(self):
                self.cpp_info.components["say"].includedirs = ["include"]
            """)

    client.save({"conanfile.py": conan_hello})
    client.run("create . hello/1.0@")
```

It is fixed by adding ``self.cpp.package.components["say"].includedirs = ["include"]`` to ``layout()`` (then the ``package_info()`` can be removed too, or can stay, it pass either way.
Thanks for the fast reply!  Yep, can confirm that using the `self.cpp.package.components` notation works. 
Also, note to other readers, `.names` property seems to not be accepted with `self.cpp.package.components`. Entries like `self.cpp_info.components["say"].names["cmake_find_package"] = "Say"`  must be translated to `self.cpp.package.components["say"].set_property("cmake_find_package", "Say")`.

@memsharded I'm not sure that the generator (`cmake_find_package`) is able to generate code for `self.cpp.package.components`.  

Using a test_package like this:

```
cmake_minimum_required(VERSION 3.8)
project(test_package)

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()

find_package(say REQUIRED)

add_executable(test_package test_package.cpp)
target_link_libraries(test_package PRIVATE say::Say)
```



```
from conans import ConanFile, CMake, tools
import os

class TestConan(ConanFile):
    settings = "os", "compiler", "build_type", "arch"
    generators = "cmake", "cmake_find_package"

    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()

    def test(self):
        if not tools.cross_building(self.settings):
            bin_path = os.path.join("bin", "test_pacakge")
            self.run(bin_path, run_environment=True)
```

The resulting `Findsay.cmake` doesn't contain any reference to `components["say"]`.

Hi @Hopobcn 

yes, please check the warning notes in https://docs.conan.io/en/latest/reference/conanfile/methods.html#layout.

It is extremely risky to try to introduce the ``layout()`` functionality changes in the old generators. Only the new ones will fully support this functionality (Note that internally we are replacing all the logic of the generators to work, from the ``self.dependencies``, to new ``cpp_info`` structure definitions.)
@lasote This error also happens here: https://github.com/conan-io/conan-center-index/pull/6578

Probably the workaround suggested by @memsharded would work here, but that would require a full refactor of the `package_info` method (not ideal)
on my way!

Resolving patch:
diff --git a/conans/client/installer.py b/conans/client/installer.py
--- a/conans/client/installer.py
+++ b/conans/client/installer.py
@@ -699,9 +699,14 @@ def _call_package_info(self, conanfile, package_folder, ref, is_editable):
 
                     if conanfile._conan_dep_cpp_info is None:
                         try:
-                            if not is_editable:
+                            if not is_editable and not hasattr(conanfile, "layout"):
                                 # FIXME: The default for the cppinfo from build are not the same
                                 #        so this check fails when editable
+                                # FIXME: Remove when new cppinfo model. If using the layout method
+                                #        the cppinfo object is filled from self.cpp.package new
+                                #        model and we cannot check if the defaults have been modified
+                                #        because it doesn't exist in the new model where the defaults
+                                #        for the components are always empty
                                 conanfile.cpp_info._raise_incorrect_components_definition(
                                     conanfile.name, conanfile.requires)
                         except ConanException as e:


Test patch:
diff --git a/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py b/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
--- a/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
+++ b/conans/test/integration/toolchains/cmake/cmakedeps/test_cmakedeps.py
@@ -62,3 +62,26 @@ class Pkg(ConanFile):
     client.run("install . -s:b os=Windows -s:h os=Linux --build=missing")
     cmake_data = client.load("pkg-release-x86_64-data.cmake")
     assert "gtest" not in cmake_data
+
+
+def test_components_error():
+    # https://github.com/conan-io/conan/issues/9331
+    client = TestClient()
+
+    conan_hello = textwrap.dedent("""
+        import os
+        from conans import ConanFile
+
+        from conan.tools.files import save
+        class Pkg(ConanFile):
+            settings = "os", "arch", "compiler", "build_type"
+
+            def layout(self):
+                pass
+
+            def package_info(self):
+                self.cpp_info.components["say"].includedirs = ["include"]
+            """)
+
+    client.save({"conanfile.py": conan_hello})
+    client.run("create . hello/1.0@")