C++ header-units.json 参考

header-units.json 文件有两种用途:

  • 规定在指定了 /translateInclude 时哪些头文件可以转换为头单元。
  • 最大程度地减少重复的符号以提高生成吞吐量。

此文件必须与包含的头文件位于同一目录中。 仅当 /translateInclude/scanDependencies/sourceDependencies:directives 一起指定时才会使用此文件。

理由

某些头文件无法安全地转换为头单元。 符合以下条件的头文件无法转换为标题单元:依赖于未在命令行中定义的宏,或未在头包含的头文件中定义。

如果头定义的宏会影响是否包含其他头,则无法安全地对其进行转换。 例如,给定 a.hb.hmacros.h,它们都在同一个目录中:

// a.h

#include "macros.h" // #defines MACRO=1
#ifdef MACRO
#include "b.h"
#endif

此目录中的 header-units.json 可以包含 a.hb.h,但不能包含 macros.h。 对于此示例,header-units.json 如下所示:

{
    "Version": "1.0",
    "BuildAsHeaderUnits": [
        // macros.h should not be listed
        "a.h",
        "b.h"         
     ] 
}

macros.h 无法在此 header-units.json 文件中列出的原因是在扫描阶段,可能尚未为 macros.h 编译头单元 (.ifc)。 在这种情况下,在编译 MACRO 时不会定义 a.h。 这意味着 a.h 的依赖项列表中将缺少 b.h。 因为它不在依赖项列表中,所以生成系统不会为 b.h 生成标头单元,尽管它已列在 header-units.json 文件中。

为了避免此问题,当另一个头文件中的宏存在依赖项时,定义宏的头文件将从可编译为标头单元的文件列表中排除。 这样,定义宏的头文件被视为正常 #include,并且 MACRO 将可见,这样将包含 b.h 并列为依赖项之一。

防止重复符号

header-units.json 文件也很重要,因为它允许自动创建头单元,而无需重复符号。 通过为 header-units.json 中列出的文件创建“原子”头单元来做到这一点。 导入的头单元不包含在转换头文件时处理的各种 #include 指令中的重复符号。

例如,假设有两个头文件,两者都包含一个通用头文件。 两个头文件都包含在同一个源文件中:

// a.h
#include "b.h"
 
// c.h
#include "b.h"
 
// Source.cpp
import "a.h";
import "c.h";

如果编译器为 a.hb.hc.h 构建头单元,那么编译后的头单元 a.h.ifcb.h.ifcc.h.ifc 将分别包含 b.h 中的所有类型。 编译 Source.cpp 会同时导入 a.hc.h,这将需要编译器对 b.h 类型进行重复数据删除,这会影响生成的性能。

但是如果 b.h 目录中有 header-units.json,并且指定了 /translateInclude,则会发生以下情况:

  1. 扫描 a.hc.h 会将 b.h 作为头单元导入列出在编译器生成的依赖扫描文件中。
  2. 生成系统读取依赖项扫描文件,并确定先生成 b.h.ifc
  3. 然后生成系统将在命令行中为 b.h.ifc 添加 /headerUnit 以编译 a.hc.h。 它调用编译器来生成头单元 a.h.ifcc.h.ifc。 因为指定了 /translateInclude,也指定了 /headerUnit for b.h.ifc,所以 a.h.ifcc.h.ifc 不会包含 b.h 类型,所以生成的头单元不会有任何重复项。

架构

标准模板库 (STL) 头有一个 headerunits.json 文件。 生成系统使用此文件来确定是否为 STL 头文件及其依赖项创建头单元。 如果 STL 头文件不在列表中,则将其视为普通 #include,而不是将其作为标头单元导入。

你可以在 Visual Studio 的安装目录下看到 header-units.json 文件。 例如:%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.30.30705\include\header-units.json

header-units.json 文件以模式版本开头,后跟可以构建到头单元中的头文件名数组。

该架构还支持注释,如下所示:

{
    "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
        ...
}

搜索规则

编译器在与正在处理的头文件相同的目录中查找此文件。 如果库组织为子目录,则每个子目录都需要其自己的 header-units.json 文件。

另请参阅

演练:导入 STL 库作为标头单位
演练:在 Visual C++ 项目中生成和导入标头单元