The C++ standard library adds new features in every C++ version. To
implement these new features libc++ adds more includes to a header. This
means the number of transitive includes grows with newer language version.
The growing size is an issue for users. This change is motivated by a
report of the Chromium team where properly enabling C++23's
std::formatter<std::vector<bool>::reference> had a significant impact on
their build time.
In D149543 Hans Wennborg reported the following
In Chromium we noticed that this almost doubled the preprocessed size of <vector>, from ca 1.6 MB to 3.2 MB. Since it's a widely included header, that results in ca 8 GB (2.5%) of extra code to compile during a full build.
This is an experiment to see how libc++ can reduce this size by only
"enabling" headers per language version. This is mainly done at the level
of the granularized includes, since they often have features for one or a
limited set of minimum language versions.
The compare header is an exception, its inclusion is often mandated by the
standard so this header is entirely guarded by C++20 or newer.
At the moment the removed transitive includes are not conditionally
restored like we usually do; this is intentional for the RFC. It gives a
good view what changes.
For this patch only vector is adjusted and mainly based on what I recall
being based on a language version.
I did some testing with the size of a preprocessed file that contains
#include <vector>
I used the following command
clang++ -E test.cpp -nostdinc++ -I <build>/include/c++/v1" -I -std=$std |wc -l
Version | Before | After |
---------+--------+------- | ||
C++03 | 53153 | 38721 |
C++11 | 55665 | 40914 |
C++14 | 56709 | 41896 |
C++17 | 60591 | 44957 |
C++20 | 75905 | 75863 |
C++23 | 61867 | 61828 |
C++26 | 61867 | 61828 |
The interesting value is C++23 (before) there the size drops a lot. In
C++23 some transitive includes are removed unconditionally. These can be
removed with a build option. The Chromimum team uses this option. This is
done by the following command
clang++ -E test.cpp -nostdinc++ -I <build>/include/c++/v1" -I -std=$std -D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES |wc -l
Version | Before | After |
---------+--------+------- | ||
C++03 | 45883 | 18482 |
C++11 | 48366 | 19352 |
C++14 | 49352 | 19745 |
C++17 | 51590 | 22331 |
C++20 | 61259 | 61217 |
C++23 | 61867 | 61828 |
C++26 | 61867 | 61828 |
Note <vector> includes this in C++20 even when it's only used in C++23. So in <vector> we could make this include optional.