Understanding the C++ Global Module Fragment
The global module fragment in C++20 is a dedicated section at the beginning of a module unit designed to bridge the gap between traditional preprocessor-based header files and modern module systems. This article explains what the global module fragment is, its specific syntax, and the exact scenarios where authoring it is required to prevent macro leakage, avoid One Definition Rule (ODR) violations, and maintain compatibility with legacy libraries.
What Is the Global Module Fragment?
The global module fragment (GMF) is an optional prologue placed at
the very start of a module file. It begins with the bare keyword
sequence module; (with no module name) and ends at the
primary module declaration (e.g., export module my_module;
or module my_module;).
Declarations introduced within this region do not belong to the named module being authored; instead, they reside in the global module. Code inside the GMF is compiled in the traditional global scope, preserving backward compatibility while isolating preprocessor behavior.
module; // Begins the global module fragment
#include <cmath>
#include <legacy_c_header.h>
#define BUFFER_SIZE 1024
export module math_utils; // Ends the global module fragment
export namespace math_utils {
double calculate(double input) {
return std::sqrt(input) * BUFFER_SIZE;
}
}Restrictions of the Global Module Fragment
The GMF is strictly reserved for preprocessor directives. Standard C++ enforces the following rules inside this block:
- Directive-Only Content: Only preprocessor
directives—such as
#include,#define,#undef,#ifdef, and#pragma—are permitted. You cannot write raw C++ language statements, functions, variables, or namespace declarations directly in this block outside of an included file. - Macro Isolation: Macros defined or imported within
the GMF do not leak to files that
importthe module. They are available exclusively within that single translation unit. - Discarded Entities: Any entity defined in the GMF that is not referenced by the module unit is discarded and not baked into the module's compiled interface (BMI).
When Is the Global Module Fragment Required?
When authoring C++ modules, the global module fragment is required in the following scenarios:
1. Including Traditional Headers That Rely on Preprocessor Macros
Modules do not export preprocessor macros by default. If your module
implementation depends on headers that define configuration macros,
feature flags, or function-like macros (such as standard C headers
<assert.h> or <setjmp.h>), these
files cannot simply be imported using
import <header>;. They must be included using
#include inside the GMF so the preprocessor can expand them
locally without polluting the consumers of your module.
2. Working with Legacy Libraries Without Header Unit Support
Not all third-party libraries or legacy codebases are "clean" enough
to be imported as C++20 header units (import "legacy.h";).
Headers that contain order-dependent includes, undeclared dependencies,
or non-modular macros will fail to compile as header units. Placing
these legacy files in the GMF allows them to compile as standard textual
includes.
3. Avoiding One Definition Rule (ODR) Violations
If a consumer application imports your module and also includes an old C-style header file directly, defining types from that header inside a named module would result in two distinct entities under the C++ type system, causing linker errors or ODR violations. Entities declared within the GMF remain in the global namespace, ensuring that the module and non-modular code refer to the exact same entity definitions.
4. Interfacing with Platform-Specific APIs
Platform APIs such as the Windows SDK
(<windows.h>) or POSIX headers
(<unistd.h>) rely extensively on macro configurations
and global types. These headers cannot be reliably imported as modern
module units. The GMF is necessary to wrap these platform headers,
allowing you to consume the platform APIs internally while exporting a
clean, macro-free modern C++ interface.