Generation of Make Dependencies for C++ Modules

joergboe joergboe@snafu.de
Thu Dec 25 18:28:43 GMT 2025


Am 23.12.25 um 5:23 PM schrieb Ben Boeckel via Gcc:
> On Mon, Dec 22, 2025 at 19:11:13 +0100, joergboe via Gcc wrote:
>> Background
> Hi,
>
> Full disclosure: I authored P1689 (the JSON format), its GCC support,
> and C++ modules support in CMake. I've also worked closely with Clang
> and MSVC on their support of P1689 and keep tabs on build system
> progress for modules ecosystem-wide.

Hi,

thanks for the quick response.

>> For the translation of programs with C++ modules, the use of special
>> build systems is necessary.
> Yes, I agree. I should clarify that my terminology is:
>
> - build tool: a build graph executor (e.g., make, ninja)
> - build system: a set of concepts around compilation artifacts (objects,
>    libraries, binaries) (e.g., cmake, gn, automake)
>
> Some tools are both (e.g., bazel, tup). Either way, I do not believe
> that build tools can build modules (sensibly; they can, of course, do
> the commands) because there's a layer of understanding missing from them
> (as they exist today). I do not believe the compiler possesses the
> required information either. I do believe that there is space for a
> "gcc+gmake modules compilations" solution, but I do not believe it is
> suitable for "real projects" meant to be compiled by more than a handful
> of people (see below).
>
> The fundamental issue is to detect and error when something like this
> happens:
>
>      liba: a.cpp         # provides module `a`
>      libb: b.cpp liba.a  # provides module `b` and links to `liba`
>
> when `a.cpp` tries to `import b`. The compilations *can* be ordered to
> make this work (absent other ordering constraints), but I see it as a
> layering violation. You need to have some build *system* layer that
> understands "libb depends on liba" and therefore "liba's sources may not
> import libb's provided modules". The compiler definitely does not have
> this information (today).

The dependency tree is refreshed in every build run. The a dependency files

are targets in Make rules, thus they will be re-created when outdated.

>> The dependency information for modules that gcc currently generates in
>> the make format
>> (options -M -MD..) have led to some open error messages (109718, 105467,
>> 120103)
>> and do not seem to be a satisfactory solution.
> I agree with this.
My goal ist to make this approach working for simple projects.
>
>> For build systems, module dependencies in JSON format have been introduced.
>> The following proposal describes the generation of module dependencies
>> in make format.
>> This makes it possible to translate C++ projects with modules using GNU
>> Make scripts alone,
> If your goal is to make it easy for CS1 and CS2 classes to compile
> homework (and other similar things like Godbolt or small demonstration
> snippets), sure. For actual deployment ("real projects"), I would
> *highly* suggest considering using an actual build system (cmake, meson,
> etc.). Note that modules support does vary between them, but *any*
> suitable system would be recommended in my book.
>
The goal is to make it easy for simple C++ projects with modules to build a

  single executable or library with gcc and make only without the need of

dealing with JSON  encoded files. I am aware that for complex build systems

the approach using JSON files is appropriate.

>> similar to classic dependency analysis with make and gcc option -M etc
>>
>> Proposal
>>
>> 1. (gcc) The current available header dependency information are used as is.
>> 2. (gcc) Add the dependencies on imported modules in form of a variable.
>> (CXX_MOD_<module name>_CMI)
>> 3. (gcc) Add information about which source file exports which module in
>> form of a list. (CXX_SRC_MOD_IF_LIST)
>> 4. (gcc) A new format in option -fdeps-format activates the module
>> dependency information.
>> With this information provided from gcc the make scrip is able to obtain
>> all necessary dependency information.
> *Dependency* information yes, but it lacks *permission* information.
> Just because a module *exists* does not mean it is *allowed* to be
> imported by any given rule.
>
> You may also have multiple rules generate the same module name (e.g.,
> `module testing;` each in its own testing executable). This case is
> highly unlikely to be solvable without some understanding of "these
> sources belong to artifact A and there is a separate artifact dependency
> graph" somewhere to understand that there is, in fact, no collision.

One build script is limited to build a single binary. This proposal is 
not intended to

replace a 'build system'.

>> 5. (make script) Add rules for the generation of the dependency files.
>> 6. (make script) Import the generation dependency files.
>> 7. (make script) Walk through the source module list and emit variables
>> with the module to CMI file link.
>> 8. (make script) Walk through the source module list and generate the
>> rules for the translation of the units with modules
>> as grouped target rules with the object file and the CMI file as target.
>> 9. (make script) Generate the rules for the remaining non-module sources
>> as usual.
> What is the plan (if any) for rules to build tools that use modules
> themselves as well as in code they generate? This looks like a "we do
> one pass for module dependencies and then do everything after that"
> which doesn't consider one-shot builds which generate sources that
> use/generate modules during the build and do not exist during this one
> pass.
In such a case, the tools that Make offers can be used; write a rule 
with the source file as the target.
>> 10. (make script) Enable secondary expansion for the prerequisites of
>> the dependency rules.
>>
>> You can find a longer description here:
>> https://github.com/joergboe/MakeItSimple/discussions/8 (Chapter: The
>> Build Process with C++ Modules)
> Are there plans for supporting modules coming from external libraries
> (e.g., `import boost;` or even `import std;` for that matter)? All
> you're going to get are a list of module sources provided by the
> library (CPS can provide more, but those, mostly, just turn into flags
> rather than rules); CMI files are not going to be shipped (and even if
> so, their window of reusability is so narrow as to be "useless" in
> practice right now).

Header units must be translates into CMI files beforehand with the same 
compiler

version and settings.

> I see that at this link that header unit support is "CMI files must
> be available before the dependency file can be generated", but this is:

This statement reflects the current state how the dependency scanning with

gcc (-M) currently works.

> - wasteful if headers are not imported;
> - does not describe who/what will generate said CMI files;
> - even if that happens, states nothing of how to make compatible CMI
>    files.
> I'd encourage you to read this document:
>
>      https://gitlab.kitware.com/ben.boeckel/cmake/-/blob/cxxmodules-docs/Help/manual/cmake-cxxmodules.7.rst
>
>      (under review for integration at
>      https://gitlab.kitware.com/cmake/cmake/-/merge_requests/11507)
>
> describing CMake's support to get some more background on the problem
> space. It goes over CMake's support and rationale. You may certainly
> decide to carve out a different space, but I would highly encourage
> consideration of the use cases not supported under different support
> spaces.
>
> Thanks,
>
> --Ben


More information about the Gcc mailing list