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.
> 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 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.
> 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.
> 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.
> 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.
> 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).
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:
- 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