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

[conf] Tools configurations improvements #2427

Merged
merged 22 commits into from
Mar 7, 2022
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
77 changes: 35 additions & 42 deletions reference/conanfile/tools/cmake/cmaketoolchain.rst
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,15 @@ CMake legacy generators (like ``cmake``, or ``cmake_paths``) with it.
Using a custom toolchain file
+++++++++++++++++++++++++++++

There are two ways of providing a custom CMake toolchain file:
There are two ways of providing custom CMake toolchain files:

- The ``conan_toolchain.cmake`` file can be completely skipped and replaced by a user one, defining the
``tools.cmake.cmaketoolchain:toolchain_file=<filepath>`` configuration value
``tools.cmake.cmaketoolchain:toolchain_file=<filepath>`` configuration value.
- A custom user toolchain file can be added (included from) to the ``conan_toolchain.cmake`` one, by using the
``user_toolchain`` block described below, and defining the ``tools.cmake.cmaketoolchain:user_toolchain=<filepath>``
``user_toolchain`` block described below, and defining the ``tools.cmake.cmaketoolchain:user_toolchain=["<filepath>"]``
configuration value.

The configuration ``tools.cmake.cmaketoolchain:user_toolchain=<filepath>`` can be defined in the :ref:`global.conf<global_conf>`
The configuration ``tools.cmake.cmaketoolchain:user_toolchain=["<filepath>"]`` can be defined in the :ref:`global.conf<global_conf>`
but also creating a Conan package for your toolchain and using ``self.conf_info`` to declare the toolchain file:

.. code:: python
Expand All @@ -178,39 +178,40 @@ There are two ways of providing a custom CMake toolchain file:
...
def package_info(self):
f = os.path.join(self.package_folder, "mytoolchain.cmake")
self.conf_info["tools.cmake.cmaketoolchain:user_toolchain"] = f

self.conf_info.define("tools.cmake.cmaketoolchain:user_toolchain", [f])


If you declare the previous package as a ``tool_require``, the toolchain will be automatically applied.
- If you have more than one ``tool_requires`` defined, you can easily append all the user toolchain values
together using the ``append`` method in each of them, for instance:

- You can also apply several user toolchains. If you have more than one ``tool_requires``, you can gather the values
from all the dependency configs and adjust the ``user_toolchain`` block to apply all the toolchains:
.. code:: python

.. code:: python
import os
from conans import ConanFile
class MyToolRequire(ConanFile):
...
def package_info(self):
f = os.path.join(self.package_folder, "mytoolchain.cmake")
# Appending the value to any existing one
self.conf_info.append("tools.cmake.cmaketoolchain:user_toolchain", f)

from conans import ConanFile
from conan.tools.cmake import CMake, CMakeToolchain
class Pkg(ConanFile):
settings = "os", "compiler", "arch", "build_type"
exports_sources = "CMakeLists.txt"
tool_requires = "toolchain1/0.1", "toolchain2/0.1"
def generate(self):
# Get the toolchains from "tools.cmake.cmaketoolchain:user_toolchain" conf at the
# tool_requires
user_toolchains = []
for dep in self.dependencies.direct_build.values():
ut = dep.conf_info["tools.cmake.cmaketoolchain:user_toolchain"]
if ut:
user_toolchains.append(ut.replace('\\\\', '/'))
# Modify the context of the user_toolchain block
t = CMakeToolchain(self)
t.blocks["user_toolchain"].values["paths"] = user_toolchains
t.generate()

def build(self):
cmake = CMake(self)
cmake.configure()

So, they'll be automatically applied by your ``CMakeToolchain`` generator without writing any extra code:

.. code:: python

from conans import ConanFile
from conan.tools.cmake import CMake
class Pkg(ConanFile):
settings = "os", "compiler", "arch", "build_type"
exports_sources = "CMakeLists.txt"
tool_requires = "toolchain1/0.1", "toolchain2/0.1"
generators = "CMakeToolchain"

def build(self):
cmake = CMake(self)
cmake.configure()


Using the toolchain in developer flow
Expand Down Expand Up @@ -271,16 +272,8 @@ Since Conan 1.36, ``CMakeToolchain`` implements a powerful capability for extend
The following predefined blocks are available, and added in this order:

- ``user_toolchain``: Allows to include user toolchains from the ``conan_toolchain.cmake`` file.
If the configuration ``tools.cmake.cmaketoolchain:user_toolchain=xxxx`` is defined, its value will be ``include(xxx)`` as the
first line in ``conan_toolchain.cmake``. If you want to apply several toolchains you can use the context variable ``paths``:

