Skip to content

Repo sync for protected CLA branch #4199

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions docs/build/walkthrough-header-units.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
description: "Learn more about C++ header units. Convert a header file to a header unit using Visual Studio 2022."
title: "Walkthrough: Build and import header units in Visual C++ projects"
ms.date: 05/12/2022
ms.date: 09/29/2022
ms.custom: "conceptual"
author: "tylermsft"
ms.author: "twhitney"
Expand All @@ -22,15 +22,15 @@ To use header units, you need Visual Studio 2019 16.10 or later.

A header unit is a binary representation of a header file. A header unit ends with an *`.ifc`* extension. The same format is used for named modules.

An important difference between a header unit and a header file is that a header unit isn't affected by macro definitions outside of the header unit. That is, you can't `#define` a symbol that causes the header unit to behave differently. By the time you import the header unit, the header unit is already compiled. This is different than how an `#include` file is treated because the included file can be affected by a macro definition outside of the header file. This is because the header file isn't compiled yet. It will go through the preprocessor when the source file that includes it is compiled.
An important difference between a header unit and a header file is that a header unit isn't affected by macro definitions outside of the header unit. That is, you can't define a preprocessor symbol that causes the header unit to behave differently. By the time you import the header unit, the header unit is already compiled. It's different from how an `#include` file is treated, because an included file can be affected by a macro definition outside of the header file, because the header file isn't compiled yet. It goes through the preprocessor when you compile the source file that includes it.

Header units can be imported in any order. This isn't true of header files because macro definitions defined in one header file might affect a subsequent header file. Macro definitions in one header unit can't affect another header unit.
Header units can be imported in any order, which isn't true of header files. Header file order matters because macro definitions defined in one header file might affect a subsequent header file. Macro definitions in one header unit can't affect another header unit.

Everything visible from a header file is also visible from a header unit, including macros defined within the header unit.

A header file must be translated into a header unit before it can be imported. An advantage of header units over PCH is that they can be used in distributed builds. For example, as long as you compile the *`.ifc`* and the program that imports it with the same compiler, and target the same platform and architecture, a header unit produced on one computer can be consumed on another. Unlike a PCH, when a header unit changes only it and what depends on it rebuild. Header units can be up to a magnitude smaller in size than a traditional `.pch`.
A header file must be translated into a header unit before it can be imported. An advantage of header units over PCH is that they can be used in distributed builds. For example, as long as you compile the *`.ifc`* and the program that imports it with the same compiler, and target the same platform and architecture, a header unit produced on one computer can be consumed on another. Unlike a PCH, when a header unit changes, only it and what depends on it are rebuilt. Header units can be up to an order of magnitude smaller in size than a traditional `.pch`.

Header units impose fewer constraints on the parity of compiler switches used to create the header unit and to compile the code that consumes it than a PCH does. However, some switch combinations and macro definitions might create one definition rule (ODR) violations between various translation units.
Header units impose fewer constraints on the parity of compiler switches used to create the header unit and to compile the code that consumes it than a PCH does. However, some switch combinations and macro definitions might create violations of the one definition rule (ODR) between various translation units.

Finally, header units are more flexible than a PCH. With a PCH, you can't choose to bring in only one of the headers in the PCH--the compiler processes all of them. With header units, even when you compile them together into a static library, you only bring the contents of the header unit you import into your application.

Expand All @@ -44,11 +44,11 @@ There are several ways to compile a file into a header unit:

- **Choose individual files to translate into header units**. This approach gives you file-by-file control over what is treated as a header unit. It's also useful when you must compile a file as a header unit that, because it doesn't have the default extension (`.ixx`, `.cppm`, `.h`, `.hpp`), wouldn't normally be compiled into a header unit. This approach is demonstrated in this walkthrough. To get started, see [Approach 1: Choose individual header units to build](#approach1).

