From d4947a52b7ce6ad070b900237844546c4620522d Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 6 Feb 2023 01:27:49 +0100 Subject: [PATCH 01/28] [develop2] reference methods --- reference/conanfile/methods.rst | 199 ++++-------------- reference/conanfile/methods/build.rst | 48 +++++ reference/conanfile/methods/build_id.rst | 58 +++++ .../conanfile/methods/build_requirements.rst | 52 +++++ reference/conanfile/methods/compatibility.rst | 46 ++++ .../conanfile/methods/config_options.rst | 16 ++ reference/conanfile/methods/configure.rst | 60 ++++++ reference/conanfile/methods/export.rst | 15 ++ .../conanfile/methods/export_sources.rst | 59 ++++++ reference/conanfile/methods/generate.rst | 4 + reference/conanfile/methods/init.rst | 4 + reference/conanfile/methods/layout.rst | 4 + reference/conanfile/methods/package.rst | 4 + reference/conanfile/methods/package_id.rst | 4 + reference/conanfile/methods/package_info.rst | 4 + reference/conanfile/methods/requirements.rst | 121 +++++++++++ reference/conanfile/methods/set_name.rst | 5 + reference/conanfile/methods/set_version.rst | 5 + reference/conanfile/methods/source.rst | 5 + .../conanfile/methods/system_requirements.rst | 5 + reference/conanfile/methods/test.rst | 5 + reference/conanfile/methods/validate.rst | 6 + .../conanfile/methods/validate_build.rst | 33 +++ .../add_dependencies_to_packages.rst | 6 +- .../configure_options_settings.rst | 2 +- 25 files changed, 609 insertions(+), 161 deletions(-) create mode 100644 reference/conanfile/methods/build.rst create mode 100644 reference/conanfile/methods/build_id.rst create mode 100644 reference/conanfile/methods/build_requirements.rst create mode 100644 reference/conanfile/methods/compatibility.rst create mode 100644 reference/conanfile/methods/config_options.rst create mode 100644 reference/conanfile/methods/configure.rst create mode 100644 reference/conanfile/methods/export.rst create mode 100644 reference/conanfile/methods/export_sources.rst create mode 100644 reference/conanfile/methods/generate.rst create mode 100644 reference/conanfile/methods/init.rst create mode 100644 reference/conanfile/methods/layout.rst create mode 100644 reference/conanfile/methods/package.rst create mode 100644 reference/conanfile/methods/package_id.rst create mode 100644 reference/conanfile/methods/package_info.rst create mode 100644 reference/conanfile/methods/requirements.rst create mode 100644 reference/conanfile/methods/set_name.rst create mode 100644 reference/conanfile/methods/set_version.rst create mode 100644 reference/conanfile/methods/source.rst create mode 100644 reference/conanfile/methods/system_requirements.rst create mode 100644 reference/conanfile/methods/test.rst create mode 100644 reference/conanfile/methods/validate.rst create mode 100644 reference/conanfile/methods/validate_build.rst diff --git a/reference/conanfile/methods.rst b/reference/conanfile/methods.rst index 59eed06ce221..bb220b5cda63 100644 --- a/reference/conanfile/methods.rst +++ b/reference/conanfile/methods.rst @@ -1,162 +1,47 @@ -.. spelling:: - - ing - ver - -.. _conan_conanfile_methods: +.. _reference_conanfile_methods: Methods ======= -requirements() --------------- - -Requirement traits -^^^^^^^^^^^^^^^^^^ - -Traits are properties of a requires clause. They determine how various parts of a -dependency are treated and propagated by Conan. Values for traits are usually computed by -Conan based on dependency's :ref:`reference_conanfile_attributes_package_type`, but can -also be specified manually. - -A good introduction to traits is provided in the `Advanced Dependencies Model in Conan 2.0 -`_ presentation. - -In the example below ``headers`` and ``libs`` are traits. - -.. code-block:: python - - self.requires("math/1.0", headers=True, libs=True) - - -headers -~~~~~~~ - -Indicates that there are headers that are going to be ``#included`` from this package at -compile time. The dependency will be in the host context. - -libs -~~~~ - -The dependency contains some library or artifact that will be used at link time of the -consumer. This trait will typically be ``True`` for direct shared and static libraries, -but could be false for indirect static libraries that are consumed via a shared library. -The dependency will be in the host context. - -build -~~~~~ - -This dependency is a build tool, an application or executable, like cmake, that is used -exclusively at build time. It is not linked/embedded into binaries, and will be in the -build context. - -run -~~~ - -This dependency contains some executables, either apps or shared libraries that need to be -available to execute (typically in the path, or other system env-vars). This trait can be -``True`` for ``build=False``, in that case, the package will contain some executables that -can run in the host system when installing it, typically like an end-user application. -This trait can be ``True`` for ``build=True``, the package will contain executables that -will run in the build context, typically while being used to build other packages. - -visible -~~~~~~~ - -This ``require`` will be propagated downstream, even if it doesn't propagate ``headers``, -``libs`` or ``run`` traits. Requirements that propagate downstream can cause version -conflicts. This is typically ``True``, because in most cases, having 2 different versions of -the same library in the same dependency graph is at least complicated, if not directly -violating ODR or causing linking errors. It can be set to ``False`` in advanced scenarios, -when we want to use different versions of the same package during the build. - -transitive_headers -~~~~~~~~~~~~~~~~~~ - -If ``True`` the headers of the dependency will be visible downstream. - -transitive_libs -~~~~~~~~~~~~~~~ - -If ``True`` the libraries to link with of the dependency will be visible downstream. - -test -~~~~ - -This requirement is a test library or framework, like Catch2 or gtest. It is mostly a -library that needs to be included and linked, but that will not be propagated downstream. - -package_id_mode -~~~~~~~~~~~~~~~ - -If the recipe wants to specify how the dependency version affects the current package -``package_id``, can be directly specified here. - -While it could be also done in the ``package_id()`` method, it seems simpler to be able to -specify it in the ``requires`` while avoiding some ambiguities. - -.. code-block:: python - - # We set the package_id_mode so it is part of the package_id - self.tool_requires("tool/1.1.1", package_id_mode="minor_mode") - -Which would be equivalent to: - -.. code-block:: python - - def package_id(self): - self.info.requires["tool"].minor_mode() - -force -~~~~~ - -This ``requires`` will force its version in the dependency graph upstream, overriding -other existing versions even of transitive dependencies, and also solving potential -existing conflicts. - -override -~~~~~~~~ - -The same as the ``force`` trait, but not adding a ``direct`` dependency. If there is no -transitive dependency to override, this ``require`` will be discarded. This trait only -exists at the time of defining a ``requires``, but it will not exist as an actual -``requires`` once the graph is fully evaluated - -direct -~~~~~~ - -If the dependency is a direct one, that is, it has explicitly been declared by the current -recipe, or if it is a transitive one. - - -validate_build() ----------------- - -The ``validate_build()`` method is used to verify if a configuration is valid for building a package. It is different -from the ``validate()`` method that checks if the binary package is "impossible" or invalid for a given configuration. - -The ``validate()`` method should do the checks of the settings and options using the ``self.info.settings`` -and ``self.info.options``. - -The ``validate_build()`` method has to use always the ``self.settings`` and ``self.options``: - -.. code-block:: python - - from conan import ConanFile - from conan.errors import ConanInvalidConfiguration - class myConan(ConanFile): - name = "foo" - version = "1.0" - settings = "os", "arch", "compiler" - def package_id(self): - # For this package, it doesn't matter the compiler used for the binary package - del self.info.settings.compiler - def validate_build(self): - # But we know this cannot be build with "gcc" - if self.settings.compiler == "gcc": - raise ConanInvalidConfiguration("This doesn't build in GCC") - def validate(self): - # We shouldn't check here the self.info.settings.compiler because it has been removed in the package_id() - # so it doesn't make sense to check if the binary is compatible with gcc because the compiler doesn't matter - pass +.. toctree:: + :maxdepth: 1 + :hidden: + + methods/build + methods/build_id + methods/build_requirements + methods/compatibility + methods/configure + methods/config_options + methods/export + methods/export_sources + methods/generate + methods/init + methods/layout + methods/package + methods/package_id + methods/package_info + methods/requirements + methods/set_name + methods/set_version + methods/source + methods/system_requirements + methods/test + methods/validate + methods/validate_build + + +- :doc:`build() `: Contains the build instructions to build a package from source +- :doc:`build_id() `: Allows reusing the same build to create different package binaries +- :doc:`build_requirements() `: Defines ``tool_requires`` and ``test_requires`` +- :doc:`compatibility() `: Defines binary compatibility at the recipe level +- :doc:`configure `: Allows configuring settings and options while computing dependencies +- :doc:`config_options `: Configure options while computing dependency graph +- :doc:`export `: Copies files that are part of the recipe +- :doc:`export_sources `: Copies files that are part of the recipe sources +- :doc:`generate `: Generates the files that are necessary for building the package +- :doc:`init `: Special initialization of recipe when extending from ``python_requires`` +- :doc:`layout `: Defines the relative project layout, source folders, build folders, etc. +- :doc:`package `: Copies files from build folder to the package folder. +- :doc:`package_id `: Defines special logic for computing the ``package_id`` diff --git a/reference/conanfile/methods/build.rst b/reference/conanfile/methods/build.rst new file mode 100644 index 000000000000..9d3c40b19ffe --- /dev/null +++ b/reference/conanfile/methods/build.rst @@ -0,0 +1,48 @@ +.. _reference_conanfile_methods_build: + +build() +======= + +The ``build()`` method is used to define the build from source of the package. In practice this means calling some build system, which could be done explictly or using any of the build helpers provided by Conan: + + +.. code-block:: python + + from conan.tools.cmake import CMake + + clas Pkg(ConanFile): + + def build(self): + # Either using some of the Conan built-in helpers + cmake = CMake(self) + cmake.configure() # equivalent to self.run("cmake . ") + cmake.build() # equivalent to self.run("cmake --build . ") + cmake.test() # equivalent to self.run("cmake --target=RUN_TESTS") + + # Or it could run your own build system or scripts + self.run("mybuildsystem . --configure") + self.run("mybuildsystem . --build") + + +For more information about the existing built-in build system integrations, visit :ref:`conan_tools`. + +The ``build()`` method should be as simple as possible, just wrapping the command line invocations +that a developer would do in the simplest possible way. The ``generate()`` method is the responsible +for preparing the build, creating toolchain file, CMake presets, or whatever other files are necessary +so developers can easily call the build system by hand easily. This way the integration with IDEs and +the developer experience is much better. The result is that the ``build()`` method should be relatively +simple in practice. + +The ``build()`` method is the right place to build and run unit tests, before packaging, and raising errors if those tests fail, interrupting the process, and not even packaging the final binaries. +The built-in helpers will skip the unit tests if ``tools.build:skip_test`` configuration is defined, for custom integrations, it is expected that the method checks this ``conf`` value in order to skip building and running tests, which can be useful for some CI scenarios. + +The ``build()`` method runs once per different configuration, so if there are some source operations like applying patches that are done conditionally to different configurations, they could be also applied in the +``build()`` method, before the actual build. It is important that in this case the ``no_copy_source`` attribute cannot be set to ``True``. + + + +.. note:: + + **Best practices** + + - The ``build()`` should be as simple as possible, the heavy lifting of preparing the build should happen in the ``generate()`` method, in order to achieve a good developer experience that can easily build locally with just ``conan install .``, plus directly calling the build system or opening their IDE. \ No newline at end of file diff --git a/reference/conanfile/methods/build_id.rst b/reference/conanfile/methods/build_id.rst new file mode 100644 index 000000000000..af02c9abf594 --- /dev/null +++ b/reference/conanfile/methods/build_id.rst @@ -0,0 +1,58 @@ +.. _reference_conanfile_methods_build_id: + +build_id() +========== + +The ``build_id()`` method allows to re-use the same build to create different binary packages in the cache, +potentially saving build time as it can avoid some unnecessary re-builds. It is an optimization method. + +In the general case, there is one build folder for each binary package, with the exact same ``package_id`` of the package. However this behavior +can be changed, there are a couple of scenarios that this might be useful: + +- The package build scripts generates several different configurations at once (like both debug and release artifacts) in the same run, without the possibility of building each configuration separately. +- The package build scripts generate one binary configuration, but different artifacts that can be packaged separately. For example if there are some test executables, you might want to create two packages: one just containing the library for general usage, and another one also containing the tests (for compliance, later reproducibility, debugging, etc). + +In the first case, we could write for example: + +.. code-block:: python + + settings = "os", "compiler", "arch", "build_type" + + def build_id(self): + self.info_build.settings.build_type = "Any" + +This recipe will generate a final different package with a different ``package_id`` for debug and release configurations. But as the ``build_id()`` will generate the +same ``build_id`` for any ``build_type``, then just one folder and one ``build()`` will be done, building both debug and release artifacts, +and then the ``package()`` method will be called for each configuration, and it should package the artifacts conditionally to the ``self.settings.build_type`` value. Different builds will still be +executed if using different compilers or architectures. + +Other information like custom package options can also be changed: + +.. code-block:: python + + def build_id(self): + self.info_build.options.myoption = 'MyValue' # any value possible + self.info_build.options.fullsource = 'Always' + +If the ``build_id()`` method does not modify the ``info_build`` data, and produce a different one than +the ``package_id``, then the standard behavior will be applied. Consider the following: + +.. code-block:: python + + settings = "os", "compiler", "arch", "build_type" + + def build_id(self): + if self.settings.os == "Windows": + self.info_build.settings.build_type = "Any" + +This will only produce a ``build_id`` different if the package is for Windows, running ``build()`` just +once for all ``build_type`` values. The behavior +in any other OS will be the standard one, as if the ``build_id()`` method was not defined, running +one different ``build()`` for each ``build_type``. + + +.. note:: + + **Best practices** + + Conan strong recommendation is to use one package binary with its own ``package_id`` for each different configuration. The ``build_id()`` goal is to deal with legacy build scripts that cannot easily be changed to do the build of one configuration each time. diff --git a/reference/conanfile/methods/build_requirements.rst b/reference/conanfile/methods/build_requirements.rst new file mode 100644 index 000000000000..f39354b7695f --- /dev/null +++ b/reference/conanfile/methods/build_requirements.rst @@ -0,0 +1,52 @@ +.. _reference_conanfile_methods_build_requirements: + +build_requirements() +==================== + +The ``build_requirements()`` method is functionally equivalent to the ``requirements()`` one, it is executed just after it. It is not strictly necessary, in theory everything that is inside this method, could be done in the end of the ``requirements()`` one. Still, the ``build_requirements()`` is good for having a dedicated place to define ``tool_requires`` and ``test_requires``: + +.. code-block:: python + + def build_requirements(self): + self.tool_requires("cmake/3.23.5") + self.test_requires("gtest/1.13.0") + + +For simple cases the attribute syntax can be enough, like ``tool_requires = "cmake/3.23.5"`` and ``test_requires = "gtest/1.13.0"``. The method form can be necessary for conditional or parameterized requirements. + +The ``tool_requires`` and ``test_requires`` are just a specialized instance of ``requires`` with some predefined trait values. See the :ref:`requires() reference` for more information. + +tool_requires +------------- + +The ``tool_requires`` is equivalent to ``requires()`` with the following traits: + +- ``build=True``. This dependency is in the "build" context, being necessary at build time, but not at application runtime, and will receive the "build" profile and configuration. +- ``visible=False``. The dependency to a tool requirement is not propagated downstream. For example, one package can ``tool_requires("cmake/3.23.5")``, but that doesn't mean that consumer packages also use ``cmake``, they could even use a different build system, or a different version, without causing conflicts. +- ``run=True``. This dependency has some executables or runtime that needs to be ran at build time. +- ``headers=False`` A tool requirement does not have headers. +- ``libs=False``: A tool requirement does not have libraries to be linked by the consumer (if it had libraries they would be in the "build" context and could be incompatible with the "host" context of the consumer package). + +test_requires +------------- + +The ``test_requires`` is equivalent to ``requires()`` with the following traits: + +- ``test=True``. This dependency is a "test" dependency, existing in the "host" context, but not aiming to be part of the final product. +- ``visible=False``. The dependency to a test requirement is not propagated downstream. For example, one package can ``self.test_requires("gtest/1.13.0")``, but that doesn't mean that consumer packages also use ``gtest``, they could even use a different test framework, or the same ``gtest`` with a different version, without causing conflicts. + + +It is possible to further modify individual traits of ``tool_requires()`` and ``test_requires()`` if necessary, for example: + +.. code-block:: python + + def build_requirements(self): + self.tool_requires("cmake/3.23.5", options={"shared": False}) + + +.. note:: + + **Best practices** + + - ``tool_requires`` are exclusively for build time **tools**, not for libraries that would be included and linked into the consumer package. For libraries with some special characteristics, using a ``requires()`` with custom trait values. + - The ``self.test_requires()`` and ``self.tool_requires`` should exclusively be used in this ``build_requirements()`` method, with the only possible exception of the ``requirements()`` method. Using them in any other method is forbidden. To access dependencies information when necessary in some methods, the ``self.dependencies`` should be used. diff --git a/reference/conanfile/methods/compatibility.rst b/reference/conanfile/methods/compatibility.rst new file mode 100644 index 000000000000..c04804c16969 --- /dev/null +++ b/reference/conanfile/methods/compatibility.rst @@ -0,0 +1,46 @@ +.. _reference_conanfile_methods_compatibility: + +compatibility() +=============== + +.. warning:: + + This is a **preview** feature + + +The ``compatibility()`` method implements the same binary compatibility mechanism than the +:ref:`compatibility plugin`, but at the recipe +level. In general, the global compatibility plugin should be good for most cases, and only +require the recipe method for exceptional cases. + +This method can be used in a *conanfile.py* to define packages that are compatible between +each other. If there are not binaries available for the requested settings and options +this mechanism will retrieve the compatible packages' binaries if they exist. The method +should return a list of compatible configurations. + +For example, if we want that binaries +built with gcc versions 4.8, 4.7 and 4.6 are considered compatible with the ones compiled +with 4.9 we could declare the ``compatibility()`` like this: + +.. code-block:: python + + def compatibility(self): + if self.settings.compiler == "gcc" and self.settings.compiler.version == "4.9": + return [{"settings": [("compiler.version", v)]} + for v in ("4.8", "4.7", "4.6")] + +The format of the list returned is as shown below: + +.. code-block:: python + + [ + { + "settings": [(, ), (, ), ...], + "options": [(