Do not require module implementation units to import primray module interface implicitly

Document #: P4370R0
Date: 2026-09-10
Project: Programming Language C++
Audience: Core Language Evolution Group
Reply-to: Chuanqi Xu
<>

1 Background & Motivation

Currently, the module implementation units will import the primary module interface implicitly.

[module.unit]p8:

A module-declaration that contains neither an export-keyword nor a module-partition implicitly imports the primary module interface unit of the module as if by a module-import-declaration.

And the primary module interface is required to import all interfaces units in the module.

[module.unit]p3:

All module partitions of a module that are module interface units shall be directly or indirectly exported by the primary module interface unit ([module.import]). No diagnostic is required for a violation of these rules.

So that, now the standard requires the module implementation units depends on all the interface units in the module.

For example,

// m-interfaceA.cppm
export module m:interfaceA;
...
// m-interfaceB.cppm
export module m:interfaceB;
...
export module m;
export import :interfaceA;
export import :interfaceB;
// m1.cpp
module m;
...
// m2.cpp
module m;
...

No matter if m1.cpp or m2.cpp depends on m:interfaceA and m:interfaceB or not, when m-interfaceA.cppm or m-interfaceB.cppm are touched, both m1.cpp and m2.cpp will be recompiled.

THIS IS EXTREMELLY A WASTE OF TIME IN PRACTICE. Especially when the number of module partitions grow up.

2 Proposal

Do not ask the module implementation units to import the primary module interface implicitly.

This is a breaking change. But the current user who don’t want this

If we’re afraid this as a breaking change, we can introduce a new syntax,

explicit module [primary_module_name];

where explicit can only appear in front of a module implementation unit. Then the explicit module implementation unit won’t import the primary module interface unit implicitly.

3 Other Alternatives

3.1 Use module internal partition units as module implementation units

Actually we have a standard conforming workaround for this issue. That is to use the module internal partition units as module implementation units. e.g.,

// m1.cpp
module m:interfaceA.impl;
import :interfaceA;
...
// m2.cpp
module m:interfaceB.impl;
import :interfaceB;
...

then the users can control the dependencies much more precisely.

This works perfectly fine in our downstream projects. But there are two problems which makes me to write the proposal, one practical and one abstract:

  1. Practical one. CMake, the defacto standard build system, will always generate a BMI for the module internal partition units. This is suboptimal as these BMIs are not needed. CMake devs explains to me several times that they have to do it, although I didn’t understand honestly.
  2. Abstract one. Someone told me that the above trick didn’t follow their design intentions. Implementation should be in implementation units.

Except our internal codebase, there aleady open source code base using this pattern now.

infinity is a business project using C++20 modules natively. Now it has 884 internal partition units which follows the pattern as *.impl.

3.2 Use dot to mimic partition units

Another workaround is to not use partitions. But what if we do need the partition semantics?

Users use dot to mimic it. For the above example,

// m-interfaceA.cppm
export module m.interfaceA;
...
// m-interfaceB.cppm
export module m.interfaceB;
...
export module m;
export import m.interfaceA;
export import m.interfaceB;
// m1.cpp
module m.interfaceA;
...
// m2.cpp
module m.interfaceB;
...

So that the false dependency is cut.

There also projects using this tricks.

The cost is that the complete module name became unnecessarily long. For example,

And also this makes the concept of partitions not useful.

4 Summary

The other practices shows that this is a real need to fix real problems.

I don’t think we can say “oh, the users simply don’t understand modules and they didn’t make the hierarchy well.”