C++20 modules in beman project libraries

Do you know this paper: C++20 modules and Boost: deep dive?

I have a PR which show the current state and problems:

1 Like

Thanks Claus –

Thanks for the link. This is a good update on the state of things. I’d note that on the gcc side, a couple weeks ago they merged support for import std and compat into main. So it seems like we’re getting closer to real modules support.

Also, be aware that @dietmarkuehl while in Poland was hacking his cmake for beman execution. Should we try with additional repos? Not sure where we go next with this.

2 Likes

I think Claus’s efforts on modules were triggered somewhat by me creating a PR with a modularized version of beman::execution26. Based on the comments and linked articles it will need some work to make the compilers happy.

That’s fair. It would be interesting to give gcc15 (aka the current trunk) a whirl because as was reported in Poland import std recently got merged.

1 Like

Some Professional CMake recommendations:

from 17.4. Recommended Practices

Projects should avoid setting compiler and linker flags directly to control the
language standard used. The required flags vary from compiler to compiler, so it
is more robust, more maintainable, and more convenient to use the features that
CMake provides and allow it to populate the flags appropriately. The
CMakeLists.txt file will also more clearly express the intent, since human-
readable variables and properties are used instead of often cryptic raw compiler
and linker flags.

The simplest method for controlling language standard requirements is to use the
CMAKE_<LANG>_STANDARD, CMAKE_<LANG>_STANDARD_REQUIRED, and
CMAKE_<LANG>_EXTENSIONS variables. These can be used to set the language
standard behavior for the entire project, ensuring consistent usage across all
targets. These variables should ideally be set just after the first project()
command in the top level CMakeLists.txt file. Projects should always set all
three variables together to make clear how the language standard requirements
should be enforced, and whether compiler extensions are permitted. Omitting
CMAKE_<LANG>_STANDARD_REQUIRED or CMAKE_<LANG>_EXTENSIONS can lead to unexpected
behavior, as the defaults may not be what some developers intuitively expect.

Projects should check to see if CMAKE_<LANG>_STANDARD and
CMAKE_<LANG>_EXTENSIONS are already set before setting them to a particular
value. Some scenarios may require enforcing stronger settings than the project’s
own minimum requirements, such as it being incorporated into a larger parent
project that needs to use a higher language version. This becomes critical if
C++20 modules are used, since they require a consistent language standard to be
used throughout the build.

If using CMake 3.8 or later, compile features can be used to specify the desired
language standard on a per-target basis. The target_compile_features() command
makes this easy and clearly specifies whether such requirements are PRIVATE,
PUBLIC, or INTERFACE. The main advantage of specifying a language requirement
this way is that it can be enforced transitively on other targets via PUBLIC and
INTERFACE relationships. These requirements are also preserved when targets are
exported and installed (see Chapter 35, Installing).

If a target exports any C++20 modules, it must set a compile feature requiring C++20 or later.

Avoid the more granular compile features like cxx_override and cxx_constexpr.
They are hard to use, difficult to maintain, and serve little practical use with
most compilers in active use today. Prefer instead to use only the higher level
meta- features that specify the language standard directly, such as cxx_std_17,
c_std_11, and so on.

Avoid directly setting the <LANG>_STANDARD and <LANG>_EXTENSIONS properties on
individual targets. Express the language standard requirement with a
<lang>_std_<value> compile feature instead, or use appropriate logic at the top
of the project to check if the standard has been set by a parent project before
setting it globally for the whole build with a CMAKE_<LANG>_STANDARD variable.
This ensures a parent project can enforce a higher language standard if it needs
to. Similarly, use top level logic to conditionally set CMAKE_<LANG>_EXTENSIONS
so it applies consistently to the whole build, but still allows a parent project
to enable extensions if needed.  There is no compile feature for enabling or
disabling extensions, so this can only be safely controlled with the
CMAKE_<LANG>_EXTENSIONS variable.


If policy CMP0128 is not set to NEW, the <LANG>_EXTENSIONS properties and their
associated variables often only take effect if the corresponding <LANG>_STANDARD
is also set. This is due to how compilers frequently combine the two into a
single flag. Therefore, unless using CMake 3.22 or later with policy CMP0128 set
to NEW, it is difficult to escape having to specify CMAKE_<LANG>_STANDARD, even
when compile features are used.

There’s an update to the Boost progress on modules. C++20 modules and Boost: a prototype

Recent reddit update on cmake 4 and gcc15 supporting import std; Reddit - Dive into anything

Yeah, given the GCC 15 release, we should make an issue for Exemplar to provide C++ modules. To get started, see modules talks:

It looks like Andreas is giving an updated version of his talk at ACCU. Anyone who feels like they couldn’t make the relevant PR to Exemplar, I recommend checking out that version of that talk when you can get access. Either of the above should be updated enough otherwise.

