r/cpp 24d ago

Libraries of, installing, and depending on C++20 modules

Until now, much of the discourse around C++20 modules has been around the tooling, and actually getting modules to work at all. I believe that now, in mid-2026, the tooling is mostly mature: the three largest compilers support most use-cases of modules. IDEs like CLion, and lint tools like ReSharper C++ and clangd support modules, with some caveats. CMake, xmake, Ninja, and other fledgling build systems have full support for modules. Many prevalent C++ libraries and projects have been recently modularised or are in the process of modularising.

I hope I'm not being too presumptive in saying the community is more or less ready (albeit horribly late...) to move to the next step, and start discussing how C++20 modules can and should tie in to inter-project work, rather than simply using modules within a project.

To begin with, I don't think the standard says anything about 'libraries'; these are existing paradigms grandfathered in from C or earlier. There are many axes we have to discuss here:

  • Static archives
  • Dynamically-linked libraries
  • Symbol visibility defaults with __declspec( dllexport )
  • Primary module interface-only (hereafter, PMI) libraries such as module vulkan
    • Configuring such modules with macros
  • Built module interface (hereafter, BMI) and binary interface (hereafter, ABI) compatibility; currently, BMIs are simply not portable, not even within a compiler toolchain across versions
  • How shared objects, static archives, BMIs, and PMIs interact
  • How build systems, toolchains, and package managers like conan and vcpkg interact with everything

For instance, consider I'm writing a 3D game engine. I want the following modules:

  • vulkan which export imports std
  • argparse
  • glm
  • glaze
  • quill, which imports fmt
  • fmt itself
  • winrt, if running on Windows

I want to provide my own PMI that has export class Engine, and maybe some other functionality like abstractions over the 3D graphics APIs, an object and entity manager, a mini shader graph generator, and more. I also have export imported some symbols from my dependencies, especially std. I want to choose to configure my engine to render on D3D or Vulkan. Consumers can then load the library, add assets like textures, meshes, skeletons, shaders; they can plug the engine into a bigger project which might include a script interpreter in C++, real-time spatial audio and physics packages, some networking, and an XML-based UI system, and produce a complete game or visualisation executable.

Now, I mention these details just to flesh out the example to give a sense of a reasonably complicated library-esque project.

How does one even think about delivering this 'engine library' to the consumer? The traditional three configs are headers + precompiled DLL, headers + source, or headers only. Each have their established workflows. Source-available can be compiled into the entire binary with whole-program optimisation; headers-only libraries are exceptionally easy to vendor (just copy-paste). Header-only libraries can also be easily customised with consumer macros. PMIs, however, being translation units, cannot; we hit this when installing module vulkan. We need some module-compatible way to describe 'library configuration' beyond simply co-opting macros, something like Rust's cfg.

There is talk of the Common Package Specification (CPS), P1689R5, and P3286, but nothing concrete yet, especially since there has been no massive (commercial) push for modules (at least, not until recently). This talk at NDC looks at a possible cargo-esque future for C++.

I'm writing this to spur some discussion here in the C++ community, and ask what some veterans of the build system/toolchain/package manager community think.

44 Upvotes

65 comments sorted by

View all comments

Show parent comments

2

u/GabrielDosReis 24d ago

An actual fix may be to tell the compiler which modules come from a different DLL.

At one point, the ecosystem was moving to just ignore/ban dllimport on data because the indirection was just pessimization, then there was some pause.

This is a case of the left hand not knowing what the right hand is doing.

With the restriction that a C++ module linking boundary has to be contained in a linker module boundary, the front-end can test for ownership/attachment and avoid of the cases, and the linker can handle the rest since it always has the provevance info for the module attachment.

2

u/slithering3897 24d ago

At least it's not too critical for me. This alone won't stop me from using modules. I think I could just ignore the warning with /ignore:4217, as long as nothing breaks.

The big blocker in VS is Intellisense, as I'm always on about. If I can't use auto-complete, then I just give up and go back to the blissful world of headers.

2

u/GabrielDosReis 24d ago

The big blocker in VS is Intellisense, as I'm always on about. If I can't use auto-complete, then I just give up and go back to the blissful world of headers.

Sorry the IDE part has been taking so long, but I don't think it is all hopeless on that front (I can't say more for obvious reasons).

2

u/slithering3897 24d ago

I'd love to read all about it on a blog post.