Description
Dear libc++ team,
I'm really concerned about growth in the preprocessed file size of core STL header files. For example, preprocessing a 1-liner like the following with -D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES
#include <vector>
expands to 2 077 167 bytes (~2 megabytes)! Without the transitive include define, it is even larger at 2 467 776 (~2.4 megabytes). The problem with this is the cost that it imposes on every compilation unit for using something as simple as a std::vector
.
Of those two megabytes of preprocessed code, only a tiny portion is ultimately concerned with std::vector
.
Here are some of the things that get pulled in, for unclear reasons:
In file included from test.cpp:1:
In file included from /usr/include/c++/v1/vector:321:
In file included from /usr/include/c++/v1/__format/formatter_bool.h:17:
In file included from /usr/include/c++/v1/__format/concepts.h:17:
In file included from /usr/include/c++/v1/__format/format_parse_context.h:16:
In file included from /usr/include/c++/v1/string_view:246:
In file included from /usr/include/c++/v1/compare:145:
In file included from /usr/include/c++/v1/__compare/compare_partial_order_fallback.h:13:
In file included from /usr/include/c++/v1/__compare/partial_order.h:14:
In file included from /usr/include/c++/v1/__compare/weak_order.h:14:
In file included from /usr/include/c++/v1/__compare/strong_order.h:20:
In file included from /usr/include/c++/v1/cmath....
So using vector
pulls in string
(why), which pulls in __compare/strong_order.h
, which pulls in the entire C & C++ math library, which is huge.
Major parts of tuple
, locale
, atomic
, mutex
, ctime
, typeinfo
, memory
are also included as well.
Much of this growth seems related to C++20 features that have started to affect C++17 builds. For example all of the code in partial_order
, weak_order
, strong_order
, etc. is actually #ifdef
-ed out when compiling in C++17 mode. But that is only true for the body part. All of the dependent header files are still included. Here is an example from __compare/strong_order.h
-basically all of the body code is disabled by #if _LIBCPP_STD_VER >= 20
, but the #include
directives at the top aren't.
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP___COMPARE_STRONG_ORDER
#define _LIBCPP___COMPARE_STRONG_ORDER
#include <__bit/bit_cast.h>
#include <__compare/compare_three_way.h>
#include <__compare/ordering.h>
#include <__config>
#include <__type_traits/conditional.h>
#include <__type_traits/decay.h>
#include <__utility/forward.h>
#include <__utility/priority_tag.h>
#include <cmath>
#include <cstdint>
#include <limits>
#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20
This issue is a plea for some attention for this issue. Would it make sense to benchmark libc++ header growth for central header files needed by many projects and start to work more actively against regressions? For projects that want to avoid the C++20+ header file growth, it would be great to trim these to what is truly needed in C++11, 14, or 17 builds.
Here are a few more examples, again all compiled in C++17 mode:
Header | Preprocessed size |
---|---|
vector |
2'046'574 bytes |
iostream |
1'906'216 bytes |
algorithm |
1'163'944 bytes |
string |
1'056'382 bytes |
list |
1'021'302 bytes |
forward_list |
1'003'060 bytes |
iterator |
965'992 bytes |
array |
739'743 bytes |
variant |
769'429 bytes |
tuple |
495'462 bytes |
utility |
427'718 bytes |