[RFC WIP] C++ Header Unit Scanning, Resolution, and Reporting

9 views
Skip to first unread message

vspefs

unread,
Jul 24, 2026, 4:10:47 PMJul 24
to cxx-ecosyst...@googlegroups.com
Hello everyone,

I am currently putting together an initial draft for an RFC regarding the standardization of C++ Header Unit scanning, resolution, and reporting across our ecosystem.

Before I formalize this into a PR, I wanted to share the WIP draft with this group to get some early feedback, particularly from compiler engineers and build system maintainers.

== The Problem

While we have made great strides with module dependency scanning (e.g., P1689), header units currently lack the detailed semantic tooling requirements needed to build a universal build and distribution logic. Different problems severely limit the correctness, usability, and practicability of header units.

Without consensus on these problems, build system maintainers and compiler developers are left at an impasse.

== The Draft RFC

This RFC does not propose any changes to C++ language semantics. Instead, it attempts to characterize the problem space and illustrate the constraints any tooling solution must satisfy. It focuses on three core areas:

The Scanning Strategy Problem:: Addressing the necessity of transitive scanning to properly evaluate mutated preprocessor state (macros) across header unit imports.

The Resolution Directive Problem:: Acknowledging the dichotomy of header units being used as "fancy includes" (inheriting context/flags) versus "opaque modules" (pre-compiled, context-independent CMIs), and how tools must handle both.

The Reporting Format Problem:: How we report these dependencies (non-transitive vs. non-flattening transitive) to allow build systems to construct a valid CMI build plan, and some practical soft requirements like a unified Core Options model to handle problems like multiple CMI instances.

== Read the WIP Draft

You can read the current AsciiDoc draft on my GitHub fork here: https://github.com/vspefs/rfcs/blob/header-units/src/00/00-cxx-header-units/proposal.adoc

== Questions for the Group

I would love to get the community's thoughts on the following:

For Build System & Library Distribution System Maintainers: How do you currently prefer to handle the "fancy include" vs. "module-like" resolution dichotomy in your systems? Do you think it's necessary that we have both?

For P1689 Contributors: What are your initial thoughts on extending or adapting the format to support non-flattened/nested header unit dependency reporting?

I believe these two problems are central to further development of this RFC and header unit solutions. Also, I welcome any other critiques, corrections on my prior art/current status section, or general feedback.

Thank you for your time.

Vito Gamberini

unread,
Jul 24, 2026, 4:38:27 PMJul 24
to vspefs, cxx-ecosyst...@googlegroups.com
Hey vs,

As you outline, because header units leak macros into their consuming context, they're effectively undecidable.

Your A/B/C demonstrates the loop. We can't scan accurately scan C without knowing A, but we don't know that A is required without scanning C. The only way to resolve this is something like the module mapper protocol, build-system-in-the-loop with the compiler. However, that risks deadlocks.

Outside a change to the standard, nothing will meaningfully move here. Trying to standardize tooling without the compilers agreeing on a model is a fool's errand. The compilers won't standardize a model without coherence from the standard.

All this to say: this needs to go back to SG15 and WG21 to fix this bug in header units prior to trying to do anything downstream. If all the compilers had agreed on a single coherent model I might think differently, but again you illustrate that they have not.

---

Aside from all that, the only thing we want from header units is to treat them like interface units. Scan once, get the direct imports, done. No need to chase imports, so no question about whether the report is transitive or non-transitive. That model has proven remarkably durable. The scanner format described by P1689 anticipated this to be the mechanism header units used.

I would much rather see header units come to P1689 than mutate that trivial format to meet the broken mechanism of header units.

- Vio

vspefs

unread,
Jul 24, 2026, 7:21:00 PMJul 24
to Vito Gamberini, cxx-ecosyst...@googlegroups.com
> As you outline, because header units leak macros into their consuming context, they're effectively undecidable.

Decidability does not matter. Practicality like cyclic dependency detection matters, and practicality here is at least as achievable as traditional header files, which is very much indeed achievable.

I am not sure what you mean here by "undecidable". Computability-theoretically speaking, CPP is indeed undecidable. Although I don't know if header units are undecidable. But all math aside, like elaborated above, decidability does not matter.

If you mean "not lexically locally immediately computed", then yes.

> Your A/B/C demonstrates the loop. We can't scan accurately scan C without knowing A, but we don't know that A is required without scanning C. The only way to resolve this is something like the module mapper protocol, build-system-in-the-loop with the compiler. However, that risks deadlocks.

I do not understand how any of the examples demonstrate that situation which I also don't understand at all and how a GCC module mapper is critical in that. Can you demonstrate?

Far as I see, the preprocessor state does cause problems, but none of them can't be solved with a reasonable amount of effort and minimal external impact. This whole RFC points out potential and existing solutions and how we can better utilize them.

> Outside a change to the standard, nothing will meaningfully move here. Trying to standardize tooling without the compilers agreeing on a model is a fool's errand. The compilers won't standardize a model without coherence from the standard.
>
> All this to say: this needs to go back to SG15 and WG21 to fix this bug in header units prior to trying to do anything downstream. If all the compilers had agreed on a single coherent model I might think differently, but again you illustrate that they have not.

