graphic 3578346 1280

Modules

Modules are one of the five prominent features of C++20. Modules will overcome the restrictions of header files. They promise a lot. For example, the separation of header and source files becomes as obsolete as the preprocessor. Ultimately, we will also have faster build times and an easier way to build packages.

 

 graphic 3578346 1280

Explaining modules from the user’s perspective is quite easy, but this will not hold for the implementer’s perspective. My plan for this post is to start with a simple example of modules and add more features as we go.

A First Example

First of all, here is my first math module.

// math.cppm

export module math;

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

 

The expression export module math is the module declaration. By putting export before the function adds, add is exported and can, therefore, be used by a consumer of my module. 

 

// main.cpp

import math;

int main(){
   
   add(2000, 20);
   
}

 

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

Be part of my mentoring programs:

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (starts March 2024)
  • Do you want to stay informed: Subscribe.

     

    import math imports the module math and makes the exported names in main.cpp visible. This was the easy part. The challenge started when I compiled the program.

    Module Declaration Files

    But first, did you notice the strange name of the module: math.cppm.

    • The extension cppm stands presumably for cpp module declaration and is the suggested extension for Clang.
    • cl.exe uses the extension ixx. The i should stand in this case for the interface.
    • I don’t know of a GCC extension.

    Compile the Module math

    To compile the module, you must use a very current clang or cl.exe compiler. It is also possible to use GCC to compile the examples of this post, but I will go into this post with clang and cl.exe on Windows. Here are more details about my compilers:

    • clang++

     clang

     

    • cl.exe

    clExe

     

    Here is the point where the fun started: figuring out the command line for clang++ and cl.exe.

     

    clang++ -std=c++2a -fmodules-ts --precompile math.cppm -o math.pcm                   // 1
    clang++ -std=c++2a -fmodules-ts -c math.pcm -o math.o                                // 2
    clang++ -std=c++2a -fmodules-ts -fprebuilt-module-path=. math.o main.cpp -o math     // 3
    
    
    cl.exe /std:c++latest /experimental:module /TP /EHsc /MD /c math.cppm /module:interface /Fo: math.obj /module:output math.pcm // 1
    cl.exe /std:c++latest /experimental:module /TP /EHsc /MD /c main.cpp /module:reference math.pcm /Fo: main.obj                 // 2
    cl.exe math.obj main.obj                                                                                                      // 3
    

     

    1. Creates a precompiled module math.pcm out of the module declaration math.cppm
    2. Creates the non-module translation unit math.o
    3. Creates the executable math or math.exe. For clang++, I have to specify the module path.

    For obvious reasons, I will not show you the output of the program execution. I will do it if I have something to show.

    From the implementor’s perspective, we can split the module definition into a module interface unit and a module implementation unit. Before I come to these units, let me take a step back and answer the question:

    What are the Advantages of Modules?

    • Compile-time speedup: A module is only imported once and should be literally for free. Compare this with M headers which are included in N translation units. The combinatorial explosion means that the header has to be parsed M*N times.
    • Isolation from the preprocessor macros: If there is one consensus in the C++ community, it’s the following: we should eliminate the preprocessor macros. Why? Using a macro is just text substitution excluding any C++ semantic. Of course, this has many negative consequences: For example, it may depend on in which sequence you include macros, or macros can clash with already defined macros or names in your application. In contrast, it makes no difference in which order you import modules.
    • Express the logical structure of your code: Modules allow you to express which names should be exported or not explicitly. You can bundle a few modules into a more significant module and provide them to your customer as a logical package.
    • No need for header files: There is no need to separate your files into an interface and an implementation part. This means modules have just half the number of source files.
    • Get rid of ugly workarounds: We are used to ugly workarounds such as “put an include guard around your header”, or “write macros with LONG_UPPERCASE_NAMES”. On the contrary, identical names in modules will not clash.

    In my first module math, I declared and defined the module in one file math.cppm. Let me talk about the new units.

    Module Interface Unit, and Module Implementation Unit

     First, the new module math1 consists of a module interface unit and a module implementation unit.

    Module Interface Unit

    // math1.cppm
    
    export module math1;
    
    export int add(int fir, int sec);
    

     

    • The module interface unit contains the exporting module declaration: export module math1.
    • Names such as add can only be exported in the module interface unit.
    • Names which are not exported are not visible outside the module. I will come to this point in my next post.
    • A module can have only one module interface unit.

    Module Implementation Unit

    // math1.cpp
    
    module math1;
    
    int add(int fir, int sec){
        return fir + sec;
    }
    

     

    • The module implementation unit contains non-exporting module declarations: module math1;
    • A module can have more than one module implementation unit.

    Main Program

     

    // main1.cpp
    
    import math1;
    
    int main(){
       
       add(2000, 20);
       
    }
    

     

    • From the user’s perspective, just the module name changed from math to math1.

    Compiling the modularised module is a little bit more involved.

    Compile the Module math1

     

    clang++ -std=c++2a -fmodules-ts --precompile math1.cppm -o math1.pcm               // 1
    clang++ -std=c++2a -fmodules-ts  -c math1.pcm -o math1.pcm.o                       // 2
    clang++ -std=c++2a -fmodules-ts -c math1.cpp -fmodule-file=math1.pcm -o math1.o    // 2
    clang++ -std=c++2a -fmodules-ts -c main1.cpp -fmodule-file=math1.pcm -o main1.o    // 3
    clang++  math1.pcm main1.o math1.o -o math                                         // 4
    
    cl.exe /std:c++latest /experimental:module /TP /EHsc /MD /c math1.cppm /module:interface /Fo: math1.pcm.obj /module:output math1.pcm  // 1
    cl.exe /std:c++latest /experimental:module /TP /EHsc /MD /c math1.cpp /module:reference math1.pcm /Fo: math1.obj                      // 2
    cl.exe /std:c++latest /experimental:module /TP /EHsc /MD /c main1.cpp /module:reference math1.pcm /Fo: main1.obj                      // 3
    cl.exe math1.obj main1.obj math1.pcm.obj                                                                                              // 4
    

     

    1. Creates a precompiled module math1.pcm out of the module declaration math1.cppm
    2. Compiles the precompiled module math1.pcm: math1.pcm.o. Compile the source file math1.cpp: math1.o. cl.exe does this in one step.
    3. Compiles the main program: main1.o or main1.obj.
    4. Creates the executable math1 or math1.exe.

    What’s next?

    As promised, this was only an introduction to modules. In my next post, I will dive more into the details. In particular, I want to show the program’s output and have, therefore, include standard headers such as <iostream> or import modules such as std.core.

     

    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, Kris Kafka, 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, moon, Philipp Lenk, Hobsbawm, and Charles-Jianye Chen.

    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

    Seminars

    I’m happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

    Standard Seminars (English/German)

    Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

    • C++ – The Core Language
    • C++ – The Standard Library
    • C++ – Compact
    • C++11 and C++14
    • Concurrency with Modern C++
    • Design Pattern and Architectural Pattern with C++
    • Embedded Programming with Modern C++
    • Generic Programming (Templates) with C++
    • Clean Code with Modern C++
    • C++20

    Online Seminars (German)

    Contact Me

    Modernes C++ Mentoring,

     

     

    0 replies

    Leave a Reply

    Want to join the discussion?
    Feel free to contribute!

    Leave a Reply

    Your email address will not be published. Required fields are marked *