C++ 20 Modules Update

FYI, I opened a feature request with MSVC to add support for a file-based mechanism for specifying the list of public modules for DLLs.

This is already the status quo for static libraries on MSVC. And from what I can see there doesn’t seem to be a mechanism in MSVC’s static library toolchain that allows to restrict this, so Ben’s suggestion to enforce it on the CMake level instead may be the only option here.

Note that we need the mechanism regardless because we need to write install and export bits for these modules. While “can use from elsewhere” may be a possible IDE thing, writing out these files is certainly outside the scope.

I followed these

to create:

  • Module interface partition unit.
  • Internal module partition unit.

So I have:

Details.cpp with module RToolBox:MetaInfo.Details;
Details.cppm with export module RToolBox:MetaInfo.Details;

When building I get the following error:

[build] ninja: build stopped: multiple rules generate CMakeFiles/RToolBox.dir/Debug/RToolBox-MetaInfo.Details.ifc.

I add them like that:

target_sources("${PROJECT_NAME}"
PUBLIC
  FILE_SET cxx_modules TYPE CXX_MODULES
  FILES
    "src/MetaInfo/Details.cpp"
    "src/MetaInfo/Details.cppm"

It looks like not all of the proposal is implemented (or I do not understand it yet):

Your code is invalid: you have two TUs in module ‘RToolBox’ with the same partition name ‘MetaInfo.Details’. A named module shall not contain multiple module partitions with the same module-partition

1 Like

@DanielaE Thank you for pointing me to the specification. I looked everywhere but there (I assumed it going to be too techincal). This example tied up the loose ends.
I got confused that partition implementation TUs are a thing.

While trying to understand modules. I watched this talk (entirely by coincidence - noticed a YouTube message a few days ago): https://www.youtube.com/watch?v=DJTEUFRslbI
So if I understand correctly we are supposed to compile std on our own for every project.

Will in that case make sense for the build system (in our case CMake) to provide standard facilities to automate this task? This is something I haven’t yet seen discussed anywhere else but in the talk in the link.

Ah,that latest talk of mine :blush:

Your proposal makes sense. MSBuild does it since msvc 17.6 (or .5? I can’t remember).

2 Likes

Yes. The idea is that we inspect information from the compiler about the standard library in use and make a target like CMake::CXX23 that provides the modules. It would be implicitly linked by anything using cxx_std_23. Note that adding flags like -std=c++23 not through a CMake-recognized standard-setting mechanism would likely not be something we notice.

The .cpp file is not a module file (i.e., it does not produce a BMI). It is instead an implementation unit of a module; it does not belong in CXX_MODULES filesets.

Wat?
Sorry, but a module TU with a partition name will always create a BMI because it is either a module interface partition (that contributes to the externally visible module interface) or an internal partition (that may or may not contribute to the externally reachable entitities of a module).

Oh, that : hid itself very well (I missed that . can be in the partition name too…). Anyways, MSVC does have an extension to allow such things (“implementation of partition” units; these don’t officially exist and should instead just use the module name only). Those files belong in the normal sources list.

We don’t like “extensions”, do we? :scream:

But you’re right: module implementation units (the ones without a partition name) belong into the regular FILES section because they don’t create BMIs.

BTW: I’m experimenting with CMake 3.27 right now. Unfortunately it broke my (admittedly very brittle) “implementation” of ‘compiling header units with CMake workaround’ that worked in 3.26.

Sounds good. All three vendors have agreed to support STD modules in C++20 mode as an extension. CMake should probably do too: Supporting `import std;` in C++20 · Issue #3945 · microsoft/STL · GitHub

The issue @RobN created got closed. I got the impression that this is considered a problem of the build tools and not clang itself. So I would like to ask if there are any workarounds for this issue. Currently touching a single file can result in cascade of recompilations.

There’s some work that would be needed to do this, but it isn’t required to make modules work, hence it not being done right now. The basic requirement is that the collator has the compiler write the BMI to a temporary file and then communicate with a command in the same rule that does cmake -E copy_if_different to the real location. How exactly this gets communicated needs worked out though.

Are header units supported in cmake 3.27?
I am getting an error:

error: header file (aka ‘/usr/bin/…/lib/gcc/x86_64-linux-gnu/13/…/…/…/…/include/c++/13/vector’) cannot be imported because it is not known to be a header unit

Unfortunately no, they are not (yet).

1 Like

I also tried using gcc - I compiled the following revision

ommit 024f135a1e9b8f8e102960357cae6e99e1dbe6eb
Author: Ben Boeckel ben.boeckel@kitware.com
Date: Fri Sep 1 09:04:02 2023 -0400

p1689r5: initial support

This patch implements support for [P1689R5][] to communicate to a build
system the C++20 module dependencies to build systems so that they may
build `.gcm` files in the proper order.

Support is communicated through the following three new flags:

- `-fdeps-format=` specifies the format for the output. Currently named
  `p1689r5`.

- `-fdeps-file=` specifies the path to the file to write the format to.

- `-fdeps-target=` specifies the `.o` that will be written for the TU
  that is scanned. This is required so that the build system can
  correlate the dependency output with the actual compilation that will
  occur.

The error is now:

[build] /usr/local/bin/g++ -DENABLE_TESTS -I/home/pkoziol/repos/aoc22/src/…/include/aoc22 -isystem /home/pkoziol/repos/aoc22/tests/Catch2/src/catch2/… -isystem /home/pkoziol/repos/aoc22/builds/dev_ninja_gcc/tests/Catch2/generated-includes -g -std=c++20 -Wall -Wextra -Wpedantic -Werror -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wunused -Woverloaded-virtual -Wconversion -Wsign-conversion -Wmisleading-indentation -Wnull-dereference -Wdouble-promotion -Wformat=2 -Wimplicit-fallthrough -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wuseless-cast /home/pkoziol/repos/aoc22/imports/aoc22/day2.cppm -MT src/CMakeFiles/aoc22.dir//imports/aoc22/day2.cppm.o.ddi -MD -MF src/CMakeFiles/aoc22.dir//imports/aoc22/day2.cppm.o.ddi.d -fdeps-file=src/CMakeFiles/aoc22.dir//imports/aoc22/day2.cppm.o.ddi -fdeps-target=src/CMakeFiles/aoc22.dir//imports/aoc22/day2.cppm.o
[build] /usr/bin/ld:/home/pkoziol/repos/aoc22/imports/aoc22/day2.cppm: file format not recognized; treating as linker script

(Note the compiler flags mentioned in https://www.kitware.com/import-cmake-c20-modules/ are outdated)

Should I use “-x c++” option? Clang doesn’t have problem with this.

Also,I am setting set(CMAKE_CXX_EXTENSIONS OFF)

Header units are not supported at all in CMake right now. What is the content of day2.cppm?

It looks like GCC is not recognizing the extension; does it work if you use .cpp or some other typical file extension?