.. code:: python

t = CMakeToolchain(self)
t.blocks["user_toolchain"].values["paths"] = ["path/to/user_toolchain1.cmake",
"path/to/user_toolchain2.cmake"]
t.generate()

If the configuration ``tools.cmake.cmaketoolchain:user_toolchain=["xxxx", "yyyy"]`` is defined, its values will be ``include(xxx)\ninclude(yyyy)`` as the
first lines in ``conan_toolchain.cmake``.
- ``generic_system``: Defines ``CMAKE_GENERATOR_PLATFORM``, ``CMAKE_GENERATOR_TOOLSET``, ``CMAKE_C_COMPILER``, ``CMAKE_CXX_COMPILER`` and ``CMAKE_BUILD_TYPE``
- ``android_system``: Defines ``ANDROID_PLATFORM``, ``ANDROID_STL``, ``ANDROID_ABI`` and includes ``CMAKE_ANDROID_NDK/build/cmake/android.toolchain.cmake``
where ``CMAKE_ANDROID_NDK`` comes defined in ``tools.android:ndk_path`` configuration value.
Expand Down Expand Up @@ -410,7 +403,7 @@ Cross building
The ``generic_system`` block contains some basic cross-building capabilities. In the general
case, the user would want to provide their own user toolchain defining all the specifics,
which can be done with the configuration ``tools.cmake.cmaketoolchain:user_toolchain``. If
this conf value is defined, the ``generic_system`` block will include the provided file, but
this conf value is defined, the ``generic_system`` block will include the provided file or files, but
no further define any CMake variable for cross-building.

If ``user_toolchain`` is not defined and Conan detects it is cross-building, because the build
Expand Down
168 changes: 165 additions & 3 deletions reference/config_files/global_conf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ Global configuration
- ``core.package_id:msvc_visual_incompatible`` allows opting-out the fallback from the new ``msvc`` compiler to the ``Visual Studio`` compiler existing binaries



Tools configurations
--------------------

Expand Down Expand Up @@ -66,7 +65,7 @@ To list all possible configurations available, run :command:`conan config list`.
tools.cmake.cmaketoolchain:generator: User defined CMake generator to use instead of default
tools.cmake.cmaketoolchain:find_package_prefer_config: Argument for the CMAKE_FIND_PACKAGE_PREFER_CONFIG
tools.cmake.cmaketoolchain:toolchain_file: Use other existing file rather than conan_toolchain.cmake one
tools.cmake.cmaketoolchain:user_toolchain: Inject existing user toolchain at the beginning of conan_toolchain.cmake
tools.cmake.cmaketoolchain:user_toolchain: Inject existing user toolchains at the beginning of conan_toolchain.cmake
tools.cmake.cmaketoolchain:system_name: Define CMAKE_SYSTEM_NAME in CMakeToolchain
tools.cmake.cmaketoolchain:system_version: Define CMAKE_SYSTEM_VERSION in CMakeToolchain
tools.cmake.cmaketoolchain:system_processor: Define CMAKE_SYSTEM_PROCESSOR in CMakeToolchain
Expand All @@ -89,6 +88,169 @@ To list all possible configurations available, run :command:`conan config list`.
tools.system.package_manager:sudo_askpass: Use the '-A' argument if using sudo in Linux to invoke the system package manager (False by default)


Configuration file template
---------------------------

Available since: `1.46.0 <https://github.com/conan-io/conan/releases>`_

It is possible to use **jinja2** template engine for *global.conf*. When Conan loads this file, immediately parses
and renders the template, which must result in a standard tools-configuration text.

.. code:: jinja

# Using all the cores automatically
tools.build:jobs={{os.cpu_count()}}
# Using the current OS
user.myconf.system:name = {{platform.system()}}


.. note::

The Python packages passed to render the template are only ``os`` and ``platform``.


Configuration data types
------------------------

Available since: `1.46.0 <https://github.com/conan-io/conan/releases>`_

All the values will be interpreted by Conan as the result of the python built-in `eval()` function:

.. code-block:: text

# String
tools.microsoft.msbuild:verbosity=Diagnostic
# Boolean
tools.system.package_manager:sudo=True
# Integer
tools.microsoft.msbuild:max_cpu_count=2
# List of values
user.myconf.build:ldflags=["--flag1", "--flag2"]
# Dictionary
tools.microsoft.msbuildtoolchain:compile_options={"ExceptionHandling": "Async"}


Configuration data operators
----------------------------

Available since: `1.46.0 <https://github.com/conan-io/conan/releases>`_

