The gcc used for this article is 16.0.0, built from gcc git source code. (Apr 24, 2025).
Alias gpp:
alias gpp="path/to/the/g++ -fmodules-ts -std=c++26"
import declaration: import module units, module partitions, header units.
hello.cpp :
import std; int main() { std::cout << "Hello, c++ modules!" << std::endl; }
Compile at the first time:
(a little slow)
> gpp -fsearch-include-path bits/std.cc hello.cpp -o hello > ./hello Hello, c++ modules!
It will create gcm.cache/std.gcm at current working directory.
Compile not at the first time:
(very fast)
After the cache is generated at the first time, the compiling is super fast.
> gpp hello.cpp -o hello > ./hello Hello, c++ modules!
The cache ./gcm.cache can be removed and you repeat above steps again, it works, you can try it!
The cache ./gcm.cache/std.gcm will be reused for the rest parts of this article conveniently.
export declaration:
c++ module declaration starts with a keyword export or module.
E.X:
export module module-name;
Declares a primary module interface unit and export, its name is module-name .
export namespace.
Make a c++ module, source code: my_class.cpp
my_class.cpp :
export module my_module; import std; export namespace my_space { class my_class { public: void greeting() const { std::cout << "Cheers, c++!" << std::endl; } }; }
Use the module, source code: main.cpp
main.cpp :
import my_module; int main() { my_space::my_class my_object; my_object.greeting(); }
Compile them :
> gpp main.cpp my_class.cpp -o main > ./main Cheers, c++!
Just compile the module source c++ file to shared library.
my_cpp.cpp :
export module my_module; export import std; export namespace my_space { class my_class { private: int __x; public: my_class(int x__): __x{x__} {} public: int get() const {return __x;} }; }
main.cpp :
import my_module; int main() { my_space::my_class object{234}; std::cout << "get: " << object.get() << std::endl; }
Compile :
> gpp my_cpp.cpp -c -fPIC -shared -o libmy_cpp.so > gpp main.cpp -L./ -lmy_cpp -o main > ./main get: 234
A module partition can be imported by module units of the same named module.
In this example, :my_partition can be imported by my_module, it can not be imported by other module.
my_cpp_part.cpp :
export module my_module:my_partition; export namespace my_space { class my_class_2 { public: int get() const { return -112233; } }; }
my_cpp.cpp :
export module my_module; export import :my_partition; export namespace my_space { class my_class { public: int get() const { return 3333; } }; }
main.cpp :
import my_module; import std; int main() { my_space::my_class obj1; std::cout << "v: " << obj1.get() << std::endl; my_space::my_class_2 obj2; std::cout << "v: " << obj2.get() << std::endl; }
Compile :
(compile order is important, my_cpp.cpp depends on my_cpp_part.cpp)
> gpp my_cpp_part.cpp my_cpp.cpp -c -fPIC > gpp *.o -shared -o libmy_cpp.so > gpp main.cpp -L./ -lmy_cpp -o main
> ./main v: 3333 v: -112233
First, precompile :
> gpp -xc++-system-header boost/parser/parser.hpp > gpp -xc++-system-header iostream
Then, use :
import <boost/parser/parser.hpp>; import <iostream>; int main() { std::cout << "Hello, c++!" << std::endl; }
Compile :
> gpp program.cpp -o program
my_cpp.cpp :
export module my_module; export namespace my_space { class my_class { public: void greeting() const; void cheers() const; int get() const; virtual ~my_class(); }; }
my_cpp_src.cpp :
module my_module; import std; my_space::my_class::~my_class() { std::cout << "Bye, c++!" << std::endl; } void my_space::my_class::greeting() const { std::cout << "Greeting, c++!" << std::endl; } void my_space::my_class::cheers() const { std::cout << "Cheers, c++!" << std::endl; } int my_space::my_class::get() const { return 12345; }
main.cpp :
import my_module; import std; int main() { my_space::my_class my_object; my_object.greeting(); my_object.cheers(); std::cout << "get: " << my_object.get() << std::endl; }
Compile :
> gpp my_cpp.cpp my_cpp_src.cpp -c -fPIC > gpp my_cpp.o my_cpp_src.o -shared -o libmy_cpp.so > gpp main.cpp -L./ -lmy_cpp -o main
> ./main Greeting, c++! Cheers, c++! get: 12345 Bye, c++!
Declare Primary Module Unit
(Name is A)
export module A;
(Name is A.B)
export module A.B;
Declare Module Implementation Unit
module A;
module A.B;
constexpr and template declared api can not be splitted into two declaration and definition module files.
c++ modules gcc can be used in b2 build by flags settings trick.
First, generate gcm.cache/std.gcm cache in current working directory like talked in the beginning of this article, I am a little lazy of how to make it by a b2 jamfile trick.
The same c++ source files of previous section of this article will used for this project:
(Split Definitions for Shared Library)
The file jamroot in current working directory:
project : requirements <cxxflags>"-fmodules-ts" : default-build <cxxstd>26 ; lib my_cpp : my_cpp.cpp my_cpp_src.cpp ; exe main : main.cpp : <library>my_cpp ;
Build:
> b2 -q -j7
Trick: run above command twice, the first run will generate errors, the second run will be OK.
Make sure the toolset used for this project is gcc. Visual c++ and clang++ has different compiler flags.
Run program:
> ls ./bin/gcc-latest/debug/cxxstd-26-iso/ libmy_cpp.so main main.o my_cpp.o my_cpp_src.o > > > > ./bin/gcc-latest/debug/cxxstd-26-iso/main Greeting, c++! Cheers, c++! get: 12345 Bye, c++!
...
...
...
...
...
A module unit is a translation unit which has a module declaration.
A module partition unit is a module unit which is included by a module unit and starts with a colon : , and is placed after the module name.
For example,
export module A:B;
export module A;
Module name is the name of the module unit, which consists of one or more identifiers separated by dots. Note that module partition unit is also module unit.
For example,
// Module name is A export module A;
// Module name is A.B.C export module A.B.C;
Written on Apr 24, 2025
c++ std::exception:
std::cout.write(err.data(), err.size());
std::cout << std::endl;
caught:
=================================== # The c++ programming language. # # # # Join c++ # # Deck # ===================================