C++20: Modules

Modules is 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. In the end, we will also have faster build times and an easier way to build packages.

 

 graphic 3578346 1280

Explaining modules for the users perspective is quite easy, but this will not hold for the implementers perspective. My plan for this post is to start with a simple example to modules and add more features to it as we go.

A First Example

First of all, here is my first module math.

// 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 add, add is exported and can, therefore, be used by a consumer of my module. 

 

// main.cpp

import math;

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

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 noticed 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 interface.
  • I don't know of a GCC extension.

Compile the Module math

To compile the module you have to 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 in this post with clang and cl.exe on Windows. Here are more details to my compilers:

  • clang++

 clang

 

  • cl.exe

clExe

 

Here is precisely the point where the fun started: to figure 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 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 one: we should get rid of 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 bigger 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 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". To 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 of all, 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 users 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 dive more into the details. In particular, I want to show the output of the program and have, therefore, to include standard headers such as <iostream> or import modules such as std.core.

Thanks a lot to my Patreon Supporters: Paul Baxter,  Meeting C++, Matt Braun, Avi Lachmish, Roman Postanciuc, Venkata Ramesh Gudpati, Tobias Zindl, Dilettant, Marko, Ramesh Jangama, G Prvulovic, Reiner Eiteljörge, Benjamin Huth, Reinhold Dröge, Timo, Abernitzke, Richard Ohnemus , Frank Grimm, and Hasan Men.

Thanks in particular to:  TakeUpCode 450 60     crp4

 

Get your e-book at Leanpub:

The C++ Standard Library

 

Concurrency With Modern C++

 

Get Both as one Bundle

cover   ConcurrencyCoverFrame   bundle
With C++11, C++14, and C++17 we got a lot of new C++ libraries. In addition, the existing ones are greatly improved. The key idea of my book is to give you the necessary information to the current C++ libraries in about 200 pages.  

C++11 is the first C++ standard that deals with concurrency. The story goes on with C++17 and will continue with C++20.

I'll give you a detailed insight in the current and the upcoming concurrency in C++. This insight includes the theory and a lot of practice with more the 100 source files.

 

Get my books "The C++ Standard Library" (including C++17) and "Concurrency with Modern C++" in a bundle.

In sum, you get more than 600 pages full of modern C++ and more than 100 source files presenting concurrency in practice.

 

Get your interactive course

 

Modern C++ Concurrency in Practice

C++ Standard Library including C++14 & C++17

educative CLibrary

Based on my book "Concurrency with Modern C++" educative.io created an interactive course.

What's Inside?

  • 140 lessons
  • 110 code playgrounds => Runs in the browser
  • 78 code snippets
  • 55 illustrations

Based on my book "The C++ Standard Library" educative.io created an interactive course.

What's Inside?

  • 149 lessons
  • 111 code playgrounds => Runs in the browser
  • 164 code snippets
  • 25 illustrations
 

Add comment


Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code

Visitors

Today 3920

All 2415465

Currently are 189 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments