Conan migration guide to 2.0

Conan team is working hard on the next major release. We’ve been gathering feedback from the community about our features and we think it’s time to break some default behaviors, clean the codebase and add space for new developments. Development is ongoing and the Conan 2.0 Tribe is having discussions about it.

Conan 2.0-alpha is already released. You can install the latest Conan Alpha version from PyPI doing:

$ pip install conan --pre

The documentation for 2.0 is still far from being complete, but we are working on it and you can access it with the right version label.

This section summarizes some of the necessary changes during Conan 1.X to be ready to upgrade to Conan 2.0:

Update the syntax of your Conanfile

  • Use the from conan import ConanFile import instead of the legacy from conans ... (note the plural)

  • Do not use dictionary expressions in your recipe settings definition (like settings = {"os": ["Windows", "Linux"]}. This way of limiting supported configurations by one recipe will be removed. Use the validate() method instead to raise ConanInvalidConfiguration if strictly necessary to fail fast for unsupported configurations.

  • Use self.test_requires() to define test requirements instead of the legacy self.build_requires(..., force_host_context).

  • Use self.tool_requires() to define the legacy build_requires.

  • Move all your packages to lowercase. Uppercase package names (or versions/user/channel) will not be possible in 2.0.

Explicit test package requirement

In Conan 2.0, the test_package/conanfile.py needs to declare the requirement being tested explicitly. To be prepared you have to set the attribute test_type="explicit" (this will be ignored in 2.0) to make Conan activate the explicit mode, then declaring the require using the self.tested_reference_str that contains the reference being tested.

from conan import ConanFile

class MyTestPkg(ConanFile):
    test_type = "explicit"

    def requirements(self):
        # A regular requirement
        self.requires(self.tested_reference_str)

    def build_requirements(self):
        # If we want to test the package as a tool_require (formerly `test_type = "build_requires"`)
        # Keep both "requires()" and "tool_requires()" if you want to test the same package both as a regular
        # require and a tool_require (formerly `test_type = "build_requires", "requires"`)
        self.tool_requires(self.tested_reference_str)

New namespace conan.tools.xxxxx

Use generators and helpers only from conan.tools.xxxx space. All the other ones are going to be removed. Please check the tools section to learn more about the new tools available for Conan 2.0.

Host and build profiles and new cross-building model

Use always build and host profiles.

Conan 1.x uses one profile by default, to start using two profiles, please do the following:

  • Pass -pr:b=default in the command line to most commands.

  • Or set the variable core:default_build_profile=default at the global.conf file to apply it always, automatically.

Do not use os_build, arch_build anywhere in your recipes or code.

Conan uses revisions by default in Conan 2.0

Conan 2.0 uses revisions by default and the local cache 2.0 will store multiple recipe and package revisions for your Conan packages (Conan 1.X supports only one revision). To start working with revisions enabled in Conan 1.X, please enable them in your Conan configuration:

$ conan config set general.revisions_enabled=True

self.copy() disappears from recipes

The self.copy has been replaced by the explicit tool copy.

from conan.tools.files import copy

def package(self):
    ...
    copy(self, "*.lib", self.build_folder, join(self.package_folder, "lib"), keep_path=False)
    copy(self, "*.dll", self.build_folder, join(self.package_folder, "bin"), keep_path=False)

self.dependencies to access information about dependencies

Do not use self.deps_cpp_info, self.deps_env_info or self.deps_user_info. Use the self.dependencies access to get information about dependencies.

Commands that disappear in 2.0: copy

Do not use the conan copy command to change user/channel. Packages will be immutable, and this command will dissapear in 2.0. Package promotions are generally done in the server side, copying packages from one server repository to another repository.

Methods that disappear in 2.0: self.imports

The def imports(self) method from the conanfile has been removed. If you need to import files from your dependencies you can do it in the generate(self) method:

from conan.tools.files import copy

def generate(self):
    for dep in self.dependencies.values():
        copy(self, "*.dylib", dep.cpp_info.libdirs[0], self.build_folder)
        copy(self, "*.dll", dep.cpp_info.libdirs[0], self.build_folder)

Editables don’t use external templates any more. New layout model

If you are using editables, the external template files are going to be removed. Use the layout() method definition instead. Please check the documentation for more information about layouts.

Default cpp_info.builddirs

The default root package folder (self.cpp_info.builddirs = ['']) has been removed. Also assign it will be discouraged because it affects how CMakeToolchain and CMakeDeps locate executables, libraries, headers… from the right context (host vs build).

To be prepared for Conan 2.0:

  • If you have cmake modules or cmake config files at the root of the package, it is strongly recommended to move them to a subfolder cmake and assing it: self.cpp_info.builddirs = ["cmake"]

  • If you are not assigning any self.cpp_info.builddirs assign an empty list: self.cpp_info.builddirs = [].

  • Instead of appending new values to the default list, assign it: self.cpp_info.builddirs = ["cmake"]

Removing missing settings

In Conan 2, removing a setting, for example, del self.settings.compiler.libcxx in the configure() method, will raise an exception if the setting doesn’t exist. It has to be protected with try/except:

def configure(self):
    try:
       # In windows, with msvc, the compiler.libcxx doesn't exist, so it will raise.
       del self.settings.compiler.libcxx
    except Exception:
       pass

New properties model for the cpp_info in Conan 2.0 generators

Using .names, .filenames and .build_modules will not work any more for new generators, like CMakeDeps and PkgConfigDeps. They have a new way of setting this information using set_property and get_property methods of the cpp_info object (available since Conan 1.36).

def set_property(self, property_name, value)
def get_property(self, property_name):

New properties cmake_target_name, cmake_file_name, cmake_module_target_name, cmake_module_file_name, pkg_config_name and cmake_build_modules are defined to allow migrating names, filenames and build_modules properties to this model. In Conan 2.0 this will be the default way of setting these properties for all generators and also passing custom properties to generators.

Important

The 2 mechanisms are completely independent:

  • Old way using .names, .filenames will work exclusively for legacy generators like cmake_find_package

  • New properties, like set_property("cmake_target_name") will work exclusively for new generators like CMakeDeps. They have changed to be absolute, and that would break legacy generators.

  • Recipes that want to provide support for both generators need to provide the 2 definitions in their package_info()

New properties defined for CMake generators family, used by CMakeDeps generator:

  • cmake_file_name property will define in CMakeDeps the name of the generated config file (xxx-config.cmake)

  • cmake_target_name property will define the absolute target name in CMakeDeps

  • cmake_module_file_name property defines the generated filename for modules (Findxxxx.cmake)

  • cmake_module_target_name defines the absolute target name for find modules.

  • cmake_build_modules property replaces the build_modules property.

  • cmake_find_mode will tell CMakeDeps to generate config files, modules files, both or none of them, depending on the value set (config, module, both or none)

Properties related to pkg_config, supported by both legacy pkg_config and new PkgConfigDeps:

  • pkg_config_name property equivalent to the names attribute.

  • pkg_config_custom_content property supported by both generators that will add user defined content to the .pc files created by the generator

  • component_version property supported by both generators that sets a custom version to be used in the Version field belonging to the created *.pc file for that component.

Properties related to pkg_config, only supported by new PkgConfigDeps:

  • pkg_config_aliases property sets some aliases of any package/component name for the PkgConfigDeps generator only, it doesn’t work in pkg_config. This property only accepts list-like Python objects.

All of these properties, but cmake_file_name and cmake_module_file_name can be defined at global cpp_info level or at component level.

The set/get_property model is very useful if you are creating a custom generator. Using set_property() you can pass the parameters of your choice and read them using the get_property() method inside the generator.

def package_info(self):
    ...
    # you have created a custom generator that reads the 'custom_property' property and you set here
    # the value to 'prop_value'
    self.cpp_info.components["mycomponent"].set_property("custom_property", "prop_value")
    ...

Please check a detailed migration guide in the dedicated section.

scm is removed, replaced by export() and source() methods

The scm by attribute feature will be removed. The new approach in Conan 2.0 will be:

  • The export() method is responsible of capturing the “coordinates” of the current URL and commit. The new conan.tools.scm.Git can be used for this (do not use the legacy Git helper but this one)

  • The export() method, after capturing the coordinates, can store them in the conandata.yml using the update_conandata() helper function

  • The source() method can use the information in self.conan_data coming from exported conandata.yml file to do a clone and checkout of the matching code. The new conan.tools.scm.Git can be used for this purpose.

This approach is already available in 1.X,. Check the conan.tools.scm.Git documentation in the reference for examples.

The core logic would be in the export() method:

def export(self):
    git = Git(self, self.recipe_folder)
    scm_url, scm_commit = git.get_url_and_commit()
    # we store the current url and commit in conandata.yml
    update_conandata(self, {"sources": {"commit": scm_commit, "url": scm_url}})

Please check the full example in the conan.tools.scm.Git section.