It's also possible to use some extra operators when you're composing tool configurations in your *global.conf* or
any of your profiles:

* ``+=`` == ``append``: appends values at the end of the existing value (only for lists).
* ``=+`` == ``prepend``: puts values at the beginning of the existing value (only for lists).
* ``=!`` == ``unset``: gets rid of any configuration value.

.. code-block:: text
:caption: *myprofile*

[settings]
...

[conf]
# Define the value => ["-f1"]
user.myconf.build:flags=["-f1"]

# Append the value ["-f2"] => ["-f1", "-f2"]
user.myconf.build:flags+=["-f2"]

# Prepend the value ["-f0"] => ["-f0", "-f1", "-f2"]
user.myconf.build:flags=+["-f0"]

# Unset the value
user.myconf.build:flags=!


Configuration in your profiles
--------------------------------

Let's see a little bit more complex example trying different configurations coming from the *global.conf* and a simple profile:

.. code-block:: text
:caption: *global.conf*

# Defining several lists
user.myconf.build:ldflags=["--flag1 value1"]
user.myconf.build:cflags=["--flag1 value1"]


.. code-block:: text
:caption: *myprofile*

[settings]
...

[conf]
# Appending values into the existing list
user.myconf.build:ldflags+=["--flag2 value2"]

# Unsetting the existing value (it'd be like we define it as an empty value)
user.myconf.build:cflags=!

# Prepending values into the existing list
user.myconf.build:ldflags=+["--prefix prefix-value"]


Running, for instance, :command:`conan install . -pr myprofile`, the configuration output will be something like:

.. code-block:: bash

...
Configuration:
[settings]
[options]
[build_requires]
[env]
[conf]
user.myconf.build:cflags=!
user.myconf.build:ldflags=['--prefix prefix-value', '--flag1 value1', '--flag2 value2']
...


franramirez688 marked this conversation as resolved.
Show resolved Hide resolved
Configuration in your recipes
-------------------------------

From Conan 1.46, the user interface to manage the configurations in your recipes has been improved. For instance:

.. code-block:: python

import os
from conans import ConanFile

class Pkg(ConanFile):
name = "pkg"

def package_info(self):
franramirez688 marked this conversation as resolved.
Show resolved Hide resolved
# Setting values
self.conf_info.define("tools.microsoft.msbuild:verbosity", "Diagnostic")
self.conf_info.define("tools.system.package_manager:sudo", True)
self.conf_info.define("tools.microsoft.msbuild:max_cpu_count", 2)
self.conf_info.define("user.myconf.build:ldflags", ["--flag1", "--flag2"])
self.conf_info.define("tools.microsoft.msbuildtoolchain:compile_options", {"ExceptionHandling": "Async"})
# Getting values
self.conf_info.get("tools.microsoft.msbuild:verbosity") # == "Diagnostic"
# Getting default values from configurations that don't exist yet
self.conf_info.get("user.myotherconf.build:cxxflags", default=["--flag3"]) # == ["--flag3"]
# Getting values and ensuring the gotten type is the passed one otherwise an exception will be raised
self.conf_info.get("tools.system.package_manager:sudo", check_type=bool) # == True
self.conf_info.get("tools.system.package_manager:sudo", check_type=int) # ERROR! It raises a ConanException
# Modifying configuration list-like values
self.conf_info.append("user.myconf.build:ldflags", ["--flag3"])
self.conf_info.prepend("user.myconf.build:ldflags", ["--flag0"])
# Modifying configuration dict-like values
self.conf_info.update("tools.microsoft.msbuildtoolchain:compile_options", {"ExpandAttributedSource": "false"})
# Unset any value
self.conf_info.unset("tools.microsoft.msbuildtoolchain:compile_options")


.. important::

Legacy configuration methods to set/get values like ``self.conf_info["xxxxx"] = "yyyyy"`` and ``v = self.conf_info["xxxxx"]`` are
deprecated since Conan 1.46 version. Use ``self.conf_info.define("xxxxx", "yyyyy")`` and ``v = self.conf_info.get("xxxxx")`` instead
like the example above.


Configuration from tool_requires
--------------------------------

Expand All @@ -106,7 +268,7 @@ configuration as:
name = "android_ndk"

def package_info(self):
self.conf_info["tools.android:ndk_path"] = os.path.join(self.package_folder, "ndk")
self.conf_info.define("tools.android:ndk_path", os.path.join(self.package_folder, "ndk"))


Note that this only propagates from the immediate, direct ``tool_requires`` of a recipe.