C++ header-units.json reference
The header-units.json
file serves two purposes:
- Specify which header files can be translated into header units when
/translateInclude
is specified. - Minimize duplicated symbols to increase build throughput.
This file must be in the same directory as the included header file. This file is only used when /translateInclude
is specified along with either /scanDependencies
or /sourceDependencies:directives
.
Rationale
Some header files can't be safely translated to header units. Header files that depend on macros that aren't defined on the command line, or that aren't defined in the header files included by the header, can't be translated to header units.
If a header defines macros that affect whether other headers are included, it can't be safely translated. For example, given a.h
, b.h
and macros.h
, which are all in the same directory:
// a.h
#include "macros.h" // #defines MACRO=1
#ifdef MACRO
#include "b.h"
#endif
The header-units.json
in this directory can contain a.h
and b.h
, but not macros.h
. The header-units.json
for this example would be similar to this:
{
"Version": "1.0",
"BuildAsHeaderUnits": [
// macros.h should not be listed
"a.h",
"b.h"
]
}
The reason macros.h
can't be listed in this header-units.json
file is that during the scan phase, the header unit (.ifc
) might not be compiled yet for macros.h
. In that case, MACRO
won't be defined when a.h
is compiled. That means b.h
will be missing from the list of dependencies for a.h
. Since it isn't in the list of dependencies, the build system won't build a header unit for b.h
despite it being listed in the header-units.json
file.
To avoid this problem, when there's a dependency on a macro in another header file, the header file that defines the macro is excluded from the list of files that can be compiled into a header unit. This way the header file that defines the macro is treated as a normal #include
and MACRO
will be visible so that b.h
is included and listed as one of the dependencies.
Preventing duplicated symbols
The header-units.json
file is also important because it allows for automatic header unit creation without duplicated symbols. It does this by creating "atomic" header units for the files listed in header-units.json
. The imported header units don't contain duplicated symbols from the various #include
directives that were processed while translating the header file.
For example, consider two header files that both include a common header file. Both header files are included by the same source file:
// a.h
#include "b.h"
// c.h
#include "b.h"
// Source.cpp
import "a.h";
import "c.h";
If the compiler built header units for a.h
, b.h
and c.h
, then the compiled header units a.h.ifc
, b.h.ifc
, and c.h.ifc
would each contain all of the types from b.h
. Compiling Source.cpp
, which imports both a.h
and c.h
, would require the compiler to deduplicate the b.h
types, which would impact build performance.
But if there's a header-units.json
in the b.h
directory, and /translateInclude
is specified, then the following happens:
- The scan of
a.h
andc.h
listsb.h
as a header unit import in the dependency scan files generated by the compiler. - The build system reads the dependency scan files and determines to build
b.h.ifc
first. - Then the build system adds
/headerUnit
forb.h.ifc
to the command lines for compilinga.h
andc.h
. It calls the compiler to build the header unitsa.h.ifc
andc.h.ifc
. Because/translateInclude
is specified, and/headerUnit for b.h.ifc
is also specified,a.h.ifc
andc.h.ifc
won't containb.h
types, so there won't be any duplication in the produced header units.
Schema
There's a headerunits.json
file for the Standard Template Library (STL) headers. The build system uses it to determine whether to create a header unit for an STL header file, and for its dependencies. If the STL header file isn't on the list, it's treated as a normal #include
instead of importing it as a header unit.
You can see the header-units.json
file under the installation directory for Visual Studio. For example: %ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.30.30705\include\header-units.json
The header-units.json
file starts with the schema version, followed by an array of filenames for headers that can be built into header units.
The schema also supports comments, as shown here:
{
"Version": "1.0",
"BuildAsHeaderUnits": [
// "__msvc_all_public_headers.hpp", // for testing, not production
"__msvc_system_error_abi.hpp",
"__msvc_tzdb.hpp",
"__msvc_xlocinfo_types.hpp",
"algorithm",
"any",
"array",
"atomic",
"barrier",
"bit",
"bitset",
// "cassert", // design is permanently incompatible with header units
...
}
Search rules
The compiler looks for this file in the same directory as the header file being processed. If your library is organized into subdirectories, each subdirectory needs its own header-units.json
file.
See also
Walkthrough: Import STL libraries as header units
Walkthrough: Build and import header units in your Visual C++ projects