How settings and options of a recipe influence its package ID¶
In Conan, a package ID is a unique identifier for a package binary that takes into account all the factors that affect its binary compatibility. These factors include recipe options and settings as well as requirements or tool requirements.
Let’s see how settings and options affect the package ID and some examples where they should not.
How settings influence the package ID¶
Settings are development project-wide variables, like the compiler, its version, or the OS itself. These variable values have to be defined, they should match the values of our development environment, and they cannot have a default value like options do.
For example, let’s define a recipe that generates packages that are only OS dependent:
from conan import ConanFile
class Pkg(ConanFile):
name = "pkg"
version = "1.0.0"
settings = "os" # Only OS setting affects the package ID
If we generate a package from this recipe for Linux we will get the following package ID:
$ conan create . --settings os=Linux
...
pkg/1.0.0: Package '9a4eb3c8701508aa9458b1a73d0633783ecc2270' created
$ conan list pkg/1.0.0:*
Local Cache
pkg
pkg/1.0.0
revisions
476929a74c859bb5f646363a4900f7cf (2024-03-07 09:13:43 UTC)
packages
9a4eb3c8701508aa9458b1a73d0633783ecc2270
info
settings
os: Linux
If we do the same thing with Windows, now the package ID will be diffent:
$ conan create . --settings os=Windows
...
pkg/1.0.0: Package 'ebec3dc6d7f6b907b3ada0c3d3cdc83613a2b715' created
$ conan list pkg/1.0.0:*
Local Cache
pkg
pkg/1.0.0
revisions
476929a74c859bb5f646363a4900f7cf (2024-03-07 09:13:43 UTC)
packages
9a4eb3c8701508aa9458b1a73d0633783ecc2270
info
settings
os: Linux
ebec3dc6d7f6b907b3ada0c3d3cdc83613a2b715
info
settings
os: Windows
Whenever a value of the settings or subsettings changes, the package ID will be different to reflect that.
The most common usage for settings is to model the different project-wide aspects that might influence the package ID. A recipe that does that will be:
from conan import ConanFile
class Pkg(ConanFile):
name = "pkg"
version = "1.0.0"
settings = "os", "arch", "compiler", "build_type"
Now, compiling a package with different compiler versions will result into different package IDs:
$ conan create . --settings compiler.version=192
...
pkg/1.0.0: Package '4f267380690f99b3ef385199826c268f63147457' created
$ conan create . --settings compiler.version=193
...
pkg/1.0.0: Package 'c13a22a41ecd72caf9e556f68b406569547e0861' created
$ conan list pkg/1.0.0:*
Local Cache
pkg
pkg/1.0.0
revisions
f1f48830ecb04f3b328429b390fc5de8 (2024-03-07 09:21:07 UTC)
packages
4f267380690f99b3ef385199826c268f63147457
info
settings
arch: x86_64
build_type: Release
compiler: msvc
compiler.cppstd: 14
compiler.runtime: dynamic
compiler.runtime_type: Release
compiler.version: 192
os: Windows
c13a22a41ecd72caf9e556f68b406569547e0861
info
settings
arch: x86_64
build_type: Release
compiler: msvc
compiler.cppstd: 14
compiler.runtime: dynamic
compiler.runtime_type: Release
compiler.version: 193
os: Windows
Removing settings for a package used as a tool_require¶
There could be cases when a setting should not influence the resulting package ID.
An example of this could be when a recipe packages a tool that would be used to build other packages via tool_requires
In that case, the value of the compiler used is needed for the compilation of the tool but not that relevant for consumers, as we only want to execute the tool to build other projects. So we could eventually remove the influence of the compiler from the pacakge ID:
from conan import ConanFile
class CMake(ConanFile):
name = "cmake"
version = "1.0.0"
settings = "os", "arch", "compiler", "build_type" # Only OS and architecture influence the resulting package
def build(self):
# self.settings.compiler value will be used here to compile cmake
def package_id(self):
# Remove compiler setting from package ID
del self.info.settings.compiler
Why not removing the setting from the settings attribute? Because the compiler value is still needed in the build() method to perform the compilation of the executable.
Note
In the case we are generating our own executables (our own apps, not a tool_require
), removing the compiler setting from package ID is not recommended, as we would always want to know
that the package was generated with a specific compiler.
However, in case we are packaging a tool that does not even require a compiler input for building (a python script for example), we could also directly remove the settings attribute:
from conan import ConanFile
class MyPythonScripts(ConanFile):
name = "my-python-scripts"
version = "1.0.0"
# No settings this time
Or, if the tool is platform specific we can just keep the OS and architecture information:
from conan import ConanFile
class MyScripts(ConanFile):
name = "my-scripts"
version = "1.0.0"
settings = "os", "arch"
How options influence the package ID¶
Options are used to specify characteristics that are particular to a single recipe, contrasting with settings that generally remain consistent across recipes within a project. They are usually a set of particular characteristics of a library executable or conan package may have.
For example, a shared option is a very common option used in recipes that can produce shared libraries. However, it could not be a setting as not all recipes produce shared libraries.
from conan import ConanFile
class Pkg(ConanFile):
name = "pkg"
version = "1.0.0"
options = {"shared": [True, False]}
default_options = {"shared": True}
As in the previous case with settings, the different values of an option will influence the package ID and therefore, generate different packages depending on it.
$ conan create . --options shared=True
...
pkg/1.0.0: Package '1744785cb24e3bdca70e27041dc5abd20476f947' created
$ conan create . --options shared=False
...
pkg/1.0.0: Package '55c609fe8808aa5308134cb5989d23d3caffccf2' created
In the same way, there might be “options” that are needed as input in a recipe to generate a package which shouldn’t be taken into account in the package ID. An example of this could be an option to control something that during the build phase but that does not influence the package result, like the verbosity of a compilation. In that case, the recipe should remove the option in the package_id() method:
However, the general advice is that options should always affect the package ID, and in case we would like to have an input to the recipe that should not affect it, it should be done via the conf section of your profile. Then in the recipe we should just add:
from conan import ConanFile
class MyPkg(ConanFile):
name = "my-pkg"
version = "1.0.0"
def build(self):
verbosity = self.conf.get("user.my-pkg:verbosity")
self.output.info(f"Using verbosity level: {verbosity})
...
[conf]
user.my-pkg:verbosity=silent
That way the package ID will be not affected, the recipe will be cleaner (without irrelevant options for package ID) and the input is easily managed via the profile’s conf section.