.. _examples_conanfile_package_info_components: Define components for Conan packages that provide multiple libraries ==================================================================== At the :ref:`section of the tutorial about the package_info() method `, we learned how to define information in a package for consumers, such as library names or include and library folders. In the tutorial, we created a package with only one library that consumers linked to. However, in some cases, libraries provide their functionalities separated into different *components*. These components can be consumed independently, and in some cases, they may require other components from the same library or others. For example, consider a library like OpenSSL that provides *libcrypto* and *libssl*, where *libssl* depends on *libcrypto*. Conan provides a way to abstract this information using the `components` attribute of the `CppInfo` object to define the information for each separate component of a Conan package. Consumers can also select specific components to link against but not the rest of the package. Let's take a game-engine library as an example, which provides several components such as *algorithms*, *ai*, *rendering*, and *network*. Both *ai* and *rendering* depend on the *algorithms* component. .. graphviz:: :caption: components of the game-engine package digraph components { node [fillcolor="lightskyblue", style=filled, shape=box] algorithms -> ai; algorithms -> rendering; ai; algorithms; network; } Please, first clone the sources to recreate this project. You can find them in the `examples2 repository `_ in GitHub: .. code-block:: bash $ git clone https://github.com/conan-io/examples2.git $ cd examples2/examples/conanfile/package_info/components You can check the contents of the project: .. code-block:: text . ├── CMakeLists.txt ├── conanfile.py ├── include │ ├── ai.h │ ├── algorithms.h │ ├── network.h │ └── rendering.h ├── src │ ├── ai.cpp │ ├── algorithms.cpp │ ├── network.cpp │ └── rendering.cpp └── test_package ├── CMakeLists.txt ├── CMakeUserPresets.json ├── conanfile.py └── src └── example.cpp As you can see, there are sources for each of the components and a CMakeLists.txt file to build them. We also have a `test_package` that we are going to use to test the consumption of the separate components. First, let's have a look at package_info() method in the *conanfile.py* and how we declared the information for each component that we want to provide to the consumers of the game-engine package: .. code-block:: python ... def package_info(self): self.cpp_info.components["algorithms"].libs = ["algorithms"] self.cpp_info.components["algorithms"].set_property("cmake_target_name", "algorithms") self.cpp_info.components["network"].libs = ["network"] self.cpp_info.components["network"].set_property("cmake_target_name", "network") self.cpp_info.components["ai"].libs = ["ai"] self.cpp_info.components["ai"].requires = ["algorithms"] self.cpp_info.components["ai"].set_property("cmake_target_name", "ai") self.cpp_info.components["rendering"].libs = ["rendering"] self.cpp_info.components["rendering"].requires = ["algorithms"] self.cpp_info.components["rendering"].set_property("cmake_target_name", "rendering") There are a couple of relevant things: - We declare the libraries generated by each of the components by setting information in the ``cpp_info.components`` attribute. You can set the same information for each of the components as you would for the ``self.cpp_info`` object. The ``cpp_info`` for components has some defaults defined, just like it does for :ref:`self.cpp_info`. For example, the ``cpp_info.components`` object provides the ``.includedirs`` and ``.libdirs`` properties to define those locations, but Conan sets their value as ``["lib"]`` and ``["include"]`` by default, so it's not necessary to add them in this case. - We are also declaring the components' dependencies using the ``.requires`` attribute. With this attribute, you can declare requirements at the component level, not only for components in the same recipe but also for components from other packages that are declared as requires of the Conan package. - We are changing the default target names for the components using the :ref:`properties model`. By default, Conan sets a target name for components like ````, but for this tutorial we will set the component target names just with the component names omitting the ``::``. You can have a look at the consumer part by checking the *test_package* folder. First the *conanfile.py*: .. code-block:: python ... def generate(self): deps = CMakeDeps(self) deps.check_components_exist = True deps.generate() You can see that we are setting the :ref:`check_components_exist ` property for CMakeDeps. This is not needed, just to show how you can do if you want your consumers to fail if the component does not exist. So, the CMakeLists.txt could look like this: .. code-block:: text cmake_minimum_required(VERSION 3.15) project(PackageTest CXX) find_package(game-engine REQUIRED COMPONENTS algorithms network ai rendering) add_executable(example src/example.cpp) target_link_libraries(example algorithms network ai rendering) And the ``find_package()`` call would fail if any of the components targets do not exist. Let's run the example: .. code-block:: text $ conan create . ... game-engine/1.0: RUN: cmake --build "/Users/barbarian/.conan2/p/t/game-d6e361d329116/b/build/Release" -- -j16 [ 12%] Building CXX object CMakeFiles/algorithms.dir/src/algorithms.cpp.o [ 25%] Building CXX object CMakeFiles/network.dir/src/network.cpp.o [ 37%] Linking CXX static library libnetwork.a [ 50%] Linking CXX static library libalgorithms.a [ 50%] Built target network [ 50%] Built target algorithms [ 62%] Building CXX object CMakeFiles/ai.dir/src/ai.cpp.o [ 75%] Building CXX object CMakeFiles/rendering.dir/src/rendering.cpp.o [ 87%] Linking CXX static library libai.a [100%] Linking CXX static library librendering.a [100%] Built target ai [100%] Built target rendering ... ======== Launching test_package ======== ... -- Conan: Component target declared 'algorithms' -- Conan: Component target declared 'network' -- Conan: Component target declared 'ai' -- Conan: Component target declared 'rendering' ... [ 50%] Building CXX object CMakeFiles/example.dir/src/example.cpp.o [100%] Linking CXX executable example [100%] Built target example ======== Testing the package: Executing test ======== game-engine/1.0 (test package): Running test() game-engine/1.0 (test package): RUN: ./example I am the algorithms component! I am the network component! I am the ai component! └───> I am the algorithms component! I am the rendering component! └───> I am the algorithms component! You could check that requiring a component that does not exist will raise an error. Add the *nonexistent* component to the find_package() call: .. code-block:: text cmake_minimum_required(VERSION 3.15) project(PackageTest CXX) find_package(game-engine REQUIRED COMPONENTS nonexistent algorithms network ai rendering) add_executable(example src/example.cpp) target_link_libraries(example algorithms network ai rendering) And test the package again: .. code-block:: text $ conan test test_package game-engine/1.0 ... Conan: Component 'nonexistent' NOT found in package 'game-engine' Call Stack (most recent call first): CMakeLists.txt:4 (find_package) -- Configuring incomplete, errors occurred! ... ERROR: game-engine/1.0 (test package): Error in build() method, line 22 cmake.configure() ConanException: Error 1 while executing .. seealso:: If you want to use recipes defining components in ``editable`` mode, check the example in :ref:`examples_conanfile_layout_components_editables`.