C++ Dependency Management with Conan and vcpkg

Why C++ never got a canonical package manager, and how Conan 2 and vcpkg manifest mode close the gap — package IDs, triplets, baselines, lockfiles, and binary caching at scale.

Overview

Why C++ never settled packaging

Every other mainstream language settled its packaging question long ago. C++ did not, because of the ABI: a Python wheel works on any CPython of the right minor version, but a C++ static library works only with a compatible compiler, standard library, language standard, exception model and set of ABI-affecting flags.

> [!IMPORTANT] No single binary works everywhere, so a C++ package manager must treat build configuration as part of the package identity. Understanding that sentence is the difference between using these tools and fighting them.

What teams did before

  • Vendored source in third_party/ — Always builds and always drifts; two copies in one link give ODR violations surfacing as memory corruption
  • Git submodules — Pin honestly by SHA, but are not a build system; the typical submodule is two years stale
  • System packages — Fast until you need a version the distro lacks, two versions at once, or a reproducible build eighteen months later
  • In-house prebuilt archives on a fileshare — The ancestor of binary caching; fails like modern caches fail when nobody records which compiler built the artifact

Conan 2: explicit

  • Dependencies — conanfile.txt or conanfile.py
  • Configuration — Profiles
  • Binary identity — Package ID, hashed from the resolved combination
  • Build-system bridge — Generators: CMakeDeps, CMakeToolchain, and equivalents for MSBuild, Meson, Autotools

Recipes are Python, so awkward upstreams (custom build steps, patches, non-CMake projects) work without forking.

vcpkg: opinionated

Configuration is a triplet; versioning is a registry baseline commit plus optional constraints and overrides. The Microsoft/vcpkg registry is a curated monorepo of ports, not an index of independently published recipes. Shorter workflow, narrower escape hatches.

The third option: FetchContent

  • Small, CMake-native, header-heavy dependency sets — You have a build-cost problem: no binary cache, no ABI model, no lockfile, so every clean build recompiles everything

What the interviewer is really probing

In C++, dependency management and build caching are the same problem. The version resolver is table stakes; the cache key is what matters at scale.

> [!TIP] Explain what goes into the key, what silently destabilizes it, and how you would detect a hit-rate collapse, and you have answered the question. Reciting conan install versus vcpkg install has not.

Key concepts

Package ID (Conan)
The SHA1 of conaninfo.txt, which records the settings, options, and requires that affect the binary. It names the binary slot in a remote. Different build_type, compiler.version, or dependency version yields a different package ID and therefore a different binary. conan cache path shows the conaninfo.txt behind any package ID.
ABI hash (vcpkg)
The vcpkg equivalent cache key. It hashes every file in the port directory, the triplet name and file contents, the C and C++ compiler executables, the selected features, each dependency ABI hash, the CMake version, and any variables named in VCPKG_ENV_PASSTHROUGH. Stored per package at share//vcpkg_abi_info.txt for inspection.
Profile (Conan)
A file holding settings, options, conf, and tool_requires. conan profile detect --force writes a default. Separate build and host profiles drive cross-compilation. Profiles are the reason the same conanfile produces a Debug MSVC binary and a Release GCC binary without editing the recipe.
Triplet (vcpkg)
A named configuration such as x64-windows, x64-windows-static, x64-linux, arm64-osx. Sets target architecture, CRT linkage, and library linkage. Custom triplets are ordinary CMake files; anything you add to one becomes part of the ABI hash, which is the supported way to make an environment detail cache-relevant.
builtin-baseline
A vcpkg registry commit SHA in vcpkg.json that sets the version floor for every port in the graph. Without it, and without any configured registry, installs fall back to classic-mode behaviour and ignore versioning entirely. Update it with vcpkg x-update-baseline, deliberately.
conan.lock
A JSON snapshot of the resolved graph including recipe revisions and timestamps, produced by conan lock create. Consumed implicitly when present, or explicitly with --lockfile. --lockfile-partial permits unlocked additions; --lockfile-clean prunes unused entries; conan lock merge combines per-configuration lockfiles.
Package ID mode
How much of a dependency contributes to the consumer package ID. Embedded edges (static or header-only into your binary) default to full_mode; shared-to-shared edges default to minor_mode; tool_requires contribute nothing by default; unknown package types use semver_mode. Tunable via core.package_id:default_embed_mode and siblings in global.conf.
Generator versus toolchain file
Conan splits the two: CMakeDeps writes the find_package config files, CMakeToolchain writes conan_toolchain.cmake carrying compiler, standard, and build type. vcpkg fuses them into one toolchain file that also triggers the install. Knowing which file is responsible for a missing find_package is most of Conan debugging.

When to use it

  • A dependency closure large enough that clean builds are a measurable CI cost — Boost, Qt, Protobuf, gRPC, OpenSSL in one graph
  • Multiple target configurations from one source tree: Debug and Release, static and shared CRT, x64 and arm64, host and cross-compiled
  • You need reproducible builds — the ability to rebuild a release from eighteen months ago with the exact same dependency binaries
  • You distribute a C++ library or SDK and consumers need it in configurations you do not control
  • You are replacing vendored source or stale git submodules and need an upgrade path that does not fork upstream

Interview questions

  • Explain the Conan package ID. What goes into it, and what happens when a dependency version changes?
  • Compare Conan 2 and vcpkg manifest mode. When would you pick each, and how do you pin versions in both?
  • Your CI binary cache hit rate dropped from 95 percent to near zero overnight and nobody changed a dependency. How do you diagnose it?
  • When is CMake FetchContent the right answer, and what does it cost you at scale?
  • A prebuilt dependency from your artifact store causes crashes on one platform but not others. Walk through the diagnosis.

Sign up free to read the full topic

More DevOps topics

Start free on Cariara · Coding problems · System design studio