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

Reply via email to