- **Build a shared header unit project**. This is the recommended approach and provides more control over the organization and reuse of the imported header units. Create a static library project that contains the header units that you want and then reference it to import the header units. For a walkthrough of this approach, see [Build a header unit static library project for header units](walkthrough-import-stl-header-units.md#approach2).
- **Build a shared header unit project**. We recommend this approach because it provides more control over the organization and reuse of the imported header units. Create a static library project that contains the header units that you want and then reference it to import the header units. For a walkthrough of this approach, see [Build a header unit static library project for header units](walkthrough-import-stl-header-units.md#approach2).

- **Automatically scan for and build header units**. This approach is convenient, but is best suited to smaller projects because it doesn't guarantee optimal build throughput. For details about this approach, see [Approach 2: Automatically scan for header units](#approach2).

- As mentioned in the introduction, you can build and import STL header files as header units and automatically treat `#include` for STL library headers as `import` without rewriting your code. To see how, visit [Walkthrough: Import STL libraries as header units](walkthrough-import-stl-header-units.md).
- As mentioned in the introduction, you can build and import STL header files as header units, and automatically treat `#include` for STL library headers as `import` without rewriting your code. To see how, visit [Walkthrough: Import STL libraries as header units](walkthrough-import-stl-header-units.md).

## <a name="approach1"></a>Approach 1: Choose header units to build

Expand Down Expand Up @@ -97,31 +97,31 @@ Compile the header file as a header unit:

:::image type="content" source="media/change-item-type.png" alt-text="Screenshot that shows changing the item type to C/C++ compiler.":::

Later in this walkthrough, when you build this project, `Pythagorean.h` will be translated into a header unit. That's because the item type for this header file is set to **C/C++ compiler**, and because the default action for `.h` and `.hpp` files set this way is to translate the file into a header unit.
When you build this project later in this walkthrough, `Pythagorean.h` will be translated into a header unit. It's translated because the item type for this header file is set to **C/C++ compiler**, and because the default action for `.h` and `.hpp` files set this way is to translate the file into a header unit.

> [!NOTE]
> This isn't required for this walkthrough, but is provided for your information. To compile a file as a header unit that doesn't have a default header unit file extension, like `.cpp` for example, set **Configuration properties** > **C/C++** > **Advanced** > **Compile As** to **Compile as C++ Header Unit (/exportHeader)**:
> :::image type="content" source="media/change-compile-as.png" alt-text="Screenshot that shows changing Configuration properties > C/C++ > Advanced > Compile As to Compile as C++ Header Unit (/exportHeader).":::

### Change your code to import a header unit

1. In the source file for the example project, change `#include "Pythagorean.h"` to `import "Pythagorean.h";` Don't forget the trailing semicolon that's required for `import` statements. Because it's a header file in a directory local to the project, we used quotes with the `import` statement, that is: `import "file";` In your own projects, to compile a header unit from a system header, use angle brackets: `import <file>;`
1. In the source file for the example project, change `#include "Pythagorean.h"` to `import "Pythagorean.h";` Don't forget the trailing semicolon that's required for `import` statements. Because it's a header file in a directory local to the project, we used quotes with the `import` statement: `import "file";`. In your own projects, to compile a header unit from a system header, use angle brackets: `import <file>;`

1. Build the solution by selecting **Build** > **Build Solution** on the main menu. Run it to see that it produces the expected output: `Pythagorean triple a:2 b:3 c:13`

In your own projects, repeat this process to compile the header files you want to import as header units.

If you want to convert only a few header files to header units, this approach is good. But if you have many header files that you want to compile, and the convenience of having the build system automatically handle it outweighs the potential impact on build performance, see the following section.
If you want to convert only a few header files to header units, this approach is good. But if you have many header files that you want to compile, and the potential loss of build performance is outweighed by the convenience of having the build system handle them automatically, see the following section.

If you're interested in specifically importing STL library headers as header units, see [Walkthrough: Import STL libraries as header units](walkthrough-import-stl-header-units.md#approach1).

## <a name="approach2"></a>Approach 2: Automatically scan for and build header units

Due to scanning all of your source files to find and build header units, this approach is best suited for smaller projects because it doesn't guarantee optimal build throughput.
Because it takes time to first scan all of your source files for header units, and then build them, this approach is best suited for smaller projects. It doesn't guarantee optimal build throughput.

This approach combines two Visual Studio project settings:

- **Scan Sources for Module Dependencies** causes the build system to call the compiler to ensure that all imported modules and header units are built before compiling the files that depend on them. When combined with **Translate Includes to Imports**, header files included in your source, that are also specified in a [`header-units.json`](./reference/header-unit-json-reference.md) file in the same directory as the header file, are compiled into header units.
- **Scan Sources for Module Dependencies** causes the build system to call the compiler to ensure that all imported modules and header units are built before compiling the files that depend on them. When combined with **Translate Includes to Imports**, any header files included in your source that are also specified in a [`header-units.json`](./reference/header-unit-json-reference.md) file in the same directory as the header file, are compiled into header units.
- **Translate Includes to Imports** treats a header file as an `import` if the `#include` refers to a header file that can be compiled as a header unit (as specified in a `header-units.json` file), and a compiled header unit is available for the header file. Otherwise, the header file is treated as a normal `#include`. The [`header-units.json`](./reference/header-unit-json-reference.md) file is used to automatically build header units for each `#include` without symbol duplication.

You can turn on these settings in the properties for your project. To do so, right-click the project in the **Solution Explorer** and choose **Properties**. Then choose **Configuration Properties** > **C/C++** > **General**.
Expand All @@ -132,7 +132,7 @@ You can turn on these settings in the properties for your project. To do so, rig

These settings work together to automatically build and import header units under these conditions:

- **Scan Sources for Module Dependencies** scans your sources for files, and their dependencies, that can be treated as header units. Files that have the extension `.ixx`, and those which have their **File properties** > **C/C++** > **Compile As** property set to **Compile as C++ Header Unit (/export)**, are always scanned regardless of this setting. The compiler also looks for `import` statements to identify header unit dependencies. If `/translateInclude` is specified, the compiler also scans for `#include` directives that are also specified in a `header-units.json` file to treat as header units. A dependency graph is built of all the modules and header units in your project.
- **Scan Sources for Module Dependencies** scans your sources for the files and their dependencies that can be treated as header units. Files that have the extension `.ixx`, and files that have their **File properties** > **C/C++** > **Compile As** property set to **Compile as C++ Header Unit (/export)**, are always scanned regardless of this setting. The compiler also looks for `import` statements to identify header unit dependencies. If `/translateInclude` is specified, the compiler also scans for `#include` directives that are also specified in a `header-units.json` file to treat as header units. A dependency graph is built of all the modules and header units in your project.
- **Translate Includes to Imports** When the compiler encounters an `#include` statement, and a matching header unit file (`.ifc`) exists for the specified header file, the compiler imports the header unit instead of treating the header file as an `#include`. When combined with **Scan for dependencies**, the compiler finds all of the header files that can be compiled into header units. An allowlist is consulted by the compiler to decide which header files can compile into header units. This list is stored in a [`header-units.json`](./reference/header-unit-json-reference.md) file that must be in the same directory as the included file. You can see an example of a `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` is used by the compiler to determine whether a Standard Template Library header can be compiled into a header unit. This functionality exists to serve as a bridge with legacy code to get some benefits of header units.

The `header-units.json` file serves two purposes. In addition to specifying which header files can be compiled into header units, it minimizes duplicated symbols to increase build throughput. For more information about symbol duplication, see [C++ header-units.json reference](reference/header-unit-json-reference.md#preventing-duplicated-symbols).
Expand All @@ -145,9 +145,9 @@ For an example of how this technique is used to import STL header files as heade

## Preprocessor implications

The standard C99/C++11 conforming preprocessor is required to create and use header units. The compiler enables the new C99/C++11 conforming preprocessor when compiling header units by implicitly adding [`/Zc:preprocessor`](/cpp/build/reference/zc-preprocessor) to the command line whenever any form of `/exportHeader` is used. Attempting to turn it off will result in a compilation error.
The standard C99/C++11 conforming preprocessor is required to create and use header units. The compiler enables the new C99/C++11 conforming preprocessor when compiling header units by implicitly adding [`/Zc:preprocessor`](./reference/zc-preprocessor.md) to the command line whenever any form of `/exportHeader` is used. Attempting to turn it off will result in a compilation error.

Enabling the new preprocessor affects the processing of variadic macros. For more information, see the [Variadic macros](/cpp/preprocessor/variadic-macros#remarks) remarks section.
Enabling the new preprocessor affects the processing of variadic macros. For more information, see the [Variadic macros](../preprocessor/variadic-macros.md#remarks) remarks section.

## See also

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
description: "Learn more about: vsnprintf_s, _vsnprintf_s, _vsnprintf_s_l, _vsnwprintf_s, _vsnwprintf_s_l"
title: "vsnprintf_s, _vsnprintf_s, _vsnprintf_s_l, _vsnwprintf_s, _vsnwprintf_s_l"
ms.date: 09/09/2022
ms.date: 09/29/2022
api_name: ["_vsnwprintf_s", "_vsnwprintf_s_l", "_vsnprintf_s", "vsnprintf_s", "_vsnprintf_s_l"]
api_location: ["msvcrt.dll", "msvcr80.dll", "msvcr90.dll", "msvcr100.dll", "msvcr100_clr0400.dll", "msvcr110.dll", "msvcr110_clr0400.dll", "msvcr120.dll", "msvcr120_clr0400.dll", "ntdll.dll", "ucrtbase.dll", "ntoskrnl.exe"]
api_type: ["DLLExport"]
Expand Down Expand Up @@ -135,8 +135,8 @@ The versions of these functions with the **`_l`** suffix are identical except th

In C++, using these functions is simplified by template overloads; the overloads can infer buffer length automatically (eliminating the need to specify a size argument) and they can automatically replace older, non-secure functions with their newer, secure counterparts. For more information, see [Secure Template Overloads](../../c-runtime-library/secure-template-overloads.md).

> [!Tip]
> If you get an undefined external `_vsnprintf_s` error and are using the Universal C Runtime, add `legacy_stdio_definitions.lib` to the set of libraries to link with. The Universal C Runtime doesn't export this function directly and is instead defined inline in `<stdio.h>`. For more information, see [Overview of potential upgrade issues](/cpp/porting/overview-of-potential-upgrade-issues-visual-cpp.md#libraries) and [Visual Studio 2015 Conformance Changes](/cpp/porting/visual-cpp-change-history-2003-2015.md#stdio_and_conio).
> [!TIP]
> If you get an undefined external `_vsnprintf_s` error and are using the Universal C Runtime, add `legacy_stdio_definitions.lib` to the set of libraries to link. The Universal C Runtime doesn't export this function directly and is instead defined inline in `<stdio.h>`. For more information, see [Overview of potential upgrade issues](../../porting/overview-of-potential-upgrade-issues-visual-cpp.md#libraries) and [Visual Studio 2015 Conformance Changes](../../porting/visual-cpp-change-history-2003-2015.md#stdio_and_conio).

### Generic-Text Routine Mappings

Expand Down
Loading