But the specific problem of include-what-you-use will still be encountered if you include directly from C libraries like system headers or library dependencies.
Do you have evidence that the situation has changed? Last I checked it still remains the case that modules inhibit parallelism and hence result in slower builds in most practical work loads. But of course if you have evidence the contrary I'd be happy to see it.
yeah, but the same graph never shows modules being faster... it only ever shows them being the same or slower. If I'm going to put in all that work, the result should be *faster*
What significantly improves compile-times is Pre-Compiled Headers (PCH), which most compilers have supported for decades.
The study you mention, does not show data for them.
Having ported one >1 million LOC C++ app to use modules in two compilers, the compile time improvement of modules over PCH was not distinguishable from noise.
Modules have many advantages, like better encapsulation, etc.
The main thing people want from them seems to be better compile times, which is the one thing they don't deliver, at least over the PCH solutions that have existed for decades, are already supported by all build systems, etc.
Compared to modules, PCHs are "zero-effort" and deliver performance instantaneously.
CMake supports these with all major compilers...
I'll just google "<your build system> pre-compiled headers" and see if there is a flag or option that you can enabled.
You will definetly need quite a bit of fine tuning for apps over 500k LOC or so, but if your app is under that, and you are splitting code between .h and .cpp files appropriately, just flipping a flag might get you 80% there.
The speed ups you see people get from PCHs is like 20-30% faster compile-times. So they are more a "nice to have" feature than something that will solve your compile-time problems.
If your app is structured in such a way that it takes 20 min to compile, this can cut it to 15 min at most, but that would probably still suck. If you want more, then you'd need to consider other solutions like distributed build caches (sccache, etc.).
Modules inhibit parallelism because modules are ordered along a DAG and must be compiled from the root of the DAG down to the leafs in order. So consider a traditional setup as follows:
A.cpp <- A.h <- B.h <- C.h <- D.h
B.cpp <- B.h <- C.h <- D.h
C.cpp <- C.h <- D.h
D.cpp <- D.h
All four of those cpp files can be built in parallel, even though you're right that all of the header files are being reparsed multiple times. My claim is that parsing header files is incredibly cheap, it's translating the .cpp files that's expensive because cpp files are where the bulk of the semantic analysis and type checking is performed.
With modules, the same compilation model looks like this:
A.mxx <- B.mxx <- C.mxx <- D.mxx
There's no longer header/source and there's no longer redundancy, but I can't build this in parallel anymore. I have to first build D.mxx, then C.mxx, then B.mxx then A.mxx in serial.
$ clang -x c++ -E - <<<"#include <vector>" | wc -l
27378
Other headers are similar: algorithm 23103
array 23450
memory 15909
random 52107
thread 31424
tuple 9240
(Of course, a bunch of this code is shared, e.g. including both thread and vector is “only” 35713 loc total, not 60kloc.)I believe C++ compilers have SIMD-accelerated lexers/parsers because of the sheer explosion of code due to headers and templates.
Modules do not have any effect on the linker one way or another. They are independent of it.
Some C++ developers can keep using their pre-historic UNIX like tooling, whereas others will embrace the fusion of compiler, linker and build system.
Other languages with modules have a similar issue. Go is the only language I know of that makes it a hard compiler error to import an unused module.