.. _creating_packages_add_dependencies_to_packages: Add dependencies to packages ============================ In the :ref:`previous tutorial section`, we created a Conan package for a "Hello World" C++ library. We used the :ref:`conan.tools.scm.Git()` tool to retrieve the sources from a git repository. So far, the package does not have any dependency on other Conan packages. Let's explain how to add a dependency to our package in a very similar way to how we did in the :ref:`consuming packages section`. We will add some fancy colour output to our "Hello World" library using the `fmt `__ library. Please, first clone the sources to recreate this project. You can find them in the `examples2 repository `_ on GitHub: .. code-block:: bash $ git clone https://github.com/conan-io/examples2.git $ cd examples2/tutorial/creating_packages/add_requires You will notice some changes in the `conanfile.py` file from the previous recipe. Let's check the relevant parts: .. code-block:: python ... from conan.tools.build import check_max_cppstd, check_min_cppstd ... class helloRecipe(ConanFile): name = "hello" version = "1.0" ... generators = "CMakeDeps" ... def validate(self): check_min_cppstd(self, "11") check_max_cppstd(self, "20") def requirements(self): self.requires("fmt/8.1.1") def source(self): git = Git(self) git.clone(url="https://github.com/conan-io/libhello.git", target=".") # Please, be aware that using the head of the branch instead of an immutable tag # or commit is not a good practice in general git.checkout("require_fmt") * First, we set the ``generators`` class attribute to make Conan invoke the :ref:`CMakeDeps` generator. This was not needed in the previous recipe as we did not have dependencies. ``CMakeDeps`` will generate all the config files that CMake needs to find the ``fmt`` library. * Next, we use the :ref:`requires()` method to add the `fmt `__ dependency to our package. * Note that we added an extra line in the :ref:`source()` method. We use the ``Git().checkout()`` method to checkout the source code in the `require_fmt `__ branch. This branch contains the changes in the source code to add colours to the library messages, and also in the ``CMakeLists.txt`` to declare that we are using the ``fmt`` library. * Finally, note we added the :ref:`validate()` method to the recipe. We already used this method in the :ref:`consuming packages section` to raise an error for non-supported configurations. Here, we call the functions :ref:`check_min_cppstd()` and :ref:`check_max_cppstd()` to verify that we are using at least C++11 and at most C++20 standards in our settings. You can check the new sources using the fmt library in the `require_fmt `__ branch. You will see that the `hello.cpp `__ file adds colours to the output messages: .. code-block:: cpp #include #include "hello.h" void hello(){ #ifdef NDEBUG fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, "hello/1.0: Hello World Release!\n"); #else fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, "hello/1.0: Hello World Debug!\n"); #endif ... Let's build the package from sources with the current default configuration, and then let the ``test_package`` folder test the package. You should see the output messages with colour now: .. code-block:: bash $ conan create . --build=missing -------- Exporting the recipe ---------- ... -------- Testing the package: Running test() ---------- hello/1.0 (test package): Running test() hello/1.0 (test package): RUN: ./example hello/1.0: Hello World Release! hello/1.0: __x86_64__ defined hello/1.0: __cplusplus 201103 hello/1.0: __GNUC__ 4 hello/1.0: __GNUC_MINOR__ 2 hello/1.0: __clang_major__ 13 hello/1.0: __clang_minor__ 1 hello/1.0: __apple_build_version__ 13160021 .. _tutorial_create_packages_headers_transitivity: Headers transitivity -------------------- By default, Conan assumes that the required dependency headers are an implementation detail of the current package, to promote good software engineering practices like low coupling and encapsulation. In the example above, ``fmt`` is purely an implementation detail in the ``hello/1.0`` package. Consumers of ``hello/1.0`` will not know anything about ``fmt``, or has access to its headers, if a consumer of ``hello/1.0`` would try to add a ``#include ``, it will fail, not being able to find that headers. But if the public headers of the ``hello/1.0`` package have the ``#include`` to ``fmt`` headers, that means that such headers must be propagated down to allow consumers of ``hello/1.0`` to be compiled successfully. As this is not the default expected behavior, recipes must declare it as: .. code-block:: python class helloRecipe(ConanFile): name = "hello" version = "1.0" def requirements(self): self.requires("fmt/8.1.1", transitive_headers=True) That will propagate the necessary compilation flags and headers ``includedirs`` to the consumers of ``hello/1.0``. .. note:: **Best practices** If a consumer of ``hello/1.0`` had a direct inclusion to ``fmt`` headers such as ``#include ``, then, such a consumer should declare its own ``self.requires("fmt/8.1.1")`` requirement, as that is a direct requirement. In other words, even if the dependency to ``hello/1.0`` was removed from that consumer, it would still depend on ``fmt``, and consequently it cannot abuse the transitivity of the ``fmt`` headers from ``hello``, but declare them explicitly. .. seealso:: - `JFrog Academy Conan 2 Essentials: Dependencies, Generators And Building `__ - :ref:`Reference for requirements() method `. - :ref:`Introduction to versioning `.