A Module Interface Unit (Abyssinian)

This module is as tiny as you can get. It has a Module Interface Unit (MIU) that combines the interface and implementation in one file. The other translation unit is main.cpp. It illustrates the usage of some module-specific statements and demonstrates a module’s distinct sections.

Module Interface Unit: Abyssinian.cppm

Below is the Abyssinian module’s MIU example for this chapter. It has a .cppm extension to distinguish it from regular source code, which is a requirement by Clang but not by GCC. Microsoft uses its own specific extensions.

An icon indicating this blurb contains information

Clang also accepts the extensions .ccm, .cxxm, or .c++m. It can also process any extension when using the -x c++-module option.

 1 module;
 2 
 3 #include <print>
 4 
 5 export module Abyssinian;
 6 
 7 using std::println, std::print;
 8 
 9 export auto miyāwi() -> void {
10    println("Ye'abisinya dmmmet miyāwi yilal:"); // Amharic transcription
11 }

Module statement

The first line is the module; (line 1) statement to indicate this is a module. Module Interface Unit (MIU) and Module Implementation Units are all C++ translation units. The keyword module distinguishes them from non-module code. The module; or similar statement must be the first code token in the file. Only comments may appear before the module statement.

The next module-specific statement is the export module statement (line 5), which declares the name of the module: Abyssinian.

The next export (line 9) places the function ‘miyāwi()’ into the module scope so it may be visible in other scopes. Without the export, miyāwi would be limited to module scope.

Global Module Fragment (GMF)

Between the module; statement (line 1) and export module declaration (line 5) is the global module fragment (lines 2-4). Code in the GMF is not part of the module and follows standard C++ scoping rules.

Officially, only preprocessing directives may appear in the global module fragment. This position roughly means only statements starting with a #, per cppreference. Note that anything in a header file may be included here.

Unfortunately, MSVC, GCC, and Clang all compile the following lines in the global fragment without error, although MSVC and GCC emit a warning.

 1 int x{};
 2 
 3 auto func() -> int {
 4    return x;
 5 }
 6 
 7 struct F {
 8    auto operator()() const -> int{return func();}
 9 };
10 using std::println, std::print;

All of these statements would be fine if placed in a header for inclusion.

Module Purview

The export module (line 5) declares the module and begins its definition. This statement begins the Module Purview area. Nothing in this area is global unless qualified with export; otherwise, everything is private to the module.

Module-specific statements, import and export, may be used here.

User Code: main.cpp

The code using the module is straightforward.

1 import Abyssinian;
2 
3 auto main() -> int {
4    miyāwi();
5 
6    return 0;
7 }

The main.cpp is simple. It imports the Abyssinian module (line 1), which brings the function miyāwi() into the scope and calls it (line 4). Importing the module makes miyāwi() available without qualification since modules do not introduce a separate namespace.