Whether you know about Conan or not, this post might help advance your perspective a bit. Conan is typically described as a “package manager for C and C++”. Indeed that’s its primary function and probably the best short description we have, but it fails to capture several of Conan’s most powerful aspects. Thus, this article aims to shed light on Conan’s lesser-known capabilities and potential roles and enable potential users to better decide whether or not it might be of value to them.
A Dependency Manager
Conan enables users to encapsulate C/C++ project dependencies, distribute them, and consume them in other projects. This involves the complex challenges of transitive dependencies, versioning, licensing, and so forth. Hopefully this high-level functionality is familiar and obvious to everyone based on experience with other ecosystems, because the features will likely become decreasingly familiar as we get into more detail.
A “Source” Package Manager
With the operative word of “Source” meaning “Source Code”, Conan shares this functionality with a number of other “package managers for native languages.” Package recipes contain the sources (or mechanism to obtain the sources) for a project and the ability to invoke the build system on the local machine. Furthermore, this includes the ability to recursively perform this process for the complete chain of transitive dependencies. This robust management and building of sources for projects and their dependencies is a central function to Conan, and the “Binary Package Management” feature which we will discuss next is built on top of it. However, its important to point out that many developers do not use the “Binary” features for a variety of reasons, and instead build all project and dependencies from sources locally. There are a variety of valid reasons and use cases for doing this which we won’t go into, but the key point here is that it’s a well supported workflow with Conan.
Of note, one reason that a number of other package managers have been springing up around C and C++ with this functionality, is that because it’s the first and easiest thing to implement in the problem domain of package management. Package managers for the languages of Rust and Go operate exclusively in this mode and have little-to-no support for binary packages. Since many of the new C and C++ package managers borrow numerous features from these ecosystems, it’s easy to understand why they stop with source package management as well.
A “Binary” Package Manager
Managing binaries for libraries is a related-but-separate feature set from managing sources. Conan is unique among “package managers for native languages” in providing this functionality as a first-class part of the platform. There are binary package managers for operating systems such as Yum, Apt, Homebrew, and Chocolatey, but those are a different category altogether. Since it’s a fairly unique feature of the platform, it’s worth defining what it means in the context of native software development.
Conan captures compiled binaries into it’s packages so that multiple developers don’t have to redundantly compile the same binaries on each of their machines. A common case with Conan is to have a CI server like Jenkins re-compile libraries after each GIT commits and push the compiled binaries to a shared Conan repository. Then, the Conan clients on all the developer machines can download updated binaries whenever they invoke Conan on a project that references those libraries. In many cases, this is much more efficient than the alternative. “Binaries” typically includes
.exe files, but Conan can technically capture any type of file in these packages. Native software binaries are unlike binaries from other languages (like Java’s
.jar files for example). Native binaries are not universal, and two binaries must be “ABI Compatible” to be used together. Thus, in order to capture, share, and consume binaries effectively, Conan must record a complete picture of “how the binaries were built” in the form of “ABI Metadata” each time it captures files. This includes OS, architecture, compiler settings, debug or release, and so forth. This also means it has to keep track of many binaries for a single package, and provide the mechanisms for searching, matching, downloading, and uploading in a way that accomodates “single-binary operation” and “multiple-binary operations”. Conan typically captures these binaries immediately after running a build like in the CI example mentioned earlier, but it can also capture binaries that were built outside Conan, such as binaries of an SDK provided by a vendor.
A Universal Build System Variable Writer
In the world of software development, package managers feed build systems. They obtain dependencies, and make them available for build systems which is done by passing variables such as file paths, compiler definitions, and other variables. Unlike other language ecosystems, C/C++ features a vast array of build systems, and even “meta-build systems”, each with their own proprietary formats. Conan intends to be a build-system agnostic package manager, and therefor needs to be able to pass these common variables to whichever build system is used by a given project. To address this daunting challenge, Conan features an extensible “Generator” model, and there are over a dozen public generators available for all the most common build systems. When a developer runs a build through Conan, it calls the appropriate generator, which converts generic variable information to the proprietary variables compatible with the specified build system(s). It then writes these variables to files, which the build system then reads.
This generator system is one of the key features of Conan that gives it the flexibility to deal with the challenging diversity of the real world. This includes the known diversity of open-source build tools, along with incomprehensible diversity of private build tools. The generators make it truly trivial for organizations to write and maintain whatever custom generators they need to integrate with their existing build systems.
A Bunch of Open-Source, Cross-Platform Scripts
People use scripts around C and C++ all the time, including shell scripts, python, groovy, etc. There are countless tedious steps to perform when working with C and C++ projects, and in any professional setting or codebase with more than a few projects, scripting is practically a necessity. Many organizations maintain their own scripts in-house, per-organization, or per-project. While there’s a great deal of specifics in these scripts which cannot be generalized, there’s a vast amount of redundancy among these scripts which can. Conan represents one generalized open-source, cross-platform collection of such scripts which is consistent, feature rich, extensively field tested, and even unit tested (how many organization unit test their in-house build scripts?). It provides this scripting framework because it has to in the service of being a package manager, and so it’s very well organized and intuitive to use.
An Environment Variable Manager
Environment variables are one of the few “common coins” we have in the diverse world of C and C++. The vast majority of build systems and related tools enable settings and options to be controlled with environment variables. If you’re doing any sort of professional development, it’s likely that you set environment variables for this purpose, either manually via your operating system, shell scripts, or via a CI platform like Jenkins. Likewise, you probably also work with a team of developers, and there’s a need for everyone on the team who works with these tools to understand and use these variables consistently to achieve consistent builds across the codebase.
Both Conan recipes and Conan profiles provide mechanisms for managing environment variables while Conan performs it’s various operations. When working with enterprise environments and teams, profiles are a cornerstone of the Conan platform and workflows. Part of the power is in Conan’s ability to compose and distribute these profiles, which includes composing and distributing of environment variables to both teams and CI servers. Much like many of the other value propositions of Conan, one of the critical characteristics which comes from managing these variables with it, is that it represents a separate abstraction layer, thus making it is agnostic of the operating system, build system, meta-build system, etc.
An Build Tool Installation Manager
There are a great many tools that surround the C and C++ development ecosystem. Developers install them using various mechanisms, including manual installation, and their operating systems package managers. There are also enterprise management tools which enable tools to be deployed to all users in an organization. With Conan’s
build_requires feature, build tools can be packaged, distributed, and “installed” just like any other Conan package, and thus represents a new option. There are over a dozen such packages featuring extremely popular build tools already on Conan Center, or the Bincrafters repository. Also, many organizations which use Conan internally package the unique build tools they use and distribute them to their developers and build servers this way.
You may wonder why we need yet another option for installing these tools, and why this method is so popular with Conan users. There are several reasons. For starters, there is often a direct relationship between a C/C++ project and the tool (or a collection of tools) required to build it. Conan provides a unique ability to describe these relationships (library to build-tool) with a very natural and robust experience which includes all the same functionality that normal “library” dependencies do. Crucially, builds that use tools from Conan packages are inherently much more deterministic thanks to some of the details about how Conan packages them. Additionally, sometimes developers have to work on libraries which require different versions of the same tools, so they often need multiple versions of tools to easily co-exist on the same machine. Conan encpasulates the tools, by version, in a way that guarantee’s safe co-existence. With the
build_requires feature being definable on a per-recipe or per-profile basis, it makes it extremely intuitive for developers to put some default tools and versions in their tools in their default profile, with the flexibility override them as needed for certain builds.
A Toolchain File Manager
A toolchain is a vague but commonly used term, and here it is used to describe all the “inputs” to a builds. Effectively, this is like a superset of the two items described above: the tools used to build something, and the settings fed into that build (by environment variables, settings files, command-line inputs, etc.). So, given that we’ve already described how Conan manages both environment variables and build tool installations, here we are pointing out that Conan can manage the various configuration files used as inputs to the build tools. These files can be packaged, versioned, and distributed just like the build tools and environment variables.
A Build System Wrapper
As mentioned before, people already wrap their build systems with their own scripts to provide a layer between the developer and the build tools, and Conan simply provides a more mature and robust layer than most other scripted solutions. While scripts for build operations are vast and diverse, probably the most common things which people script is the calling of the build system. So, here are just a few of the novel “build system wrapper features” which people often script themselves and which Conan provides (although there are several more):
- Run a build in a temporary build directory with one command
- Create and use unique build directories for each unique build (arch, compiler, etc)
- Clean and re-use build directories for re-runs (idempotently)
I focused on this small and simple workflow, because in the world of C and C++ development, one of our most famous and ancient incantations repeated thousands of times each day around the world is
mkdir build && cd build && some_build_command ... If questioned about why they use this specific workflow, I imagine many people would probably something like “it’s simple and it works”, which I would not deny. However, the reality is that the workflow doesn’t end there, and so these commands brings along baggage in terms of the natural followup steps (cleaning the directory and re-running, creating separate directories for debug/release, etc). These steps are just unsimple enough to get scripted most of the time, so when taken as a whole, it’s nice to have a set of scripts that manages our build directories intelligently and idempotently.
An Enterprise-Ready Platform for Native Software Tooling Interoperability
So now that we’ve outlined a variety of lesser-known features, maybe the above description is a more accurate represntation of Conan which includes all the things that Conan can do that are not traditionally considered part of “package management”. Hopefully this gives readers who are new to Conan a bit more context with which they can read through the documentation and get a foothold in how Conan works, why it works the way it does, and whether or not they want to try using it in their codebase.