Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[question] Why is the default component name not checked when resolving components with check_components_exist? #17689

Open
1 task done
Kogzedri opened this issue Feb 3, 2025 · 1 comment
Assignees

Comments

@Kogzedri
Copy link

Kogzedri commented Feb 3, 2025

What is your question?

I've created a library created with several components in the following manner:

class ExampleRecipe(ConanFile):
    name = "example"
    version= "1.0.0"
    package_type = "header-library"

    settings = "os", "compiler", "build_type", "arch"

    exports_sources = "CMakeLists.txt", "src/*"          

    def layout(self):
        cmake_layout(self)
    
    def generate(self):
        deps = CMakeDeps(self)
        deps.generate()
        tc = CMakeToolchain(self)
        tc.generate()

    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["asdf"].requires = []

When trying to consume the above library:

class ConsumerRecipe(ConanFile):
    ...
   def requirements(self):
        self.requires('example/1.0.0')
    def generate(self)
        deps = CMakeDeps(self)
        deps.check_components_exist=True
        deps.generate()
        tc = CMakeToolchain(self)
        tc.generate()
    ...
find_package(example REQUIRED COMPONENTS asdf)
set(${tgt} consume_test)
add_executable(${tgt})
...
target_link_libraries(${tgt}
    PRIVATE
        example::asdf
)

Relevant output:

======== Calling build() ========
conanfile.py (consume_test/1.0.0): Calling build()
conanfile.py (consume_test/1.0.0): Running CMake.configure()
conanfile.py (consume_test/1.0.0): RUN: cmake -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE="generators/conan_toolchain.cmake" -DCMAKE_INSTALL_PREFIX="/path/to/consume_test" -DCMAKE_POLICY_DEFAULT_CMP0091="NEW" -DCMAKE_BUILD_TYPE="Release" "/path/to/consume_test"
-- Using Conan toolchain: /path/to/consume_test/build/Release/generators/conan_toolchain.cmake
-- Conan toolchain: Defining architecture flag: -m64
-- Conan toolchain: C++ Standard 17 with extensions ON
-- Conan: Component target declared 'example::asdf'
-- Conan: Target declared 'example::example'
CMake Error at build/Release/generators/example-config.cmake:48 (message):
  Conan: Component 'asdf' NOT found in package 'example'
Call Stack (most recent call first):
  src/CMakeLists.txt:1 (find_package)

When specifying CMakeDeps.check_components_exists, only the strict component name seems to get checked. The generated CMake code doesn't check the default namespaced package_name::component target, despite it being declared earlier during processing.

The culprit seems to be here: config.py, checking only if(TARGET _FIND_COMPONENT)

My ultimate question boils down to: why is the above template CMake code not checking: if((TARGET _FIND_COMPONENT) OR (TARGET ${CMAKE_FIND_PACKAGE_NAME}::${_FIND_COMPONENTS})? Does that cause some kind of other problem that I'm just not seeing?

Have you read the CONTRIBUTING guide?

  • I've read the CONTRIBUTING guide
@Kogzedri Kogzedri changed the title [question] Why the default component name not checked with resolving components with check_components_exist? [question] Why is the default component name not checked with resolving components with check_components_exist? Feb 3, 2025
@Kogzedri Kogzedri changed the title [question] Why is the default component name not checked with resolving components with check_components_exist? [question] Why is the default component name not checked when resolving components with check_components_exist? Feb 3, 2025
@memsharded memsharded self-assigned this Feb 3, 2025
@memsharded
Copy link
Member

Hi @Kogzedri

Thanks for your question.

This is a known limitation of the current CMakeDeps generator.
See the following unit test:

def test_components_required():
    # https://github.com/conan-io/conan/issues/17689
    conanfile = textwrap.dedent("""
        from conan import ConanFile
        class ExampleRecipe(ConanFile):
            name = "example"
            version = "1.0.0"
            package_type = "header-library"
            settings = "os", "compiler", "build_type", "arch"
            exports_sources = "CMakeLists.txt", "src/*"

            def package_info(self):
                self.cpp_info.components["asdf"].requires = []
        """)
    consumer = textwrap.dedent("""
        from conan import ConanFile
        from conan.tools.cmake import CMakeDeps, CMakeToolchain, CMake
        class ConsumerRecipe(ConanFile):
            settings = "os", "arch", "compiler", "build_type"
            def requirements(self):
                self.requires('example/1.0.0')
            def generate(self):
                deps = CMakeDeps(self)
                deps.check_components_exist=True
                deps.generate()
                CMakeToolchain(self).generate()
            def build(self):
                cmake = CMake(self)
                cmake.configure()
                cmake.build()
        """)
    cmake = textwrap.dedent("""
        cmake_minimum_required(VERSION 3.15)
        project(consumer)
        find_package(example REQUIRED COMPONENTS example::asdf)
        """)
    c = TestClient()
    c.save({"example/conanfile.py": conanfile,
            "consumer/conanfile.py": consumer,
            "consumer/CMakeLists.txt": cmake})
    c.run("create example")
    c.run("build consumer")
    print(c.out)
    # seems to work fine

Note it has to use the COMPONENTS as the example::asdf, not the asdf alone. That might be changed using the set_property("cmake_target_name"), but by default, it requires the full name.

This has already been improved in the new "incubating" CMakeDeps generator, see https://docs.conan.io/2/incubating.html

It can be validated in the above test, changing

    find_package(example REQUIRED COMPONENTS asdf)
    ...
    c.run("build consumer -c tools.cmake.cmakedeps:new=will_break_next")

Also, the deps.check_components_exist=True is not necessary in the incubating new CMakeDeps, component validation is done by default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants