C++20: Module Support of the Big Three

I have written almost 100 posts about C++20 in the last four years, but I’m not done. This post continues my story about C++20.

Modules are one of the Big Four in C++20. In my C++20 classes, they are one of the main topics. Sadly, the implementation in GCC and Clang was way behind the Microsoft Compiler. Consequentially, I usually used the Microsoft Compiler in my classes, my talks, and books to present modules. I’m happy to say that the module support of GCC and Clang significantly improved. I will, therefore, present the current module implementation state (10/2023) of the Big Three GCC, Clang, and MSVC in this post.

If you are not familiar with modules in C++20, here is a simple example:

A Simple Module

This is the module math.

// math1.ixx

module;                  // (1)          

#include <numeric>
#include <vector>

export module math;      // (2) 

export int add(int fir, int sec){
    return fir + sec;
}

export int getProduct(const std::vector<int>& vec) {
    return std::accumulate(vec.begin(), vec.end(), 1, std::multiplies<int>());
}

The global module fragment starts with the keyword module (line 1) and ends with the exporting module declaration (line 3). The global module fragment is the place to use preprocessor directives such as #include so that the module can compile. Preprocessor entities used inside the global module fragment are only visible inside the module. The module math exports the two functions add and getProduct.

 The client imports the module math (line 1) and uses its functionality:

// client1.cpp

#include <iostream>
#include <vector>

import math;                        // (1)

int main() {
    
    std::cout << '\n';   
   
    std::cout << "add(2000, 20): " << add(2000, 20) << '\n';
    
    std::vector<int> myVec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    
    std::cout << "getProduct(myVec): " << getProduct(myVec) << '\n';
    
    std::cout << '\n';
   
}

Finally, this is the output of the program:

Of course, there is a lot more to modules you should know. I suggest that you read the following posts:

  1. The Advantages of Modules
  2. A Simple math Modul
  3. Module Interface Unit and Module Implementation Unit
  4. Structure Modules
  5. Open Questions to Modules
  6. Private Module Fragment and Header Units

I started with a simple module, and I will make it even more simple when I discuss the module implementation state of GCC, Clang, and MSVC.

Implementation State

math.ixx defines the module math, I will use it in the following comparison.

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (open)
  • "Generic Programming (Templates) with C++": October 2024
  • "Embedded Programming with Modern C++": October 2024
  • "Clean Code: Best Practices for Modern C++": March 2025
  • Do you want to stay informed: Subscribe.

     

    // math.ixx
    
    export module math;     // (1)
    
    export int add(int fir, int sec){
        return fir + sec;
    }
    

    Additionally, here is the client program client.cpp importing the module math.

    // client.cpp
    
    import math;       // (2)
    
    int main() {
       
       add(2000, 20);
       
    }
    

    Line (1) is the exporting module declaration, and line (2) imports the module. For obvious reasons, I will not show you the program’s output.

    First, you may wonder why I called the module declaration file math.ixx. Here is the first irritating point.

    Module Declaration File

    • The Microsoft compiler uses the extension ixx. The suffix ixx stands for a module interface source.
    • The Clang compiler uses the extension cppm. The m in the suffix probably stands for module.
    • The GCC compiler uses no special extension.

    These are only the defaults that you can change. Now, let me compile and use the module math.

    Compile and Use the Module

    First, I start with Microsofts cl.exe 19.29.30133 for x64 compiler.

    Microsoft Compiler

    These are the steps to compile and use the module with the Microsoft compiler. I only show the minimal command line. As promised, more will follow in the next post. Additionally, with an older Microsoft compiler, you must use the flag /std:c++latest instead of the flag /std:c++20.

    cl.exe /std:c++20 /c math.ixx           
    cl.exe /std:c++20 client.cpp math.obj
    
    • Line 1 creates an obj file math.obj and an IFC file math.ifc. The IFC is the module and contains the metadata description of the module interface. The binary format of the IFC is modeled after the Internal Program Representation by Gabriel Dos Reis and Bjarne Stroustrup.
    • Line 2 creates the executable client.exe. The compiler implicitly finds the compiled math.ifc from the first step.

    Now, let’s continue with the Clang compiler

    Clang Compiler

    I use the Clang 16.0.5 compiler.

    The Clang compiler expects a module with the extension cppm. Consequently, I must rename the math.ixx file to math.cppm. On the contrary, the file client.cpp is unchanged. Finally, here are the corresponding build and use steps:

    clang++ -std=c++20 -c math.cppm --precompile -o math.pcm
    clang++ -std=c++20 client.cpp -fprebuilt-module-path=. math.pcm -o client.exe
    
    • Line 1 creates the module math.pcm. The suffix pcm stands for precompiled module and is equivalent to the ifc file extension of the  Microsoft Visual Compiler. Additionally, the produced module already includes the module definition. Consequentially, the Clang compiler does not produce an object file math.o. The option --precompile is necessary for creating the precompiled module.
    • Line 2 creates the executable client.exe, which uses the module math.pcm. The Clang compiler requires that you specify the path to the module with the -fprebuilt-module-path flag. If not, the link process fails:

    Finally, let me do it with the GCC compiler.

    GCC Compiler

    I use the GCC 11.1.0 compiler.

    The GCC Compiler neither expected Window’s ixx nor Clang’s cppm suffix. Consequently, I rename the math.ixx file into a cpp file: math.cxx. The client.cpp is identical to the one I used with the Microsoft and the Clang compiler.

    g++ -c -std=c++20 -fmodules-ts math.cxx
    g++ -std=c++20 -fmodules-ts client.cpp math.o -o client
    
    • Line 1 creates the module math.gcm and the object file math.o. I have to specify -fmodules-ts. The extension –fmodules-ts irritates me because ts usually stands for technical specification. The module math.gcm is in the subdirectory gcm.cache. math.gcm is the compiled module interface. Presumably, gcm stands for GCC compiled module.
    • Line 2 creates the executable client. It uses the module math.gcm implicitly.

    What’s Next?

    This post gave you the first steps of how to build a module with the Big Three. In my next post, I will drill deeper.

    Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery,and Matt Godbolt.

    Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.

    My special thanks to Embarcadero
    My special thanks to PVS-Studio
    My special thanks to Tipi.build 
    My special thanks to Take Up Code
    My special thanks to SHAVEDYAKS

    Modernes C++ GmbH

    Modernes C++ Mentoring (English)

    Do you want to stay informed about my mentoring programs? Subscribe Here

    Rainer Grimm
    Yalovastraße 20
    72108 Rottenburg

    Mobil: +49 176 5506 5086
    Mail: schulung@ModernesCpp.de
    Mentoring: www.ModernesCpp.org

    Modernes C++ Mentoring,