I’ve opened a issue (PR shortly) to add module support to scope. I’ve done basic tests by hand with g+±15 and import std and it’s nice!

It appears that fmtlib has a special file for doing modules test, but I saw noted in a recent PR that they don’t have CI for modules – that would be something nice to setup, but I imagine might require cmake 4 - (@vito.gamberini do you know for sure – I’m using 4.02 locally now).

CMake 3.28 is all that’s required for modules, which is what ships in the current Ubuntu LTS (the internationally recognized signal for ā€œOK to put as your minimum versionā€).

Throwing my hat in the ā€œthis is what modules might look likeā€ ring

A much more intrusive take that assumes you have a compiler with pretty good named module support. None of the CI containers met that assumption. Working on it.

4 Likes

I just noticed that the gcc-15 Ubuntu 25.04 package installs the module interface definitions in /usr/include. Not sure if anyone at ubuntu or debian noticed, since they are in ā€˜bits’ but it’s at least something:

/usr/include/c++/15/bits/std.compat.cc
29:export module std.compat;

/usr/include/c++/15/bits/std.cc
37:export module std;

Interesting – and geez I almost forgot about compat.

As a progress report I’ll say that scope has ā€˜crossed the rubicon’ to being ā€˜modules-ready’. It’s been tested on 3 compilers and the cmake is updated to test it on those platforms. Import std or compat is not involved since that’s a higher bar. I think the remaining issues we have come down to needing g++15 in CI system and fixing clang compiles to work with cmake 3.28.

Thanks to all that participated in the adventure, I know I learned a lot about the state of modules :slight_smile:

1 Like

With ubuntu 25.4 I have a working eperimantal example tested with cxx_modules and import std:

There’s no rush to incorporate import std work before CMake stabilizes support. It missed the train for the 4.1 branch so it has more time to cook before seeing daylight.

I think it’s very unlikely the current usage will remain the idiomatic one. I think C++23 and above targets will get ā€œautomaticā€ import std from supported compilers when support is stabilized in CMake.

but we need to be prepared and to have a concept how to work with compilers, that does not support CXX_MODULES!

see i.e.: Add cmake-init generated CMake files by ClausKlein Ā· Pull Request #4 Ā· ClausKlein/asio Ā· GitHub

There’s really only two options:

  • Libraries targeting C++20 support really mean C++20 support, if your compiler doesn’t support C++20, it can’t package the library. ā€œC++20ā€ includes modules.

  • You seperate out the call to target_sources(FILE_SET CXX_HEADER) based on whether the compiler supports modules. This is pretty simple but hurts packaging reproducability, different compilers producing different packages for the same library is bad.

So both suck, I leave it to the other Bemanites to vote on which they hate less.

That is not really true:

i.e.:

bash-5.2$ cmake -S . -B build --fresh -D CMAKE_CXX_STANDARD=20
-- The CXX compiler identification is AppleClang 16.0.0.16000026
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Performing Test COMPILER_HAS_HIDDEN_VISIBILITY
-- Performing Test COMPILER_HAS_HIDDEN_VISIBILITY - Success
-- Performing Test COMPILER_HAS_HIDDEN_INLINE_VISIBILITY
-- Performing Test COMPILER_HAS_HIDDEN_INLINE_VISIBILITY - Success
-- Performing Test COMPILER_HAS_DEPRECATED_ATTR
-- Performing Test COMPILER_HAS_DEPRECATED_ATTR - Success
-- Configuring done (1.3s)
CMake Error in CMakeLists.txt:
  The target named "Algo" has C++ sources that may use modules, but the
  compiler does not provide a way to discover the import graph dependencies.
  See the cmake-cxxmodules(7) manual for details.  Use the
  CMAKE_CXX_SCAN_FOR_MODULES variable to enable or disable scanning.


-- Generating done (0.0s)
CMake Generate step failed.  Build files cannot be regenerated correctly.
bash-5.2$ 

It is really true.

C++20 is a language standard, it include modules, they’re not an optional part of the standard. No compiler fully supports C++20, but that’s a separate discussion.

The CMAKE_CXX_STANDARD=20 tells CMake what to ask the compiler for. CMake only verifies the compiler supports such a flag, it doesn’t verify that the compiler actually supports the entire language standard.

It is a totally valid choice for a project to say ā€œI only support compilers which support C++20, including named modules.ā€

Anyway, on the topic of AppleClang, I’m unclear if it actually doesn’t support modules (ie, won’t accept -fmodule-file flags), or if they simply don’t ship clang-scan-deps and thus lack a scanner (well, I know for certain they don’t ship a scanner).

If it’s only the latter we might be able to hack something into upstream CMake that allows the user to specify a module scanner and backdoor module support into AppleClang via the upstream clang-scan-deps.

EDIT: Ya it supports modules, I’m going to explore a solution to the scanner problem.