Multiple configurations

Warning

This is an experimental feature subject to breaking changes in future releases.

In the previous section we managed just 1 configuration, for the default profile. In many applications, packages need to be built with several different configurations, typically managed by different profile files.

Note

This section continues with the previous example with the Introduction. The code used in this section, including a build.py script to reproduce it, is in the examples repository: https://github.com/conan-io/examples. You can go step by step reproducing this example while reading the below documentation.

$ git clone https://github.com/conan-io/examples.git
$ cd features/lockfiles/intro
# $ python build.py only to run the full example, but better go step by step

Lets start in the features/lockfiles/intro of the examples repository, remove the previous packages, and create both release and debug pkga packages:

$ conan remove "pkg*" -f
$ conan create pkga pkga/0.1@user/testing
$ conan create pkga pkga/0.1@user/testing -s build_type=Debug

Now, we could (don’t do it) create 2 different lockfiles, one for each configuration:

# DO NOT type these commands, we'll do it better below
$ cd pkgb
$ conan lock create conanfile.py --user=user --channel=testing --lockfile-out=locks/pkgb_release.lock
$ conan lock create conanfile.py --user=user --channel=testing --lockfile-out=locks/pkgb_debug.lock -s build_type=Debug

Important

The dependency graph is different for each different configuration/profile. Not only the package-ids, but also because of conditional requirements, the dependencies can be different. Then, it is necessary to create a lockfile for every different configuration/profile.

But, what if a new pkga/0.2@user/testing version was created in the time between both commands? Although this is unlikely to happen in this example, because everything is local. However, it could happen that pkga was in a server and the CI uploads a new pkga/0.2@user/testing version while we are running the above commands.

Base lockfiles

Conan proposes a “base” lockfile, with the --base argument, that will capture only the versions and topology of the graph, but not the package-ids:

$ cd pkgb
$ conan lock create conanfile.py --user=user --channel=testing --lockfile-out=locks/pkgb_base.lock --base

Let’s inspect the locks/pkgb_base.lock lockfile:

{
    "graph_lock": {
        "nodes": {
            "0": {
                "ref": "pkgb/0.1@user/testing",
                "requires": ["1"],
                "path": "..\\conanfile.py",
                "context": "host"
            },
            "1": {
                "ref": "pkga/0.1@user/testing",
                "context": "host"
            }
        },
        "revisions_enabled": false
    },
    "version": "0.4"
}

This lockfile is different to the ones in the previous section. It does not store the profile, and it does not capture the package-ids or the options of the nodes. It captures the topology of the graph, and the package references and versions.

At this point, the new pkga/0.2@user/testing version packages could be created:

$ cd ..
# The recipe generates different package code depending on the version, automatically
$ conan create pkga pkga/0.2@user/testing
$ conan create pkga pkga/0.2@user/testing -s build_type=Debug

Using the “base” locks/pkgb_base.lock lockfile, now we can obtain a new lockfile for both debug and release configurations, and it is guaranteed that both will use the pkga/0.1@user/testing dependency, and not the new one:

$ cd pkgb
$ conan lock create conanfile.py --user=user --channel=testing --lockfile=locks/pkgb_base.lock --lockfile-out=locks/pkgb_deps_debug.lock -s build_type=Debug
$ conan lock create conanfile.py --user=user --channel=testing --lockfile=locks/pkgb_base.lock --lockfile-out=locks/pkgb_deps_release.lock

Now, we will have 2 lockfiles, locks/pkgb_deps_debug.lock and locks/pkgb_deps_release.lock. Each one will lock different profiles and different package-id of pkga/0.1@user/testing.

Note

In Conan 1.X, if you are generating lockfiles with separate build and host profiles, your base lockfiles must also use separate build and host profiles. For example, here we are generating a base lockfile that will be used to generate lockfiles for a Linux and Windows build:

# The build and host profiles you choose for the base lockfile should
# include all dependencies needed by all lockfiles you will generate
# from the base lockfile.
$ conan lock create conanfile.py -pr:b release -pr:h debug --lockfile-out=base.lock --base

# Use the base lockfile to generate lockfiles for a Linux and Windows
# build.
$ conan lock create conanfile.py -pr:b linux-rel -pr:h linux-dbg --lockfile=base.lock --lockfile-out=linux.lock
$ conan lock create conanfile.py -pr:b windows-rel -pr:h windows-dbg --lockfile=base.lock --lockfile-out=windows.lock

For more information, please see GitHub issue #9446.

Locked configuration

The lockfiles store the effective configuration, settings, options, resulting from the used profiles and command line arguments. That configuration arguments can be passed to the conan lock create command, but not when using lockfiles. For example:

$ mkdir build && cd build
$ conan install .. --lockfile=../locks/pkgb_deps_debug.lock -s build_type=Debug
ERROR: Cannot use profile, settings, options or env 'host' when using lockfile

results in an error, because the locks/pkgb_deps_debug.lock already stores the settings.build_type and passing it in the command line could only result in inconsistencies and errors.

Important

Lockfiles store the full effective profile configuration. It is not possible to pass configuration, settings, options or profile arguments when using lockfiles (only when creating the lockfiles)

With the two captured lockfiles, now we can locally build and run our pkgb application for both configurations, guaranteeing the dependency to pkga/0.1@user/testing:

$ conan install .. --lockfile=../locks/pkgb_deps_release.lock
$ cmake ../src -G "Visual Studio 15 Win64"
$ cmake --build . --config Release
$ ./bin/greet
HelloA 0.1 Release
HelloB Release!
Greetings Release!
$ conan install .. --lockfile=../locks/pkgb_deps_debug.lock
$ cmake --build . --config Debug
$ ./bin/greet
HelloA 0.1 Debug
HelloB Debug!
Greetings Debug!

We can create pkgb package again for both configurations:

$ cd ..
$ conan create . user/testing --lockfile=locks/pkgb_deps_release.lock --lockfile-out=locks/pkgb_release.lock
$ conan create . user/testing --lockfile=locks/pkgb_deps_debug.lock --lockfile-out=locks/pkgb_debug.lock

And we could still use the lockfiles later in time to install the pkgb package with the same dependencies and configuration that were used to create that package:

$ cd ..
$ mkdir consume
$ cd consume
$ conan install pkgb/0.1@user/testing --lockfile=../pkgb/locks/pkgb_release.lock
$ ./bin/greet
HelloA 0.1 Release
HelloB Release!
Greetings Release!
$ conan install pkgb/0.1@user/testing --lockfile=../pkgb/locks/pkgb_debug.lock
$ ./bin/greet
HelloA 0.1 Debug
HelloB Debug!
Greetings Debug!

As you can see, the immutability principle remains. If we try to use pkgb_release.lock to create the pkgb package again instead of the pkgb_deps_release.lock lockfile, it will error, as pkgb would be already fully locked in the former.