Compilers fully agree on everything, which has and causes no issue at all. Scanners' behaviors and the backing philosophies differ, which is out of the scope of the C++ language IS and thus not requiring any modification to it.

> Aside from all that, the only thing we want from header units is to treat them like interface units. Scan once, get the direct imports, done. No need to chase imports, so no question about whether the report is transitive or non-transitive. That model has proven remarkably durable. The scanner format described by P1689 anticipated this to be the mechanism header units used.

The whole point of header units is the partial preprocessor awareness, which mandates transitive scanning and `import` chasing. However, scanning and reporting are very much orthogonal in this specific problem. You can scan transitively and report non-transitively. The only requirement is that in the final summary, the `import` layer information is reserved.

Layered reporting is mandated due to the build requirement of CMIs, which is universal between named modules and header units. Such layering can be achieved by non-transitive reporting (like named modules already do) or non-trivial transitive reporting, regardless of whether you're dealing with named modules or header units. Everything applies to both, so I don't understand how "treat them like interface units" clarifies or avoids any problem.

> I would much rather see header units come to P1689 than mutate that trivial format to meet the broken mechanism of header units.

Header units don't need to "come to P1689". They already are there. They lack certain additional components and that's all.

Vito Gamberini

unread,
Jul 24, 2026, 7:36:38 PMJul 24
to vspefs, cxx-ecosyst...@googlegroups.com
> If you mean "not lexically locally immediately computed", then yes.

That's what I mean, yes. Their dependency list cannot be decided based on the information available at scan time.


> Scanners' behaviors and the backing philosophies differ

The compilers are the scanners. s/compilers/scanners/g if you like.

> Can you demonstrate?

It's self-evident. I cannot correctly report the dependencies of C without being able to chase A. I don't know I need to chase A prior to scanning C. So I need to scan up to the point of discovery of A, pause scanning, go find and manifest A, then continue scanning C.

Gabriel Dos Reis

unread,
Jul 24, 2026, 7:42:22 PMJul 24
to Vito Gamberini, vspefs, cxx-ecosyst...@googlegroups.com
Is the goal to turn every imaginable header file that can be written into a header unit?

-- Gaby




From: 'Vito Gamberini' via C++ Ecosystem Evolution <cxx-ecosyst...@googlegroups.com>
Sent: Friday, 24 July 2026 16:36:31
To: vspefs <vsp...@protonmail.com>
Cc: cxx-ecosyst...@googlegroups.com <cxx-ecosyst...@googlegroups.com>
Subject: [cxx-eco-ev] Re: [RFC WIP] C++ Header Unit Scanning, Resolution, and Reporting
 
--
You received this message because you are subscribed to the Google Groups "C++ Ecosystem Evolution" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cxx-ecosystem-evo...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/cxx-ecosystem-evolution/CANRryCUs-_F11NO_9xO1dyiAP3bkirSDi83saBo2DW-VJMhHMw%40mail.gmail.com.

vspefs

unread,
Jul 24, 2026, 10:20:59 PMJul 24
to Vito Gamberini, cxx-ecosyst...@googlegroups.com
> The compilers are the scanners. s/compilers/scanners/g if you like.

Then it’s out of the scope of the language IS. Technically it should be a SG15 TR or another ISO standard, but the administrative and law reasons why we can’t really have them is exactly why EcoStd exists.

Besides the Modules TR is not withdrawn but I don’t see any current progress being made.

> It's self-evident. I cannot correctly report the dependencies of C without being able to chase A. I don't know I need to chase A prior to scanning C. So I need to scan up to the point of discovery of A, pause scanning, go find and manifest A, then continue scanning C.

How we can do it and the different strategies is the main content of the whole Resolution Directive Problem section. How we already do it is in the Scanner Behaviors section.

vspefs

unread,
Jul 25, 2026, 10:34:00 AMJul 25
to Gabriel Dos Reis, Vito Gamberini, cxx-ecosyst...@googlegroups.com
> Is the goal to turn every imaginable header file that can be written into a header unit?
>
> -- Gaby

I think "project-internal, more flexible PCH" and "immutable external library interface" are two reasonable and practical demands.

Vito Gamberini

unread,
Jul 25, 2026, 1:30:48 PMJul 25
to vspefs, cxx-ecosyst...@googlegroups.com
> the different strategies is the main content of the whole Resolution Directive Problem

And highlights the exact problem

Our options are:

* "Treat them like headers": assume the initial preprocessor state matches the initial preprocessor state of the consumer. This is wrong and non-conforming. Header units are translation units. They have their own initial preprocessor state, independent of their consumers. These states need not match.

* "Treat them like modules": Impossible to reason about. Requires pausing to construct BMIs as we encounter imports.

"Treat them like headers" is the only reasonable approach, but requires a change to the standard to specify their initial preprocessor state matches that of the consumer.

Everything else becomes trivial after that.
Reply all
Reply to author
Forward
0 new messages