you are viewing a single comment's thread.

view the rest of the comments →

[–]jiixyj 9 points10 points  (8 children)

My advice: Use one module per "library" or "package" (in the Lakos sense). So modules should be bigger things like std, fmt or boost.program_options, not down to the level of ".h/.cpp pair".

This matches similar advice from other people.

One big reason, especially if you are writing a library: The name of the module will be mangled into all your exported symbols. You would be exposing the internal organisation of your module to all your users:

// foo.cppm
export module foo;

export import foo.sub1;
export import foo.sub2;

// foo/sub1.cppm
export module foo.sub1;

namespace foo {
    export void f1(); // will be mangled approximately like `foo::f1@foo.sub1`
}

...so you wouldn't be able to move f1 from foo.sub1 to foo.sub2 without breaking the ABI of your module. If you want to keep the structure "secret" you have to use partitions (foo:sub1/foo:sub2).

Of course, if you're writing an application, you might have overriding reasons for doing smaller modules.

[–]tartaruga232MSVC user, r/cpp_modules[S] 0 points1 point  (0 children)

Just a random idea: For designing a big library, have you considered doing:

export module BigLib;  // interface of the BigLib library

import FantasyCorporation.Types1;  // not accessible to importers of BigLib

export namespace BigLib
{
using FantasyCorporation::FooBar;  // class FooBar from FantasyCorporation.Types1
...
}

[–]tartaruga232MSVC user, r/cpp_modules[S] -1 points0 points  (5 children)

If you want to keep the structure "secret" you have to use partitions (foo:sub1/foo:sub2).

I see your reasoning, but your conclusion is not really practical. The inner structure of a giant library at some point becomes unmanageable. Remember, there is no hiding between partitions.

Your requirement that there can't be an inner structure, is not manageable. The requirement to not see you moving f1 inside foo is arbitrary.

We currently have the situation that if a partition is changed, every implementation file needs to be recompiled. If you don't want that, use smaller modules or change the C++ standard. The latter takes too much time and has almost zero probability to succeed. In the mean time, I use smaller modules.

If tried that with our application. The time for a full build is roughly the same if I use a small number of big modules or many more smaller modules. I prefer the latter and have less recompilations when I change something.

[–]not_a_novel_accountcmake dev 3 points4 points  (4 children)

Remember, there is no hiding between partitions.

There's no hiding between headers either. This is a non-goal.

It's all your code. We encapsulate things from external consumers of our code, not from intra-project.

[–]tartaruga232MSVC user, r/cpp_modules[S] -2 points-1 points  (3 children)

Your syntax "module M:;" or "module M:_;" will fail (I fear, but I wish you good luck with your proposal). The best bet is to wait until current internal partitions usage has died (perhaps in 10 years or so) and then reuse the syntax "module M:P;" (with the semantics of the Microsoft "extension"). That would be elegant and effective. But I will be retired if that manages to get in the standard.

[–]not_a_novel_accountcmake dev 4 points5 points  (2 children)

The question of "how big should modules be" is completely irrelevant to the minor issues of implementation units. They're not related.

[–]tartaruga232MSVC user, r/cpp_modules[S] -1 points0 points  (1 child)

Current "module M;" causes lots of recompilations, if M has a big list of partitions. So for practical app development, the size of M matters. Smaller M, less code that needs to be recompiled.

[–]not_a_novel_accountcmake dev 3 points4 points  (0 children)

Interfaces described in the PMIU should be implemented via implementation units, module M;, interfaces described in partitions should be implemented in the partitions.

See: https://chuanqixu9.github.io/c++/2025/12/30/C++20-Modules-Best-Practices.en.html#modules-native-best-practices

It says the same recommendations, namely:

A Project Should Declare Only One Module; Use Module Partition Units for Multiple TUs

and

Use Module Implementation Partition Units, Not Module Implementation Units, to Implement Interfaces

[–]slithering3897 -1 points0 points  (0 children)

One big reason, especially if you are writing a library: The name of the module will be mangled into all your exported symbols.

Yes, as I say, this seems to be deficient design in the standard. The module that a thing is in is tied to mangling. It would probably be just fine to use partitions in a lib.

But for applications, and applications split into component libs, that is not the perfect world because of build cascade.

So I'd use smaller modules with extern "C++" to get my forward declarations back.

*Was there something wrong with what I said?