A module mapper can also manage generated headers
P1842R0 extends compiler and build-system communication so dependency discovery can resolve headers before preprocessing them.
A missing generated header is only one dependency problem. An existing but outdated header can be worse because the compiler may read it and fail before the build system replaces it. Boris Kolpackov's P1842R0, dated August 4, proposes extending a module mapper to handle headers as well. The build system gets an opportunity to act before preprocessing consumes the dependency.
The paper draws on implementation work in GCC and use in build2. It generalizes an existing mapper direction instead of proposing that an import statement should somehow locate every build product by itself. That separation is necessary because source-level module names and filesystem artifacts have different responsibilities.
Compile times are one of the costs I associate with C++ abstraction. I find this proposal interesting because it addresses a prerequisite for useful module builds, the communication through which a compiler obtains the right interface artifact at the right time.
Header units complicate discovery
The merged modules design P1103R3 includes header units and a route for translating includes into imports. Header units can make macros available to the importing preprocessing context. Those macros can affect what subsequent source requires.
That means discovering dependencies can depend on having already processed an earlier dependency. A scanner cannot always determine the complete graph from a superficial inspection of import spellings. The compiler's current preprocessing state can be part of the answer.
P1842R0 reports that build2 initially used GCC's mapper for header-unit imports and the -M family for ordinary header dependencies. Include translation created substantial overlap between those routes. Generalizing the mapper could let the same conversation handle both kinds of dependency.
The proposal is therefore about coordinating discovery with compilation. It does not claim that a static list of module names alone describes all the headers the preprocessor will consume. A build integration has to account for how those headers affect later processing.
A dependency file can arrive too late
The paper explains the conventional generated-header approach using -MG. The compiler tolerates a missing header during dependency discovery, and the build system reads the output, generates the file and invokes the compiler again. This handles a useful case, but it requires another pass.
An outdated header creates a different failure. It exists, so missing-file tolerance does not identify the need to regenerate it. The old contents can produce a fatal preprocessing error. Merely learning after the pass that the file was read does not prevent that error.
A missing generated header can also expose the wrong file. The include search may find an unrelated header with the same name in a later search directory. That makes the search path part of the correctness problem. The compiler found a file, but the build graph needed another one.
A dynamic mapper can intervene before the header is consumed. The build system can update the expected artifact or request that the compiler search again. That gives dependency production a place in the protocol at the operation that needs the result.
Requests distinguish inclusion from import
The generalized protocol includes IMPORT and INCLUDE requests. A module-name import requests the corresponding binary module interface. A header request can also contain the resolved path, if the compiler has found one.
For an inclusion request, the response can keep textual inclusion or translate it into an import. A SEARCH response asks the compiler to repeat header lookup and issue another request. This permits the build system to generate a header before the compiler makes its final selection.
Quoting distinguishes the header forms. The paper uses double quotes and angle brackets for the corresponding source styles, while single quotes identify final or immutable requests. That last form does not permit another search or a translation.
These distinctions retain compiler knowledge about the search. Returning an arbitrary replacement path would require reconstructing its relationship to include directories and associated properties. Asking the compiler to search again leaves that work with the component that already implements it.
I prefer that division of responsibility. The build system knows which artifact must be produced. The compiler knows how header lookup determines the file's preprocessing context. A protocol should exchange those facts without making either component reproduce the other's internal rules.
Static and dynamic maps serve different integrations
P1842R0 distinguishes static mappings, normally read from a file, from a dynamic request-response conversation. Static mappings provide module or header paths and their interface artifacts. The dynamic protocol can respond when compilation discovers something requiring action.
The paper describes several communication media, including pipes and spawned programs. It identifies a pipe from a build system that launches the compiler as a natural integration. Other media can help with build systems that are harder to modify.
The documented implementation and build2 usage make this a tooling proposal with concrete experience. Its main benefit is the point at which it can resolve a dependency. For generated headers, obtaining a correct file before preprocessing is materially different from discovering the dependency after reading an outdated or unintended file.