Modules Woes
Author: thothonegan
Tags: c++ modules catalyst
C++20 modules are amazing. They keep things cleaner, can speed up compiling drastically, and allow for a lot of flexibility. However, there are still issues with how modules work currently as they are still being implemented. Here are some of the issues I've run into.
Headers in the Global Module Fragment
Modules have a section called the Global Module Fragment (GMF). This is where code not written to
use modules lives. For example, if you need to use iostream
, you include it in GMF. Modules, however,
are sealed—no module can affect another module. To guarantee this, the contents of the header are
placed into the GMF—meaning every module that includes iostream
, now has the complete contents of
iostream. So you end up with lots of copies of the same headers in multiple module files, resulting in:
- The BMI (output of the module) gets bigger since it has an entire copy of the header.
- Compile time of the file is slower, since it has to process the header.
- Linking and usage of the module are slower because it needs to de-duplicate anything in the GMF (we don't want it to cause an ODR failure).
- Lastly, debug information and line data explode in size. Since each header might have been included with different preprocessor settings and has a different source trace, it has to store all of it for compile time errors. Imagine importing multiple modules that include std::map, and one of them causes a compiler error in the template due to a bad template parameter. The compiler needs the entire copy of the header for that module to output the correct line numbers. In clang, this can result in source locations exhaustion.
Once everything is moved over to modules, most of these problems get minimized.
import std
import std
is c++23 adding support for modules in the standard library. While it works in certain places,
it's very much incomplete.
- CMake doesn't support it yet except in experimental modes
- Compilers are split between providing the modules or forcing you to compile them yourselves as part of the program.
BMI portability
The BMI (or PCM/IFC for clang/MSVC respectively) is how the compilation of the module is written to disk. Generally, this is a file similar to a PCH. Right now, though, it is not considered a stable format—between projects. Because of this, it has to be recompiled for every other project that uses it. This also applies within Okami since Okami needs to parse the module to be able to extract the Canis data. Okami works around this by managing the PCM itself and reusing as needed, but this cannot be used with the copies CMake works on. Potentially, this can be better in the future.
Windows support / MSVC
MSVC halfway works and gets better all the time, but it fails on various constructs in odd ways. It's been a while since I tried it, but it ran into some basic issues with things like importing fmt properly that I switched to compiling with Clang on Windows. This opened up other issues...
Windows support / Clang
windows.h
has always been a bad header. This gets much worse with modules, since so many other headers
include it, and it defines a ton of symbols. This makes any complex program cause source location
exhaustion, preventing things from compiling. You can do things to reduce the symbols, such as creating
a Windows module to help with the duplication. However, main c++ headers also include Windows header files
with a huge number of symbols, so you can only go so far. This gets worse and worse the more
modules you import, since all the module state has to be imported into the current translation unit.
Conclusion
Most of these issues are teething issues. Either they are implementation issues that will be
fixed over time or issues with mixing headers and modules. While the header issues will get
better, there will always be code that uses headers and has to mix with modules. Once import std
is stable, this will be a huge improvement. As MSVC gets better module compatibility, it helps there.
And if the source location exhaustion can be improved, that will fix clang on windows.
Overall, modules are a big step forward, and while it is taking a few years to get in a reasonable state: theirs a lot more to be done.