Why C++ Needs a Modern Package Manager

The most widely-used systems language in the world has the worst dependency story. Here's why, and what we're doing about it.

A Brief History of C++ Dependency Management

In 1998, when the first C++ standard was published, the concept of a "package manager" barely existed. You downloaded tarballs, ran ./configure && make && make install, and hoped your system's include paths were set up correctly.

Nearly three decades later, the core workflow hasn't fundamentally changed.

The Three Fundamental Problems

1. Headers Are the Root of All Build Evil

The #include preprocessor directive is textual substitution. When you write #include <vector>, the compiler literally pastes the contents of that file into your translation unit. Every. Single. Time.

  • Redundant work. The same header gets parsed thousands of times across a project.
  • Macro pollution. A macro defined in one header can silently change the meaning of code in another.
  • Fragile ordering. Include order matters, and getting it wrong produces cryptic errors.
  • No isolation. There's no module boundary — everything leaks.

C++20 modules fix all of this. A module is compiled once into a Binary Module Interface (BMI), and consumers import the interface — not the source text. It's faster, safer, and deterministic.

2. There's No Universal Identity for C++ Libraries

In Rust, a crate is identified by its name on crates.io. In Go, a module is identified by its Git URL. In C++, a library is identified by... whatever the person who packaged it decided to call it.

Is it fmt or fmtlib or libfmt? This ambiguity creates real problems: version conflicts, namespace collisions, and an ecosystem where the same library exists under different names in different package managers.

3. Reproducibility Is an Afterthought

Without mandatory lockfiles, pinned compiler versions, and deterministic dependency resolution, C++ builds are inherently non-reproducible. The same CMakeLists.txt can produce different binaries on different machines.

How cmod Addresses Each Problem

Modules as the Unit of Composition

cmod doesn't treat modules as an optional feature bolted onto a header-based system. Modules are the foundation. The full build graph is known before any compilation begins, enabling parallel compilation, correct ordering, and cached BMIs that skip redundant work.

Git URLs as Universal Identity

[dependencies]
"github.com/fmtlib/fmt" = ">=10.0"
"github.com/nlohmann/json" = "^3.11"

There's no ambiguity. No registry to search. No name squatting. Private dependencies work the same way. No vendor lock-in. Forking is trivial.

Lockfiles Are Mandatory

Every cmod project has a cmod.lock file that records the exact Git commit hash for every dependency. When you build with --locked, cmod will refuse to proceed if the lockfile doesn't match. No surprises.

The Developer Experience Gap

With CMake + Conan: at least 6 steps, two configuration files, and two different tools to learn.

With cmod:

cmod init my_project
cmod add github.com/fmtlib/fmt@10.0
cmod build

Three commands. One configuration file. One tool.

Who Is cmod For?

  • Systems programmers who want fast, deterministic builds without fighting their build system.
  • Game engine teams managing complex dependency graphs with monorepo support.
  • Open-source maintainers who want to publish C++ libraries without registry accounts.
  • Infrastructure teams who need reproducible CI/CD pipelines.

The Road Ahead

cmod is feature-complete across all planned phases: 30+ CLI commands, Git-based resolution, mandatory lockfiles, LLVM/Clang build backend, workspace support, local and remote artifact caching, cryptographic signing, LSP server, and plugin sandboxing — all backed by 780+ tests.

Recent additions:

  • IDE extensions — VS Code extension and CLion/IntelliJ plugin with LSP integration, module graph visualization, and build status
  • Remote caching — HTTP-based cache protocol for sharing build artifacts across your team
  • Distributed builds — Work-stealing distributed build workers
  • 12+ examples — From minimal binaries to shared libraries, workspaces, and multi-binary projects

cmod is open source under Apache-2.0. Star the repo, file issues, and help us build the package manager C++ deserves.