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.
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); }
Modernes C++ Mentoring
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++
- cl.exe
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
- Creates a precompiled module math.pcm out of the module declaration math.cppm
- Creates the non-module translation unit math.o.
- 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
- Creates a precompiled module math1.pcm out of the module declaration math1.cppm
- Compiles the precompiled module math1.pcm: math1.pcm.o. Compile the source file math1.cpp: math1.o. cl.exe does this in one step.
- Compiles the main program: main1.o or main1.obj.
- 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, 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 |
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
Contact Me
- Mobil: +49 176 5506 5086
- Mail: schulung@ModernesCpp.de
- German Seminar Page: www.ModernesCpp.de
- Mentoring Page: www.ModernesCpp.org
Modernes C++ Mentoring,
Leave a Reply
Want to join the discussion?Feel free to contribute!