Conan 1.32.0 features a new strategy for defining, detecting, and handling invalid configurations. This includes a new method named validate(), and a new package_id mode named BINARY_INVALID. It also includes a big refactor of our future toolchain and generators strategy, some new capabilities of generators in general, and 2 new classes for Meson (a Toolchain and a build helper class). We’ve also added some subcommands for dealing with recipes and packages which have no remote associated, and made it possible to deal with lockfiles which contain the same package multiple times in the graph (possible via private requirements). Finally, we’re excited to show a proven workaround which satisfies a long-standing and high-priority request, which is to optionally include build_requires into the package_id. There are some important side-effects and caveats, to be aware of, so read on to learn about the details.

New Strategy for Invalid Configurations

In recent months, there has been growing discussion in the community about some awkward challenges surrounding the definition, detection, and handling invalid or impossible configurations. Historically, the general recommendation has been to handle these cases by raising ConanInvalidConfiguration errors during the configure() method, but in practice there are some checks which simply cannot be run there because of the state of the dependency graph. Also, with the compatible_packages feature, there are cases when a recipe might not be able to build, but might be configured to provide a compatible package instead.

The existing workarounds for these cases were unfortunate, so we’ve now added some first-class-features around them. The first is to add a new method to Conanfile named validate() method which executes after the graph has been fully evaluated solving the previous problems. The second is to add a new package_id mode named BINARY_INVALID. Moving forward, the configure() method should still be used for actually setting configurations, but the validate() method should take over all responsibility for raising ConanInvalidConfiguration errors. In these cases, the BINARY_INVALID is now reported as the state in the output of conan info command, as opposed the previous behavior which was for this command to fail with return code 6. This is a major improvement as some automation cases (such as ConanCenter) use conan info to make decisions about what to build, and parsing json output is more desirable than interpreting return codes.

Here’s an example of validate() and the output from it

def validate(self):
    if self.settings.os == "Windows":
        raise ConanInvalidConfiguration("Windows not supported")

$ conan create . pkg/0.1@ -s os=Windows
    pkg/0.1:INVALID - Invalid
> ERROR: There are invalid packages (packages that cannot exist for this configuration):
> pkg/0.1: Invalid ID: Windows not supported

Refactoring Toolchains and Generators (and Namespaces)

It’s important to highlight that a lot of experimental classes were moved around into different namespaces in this release. Please refer to the changelog and docs for all the specifics, but here’s a simple summary.

First, we’ve now exposed a new top-level namespace called conan. Experienced users will recall that previously, virtually all Conan classes and functions have been exposed to under the namespace conans. In summary, there’s no longer a reason for the letter s which many people have found annoying. As we prepare for Conan 2.0, we plan to make all existing classes and functions available under conan namespace, and eventually deprecate conans. In this release, we’ve started conservatively by simply exposing a few brand new classes and functions under the tools sub-namespace. If things go well, we’ll add aliases to existing classes and functions over time.

So, under, we’ve created four sub-namespaces:

  • cmake
  • gnu
  • meson
  • microsoft

We’ll be adding to this structure in the future, and the decision was that organizing these tools for integrations by “vendor” was a lot more intuitive than trying to organize them by “purpose” or “functionality”. Such strategies have proven to be awkward in the past because so many tools and utility functions are multi-purpose.

We’ve started using these directories by putting all the respective toolchains classes into in them. We’ve also begun moving forward on a new naming convention for generators, starting with the experimental msbuild generator. It has been renamed to MSBuildDeps, and we’ll talk more about why we did this shortly. We will also be creating in 1.33 a new generator named CMakeDeps in the cmake directory, that will initially be a copy of the existing cmake_find_package_multi generator. We’ve already been promoting that as the top recommendation for most use-cases of CMake generators, and we’ll be promoting that people use it from this new import and new name (CMakeDeps) when it becomes available. Also, we’ve added a new toolchain called MesonToolchain.

How Toolchains Helped Generators Evolve

You may have also noticed that the new generator names listed have capital letters in them. Indeed, this represents the start of a pretty important change of convention. Historically, generators have had capital letters in the class name, and then had a lowercase name field which was an alias used in recipes, profiles, and the CLI. We’re now starting the process of deprecating the use of lower-case generator aliases, and migrating to the use of the literal class name as the identifier in all places where Generators are referenced. Change like this can be difficult to adapt to, and this might appear to be purely cosmetic, so I think this calls for some explanation.

Our work on toolchains has had a major impact on our future plans for generators. We created the abstraction of the “Toolchain” class and the corresponding method in, to distinguish two separate concerns. “Generators” are now intended to focus on information “related to dependencies”, and “Toolchains” are intended to focus on build variables which are related to “everything else” (which means mostly platform, compiler, and linker settings). As we started to work with the Toolchains as simple classes and function calls within a dedicated recipe method, it was an obvious thing to give the constructors and methods of these toolchains parameters. This made the toolchains flexible and configurable, and allowed us to start doing some cool stuff with them. We then realized that if we did the same thing with generators (creating some new ones which took paramters and were configurable), then we could probably solve a bunch of long-standing generator-related feature requests, and with relative ease.

This seemed to be a pretty amazing revelation… almost too good to be true. Rarely do big wins come easy, so we looked back to figure out why this hasn’t occurred to us during the process of trying to resolve some of those feature requests. Also, how is the current Generators implementation unique, and why again is it designed the way it is. We found some reasons which I’ll now summarize, but simply put, it’s not enough to prevent us with moving forward with configurable generators. We’re still working on proving the basics internally, and hope to have something significant to share soon.

The primary “magic” of generators in Conan is the way that they are declared in recipes and implicitly “depended upon”, and invoked at the appropriate time. The benefit really boils down to a super concise declarative syntax. However, this little bit of magic and convenience actually comes at a major cost. There are fundamental internal challenges with it’s implementation which cannot be fixed without breaking changes. In retrospect, the magic probably was not worth the cost. The approach being explored now doesn’t suffer any of those major consequences, has the promise of providing “configurable generators”, and might not even be any more verbose than what we have today.

The main snag with implementing configurable generators right now is that generators can be invoked in two contexts: in-recipe and on-demand (with -g generator or in a profile). Most of the “configurability” people have asked for historically is surrounding the in-recipe use of Generators, and making them normal python classes with methods seems like it will have all the benefits one might expect there. However, its difficult to imagine whether or not the configurable generators will make sense when used on-demand. At this time, we don’t plan to support an extra command-line syntax for passing paramters to the generators in this context (although we have thought about it already). So, we’ll have to see if the majority of generators are useful in the on-demand context only using default values. They probably will, and it shouldn’t be any worse than one of the existing generators which has no configuration at all.

The revelation process described above also allowed us to step back and recognize a simplification that could be made. While Toolchains and Generators are definitely distinct categories of information from the perspective of the build, we’ve decided that they’re not substantially different in terms of their essence in Conan. As such, we’ve decided to refactor the implementations around them to treat them in a similar way. This dramatically reduces internal complexity and increases consistency in a several ways, but simply put, it’s less to learn.

The overall idea here is that the process for both things is still the same:

  • Analyze the configuration and dependency data Conan has gathered
  • Generate files

They’re just two sub categories of the same thing. So, at that point, it seemed fairly obvious to rename the still-experimental def toolchain() method in to def generate(). For the same reasons, we decided that the “primary interface method” to trigger the generation of files on both Toolchains and Generators moving forward should just be generate() as well. So, for toolchains, the old method write_toolchain_files() has been renamed to generate(). It’s simple, consistent, and descriptive. Here’s an example of using the two together:

from conans import ConanFile
from import MSBuildDeps, MSBuildToolchain

class Pkg(ConanFile):
    settings = "os", "compiler", "build_type", "arch"
    requires = "boost/1.72.0", "poco/1.9.4"

    # The generate method creates files that the build can use
    def generate(self):
        # generates conan_boost.props, conan_poco.props for dependencies
        # and conandeps.props that aggregates them
        deps= MSBuildDeps(self)
        # generates conantoolchain.props from current settings
        tc= MSBuildToolchain(self)

Furthermore, going back to the topic of deprecating of the lower-case name field/alias of generators, we realized that we did not implement an equivalent feature in toolchains. This was largely because it really only represented a layer of abstraction and redirection which was more confusing than it was valuable. Looking back at Generators, we felt the same way. Sometimes you want to de-couple class name from “usage name” of something, but this no longer feels like one of those times. But it’s not only cosmetic, it created some awkward design questions when implementing configurable generators which just went away if we chose to use the class name. Simpler was just better in this case on multiple fronts.

Including build_requires in package_id (Experimental)

There has been an outstanding feature request for a long time which has seemed virtually un-solvable in the current version of Conan without major breaking changes. That feature request is to make it possible for build_requires to affect package_id. Users have been wanting this for a very long time, and the existing workarounds are unacceptible in a number of cases. Sadly, a first-class fix is still likely only going to happen in Conan 2.0. However we’ve discovered a new workaround which may achieve the goal for some use-cases, and which has actually existed under the radar for a very long time, and is substantially different from previously known workarounds. Of note, before we create too much excitement for those affected, there are a few caveats and challanges with this workaround which might negate it’s use.

Nonetheless, here’s the strategy. If you have a build_requires declared in a recipe, and you want it to affect the package_id of the package, simply add it as a python_requires as well. That’s it, that’s the strategy. It works because Conan includes python_requires in package_id calculations already, and it doesn’t cause any problems because it just discards and does not use the for the build_requires. Again, it seems good to be true, so lets highlight the biggest problem. If you leverage your build_requires via profiles, this won’t work for you at all. It’s unfortunate, because that describes a lot of use-cases for build_requires, but not all. In any case, we think some users will be able to use this strategy, so we wanted to announce the discover here. We’ve also included an example in the docs.

Besides the items listed above, there was a long list of fairly impactful bug fixes you may wish to read about. If so, please refer to the changelog for the complete list.

We hope you enjoy this release, and look forward to your feedback.