C++ 20 introduces modules, a feature that eliminates the problems introduced by traditional header files. The syntax of using a module: import
, is quite similar to modern scripting languages like Python and JavaScript. I’m very curious about how import
works under C++ and what changes does this new feature bring to modern C++. In this article, I’ll try a simple example with modules.
Setup
The modules feature is quite new, so we need the latest compilers and tools supporting C++ 20 standards.
Here I’d recommend Clang 10. Just download the pre-built binaries and make sure you could use clang++
tools. If you’re a Windows user, enabling WSL2 would help setting up the compiler tools.
$ sudo apt install build-essential libncurses5$ bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)"
Once you’ve installed Clang 10, make sure it could be found in your path: which clang++
Hello Module!
Great! Let’s now create our first module hellowolrd.cpp
:
/// helloworld.cpp
export module helloworld;
export auto hello() { return "Hello C++ 20!"; }
Then, let’s create our main.cpp
, we can simply import the helloworld
module we just created! By default, all the exported functions can be directly used once we import the module:
/// main.cpp
#include <iostream>
import helloworld;int main() {
std::cout << hello() << std::endl;
return 0;
}
Now, let’s compile it. There are two steps in compiling this program:
- Compile the module into
.pcm
, which stands for Pre-compiled Module - Compile main.cpp with the
.pcm
file
In Clang 10, we have to specify the flag -std=c++2a
with other flags. Refer to the Clang Modules page for detailed explanation.
$ clang++ -std=c++2a -c helloworld.cpp -Xclang -emit-module-interface -o helloworld.pcm$ clang++ -std=c++2a -stdlib=libc++ -fprebuilt-module-path=. main.cpp helloworld.cpp
Run the compiled program, and we shall see the “Hello C++ 20!” output
$ ./a.out
Hello C++ 20!
Import Standard Library
We notice that in the above main.cpp
, we use both #include
and import
, which is kinda ugly. Could we also import
the standard library? Yes. All we have to do is simply replace the #include
with import
. Don’t forget to add the semicolon at the end of the line.
// main.cpp
import <iostream>;
import helloworld;
To compile it, we have to add another two flags: -fimplicit-modules
and -fimplicit-module-maps
. Currently, Clang doesn’t support Semantic Import, which means you couldn’t do something like: import std.io
(but MSVC supports). So we could compile the main.cpp
like this:
$ clang++ -std=c++2a -stdlib=libc++ -fimplicit-modules -fimplicit-module-maps -fprebuilt-module-path=. main.cpp helloworld.cp
Use namespace in Module
We can further modify the above example to export functions within a namespace. Therefore, the helloworld.cpp
would be:
/// helloworld.cpp
module;
import <cstdio>;
export module helloworld;export namespace helloworld {
int global_data;void say_hello() {
std::printf("Hello Module! Data is %d\n", global_data);
}
}
Use helloworld
namespace in main.cpp
/// main.cpp
import helloworld;int main() {
helloworld::global_data = 123;
helloworld::say_hello();
}
Here, we used import <cstdio>
in our module, to successfully compile it, we need to specify -stdlib=libc++
$ clang++ -std=c++2a -stdlib=libc++ -fimplicit-modules -fimplicit-module-maps -c helloworld.cpp -Xclang -emit-module-interface -o helloworld.pcm
$ clang++ -std=c++2a -stdlib=libc++ -fimplicit-modules -fimplicit-module-maps -fprebuilt-module-path=. main.cpp helloworld.cpp$ ./a.out
Hello Module! Data is 123
Good Practice of Module
Modules the beginner’s guide — Daniela Engert — Meeting C++ 2019 is a really good tutorial talking about modules in C++ 20. The speaker gives a good practice of writing a module:
module;
#include <standard library header>
#include "library not ready for modularization"
...
export module top.middle.bottom;import modularized.standard.library.component;
import other.modularized.library;
...#include "module internal header" // beware!non-exported declarations;
...
export namespace top {
namespace middle {
namespace bottom {
exported declarations;
...
}}}
Takeaways
The import
syntax and module seems promising, but wait, do we really need to use module now in 2020?
- Module is still at very early stage for most compilers
- Different compilers have their own implementation of modules. Not all the features of modules are supported yet
Such new features in C++ 20 will become popular someday when the standards, compilers, IDEs are ready for the new changes.
I think modules are fun to play with. Even though we won’t see modules being widely used this or next years, who knows if it will replace header files in five to ten years, right?
Fun fact: I first learnt about modules back in 2017, when Bjarne Stroustrup visited our school and gave a talk about it.
References
- Modules: The Beginner’s Guide
- Hello World with C++2a modules
- Understanding C++ Modules: Part 1: Hello Modules, and Module Units
- Overview of modules in C++ | Microsoft Docs
- C++20: Module Interface Unit and Module Implementation Unit
- C++20 Modules | PureCPP
- Modules Are Not Precompiled Headers
- Modules in Clang 11