├── .gitignore ├── LICENSE ├── README.md ├── hello_world ├── commands.sh ├── hello_modular_world.cc └── hello_world.cc ├── legacy ├── commands.sh ├── header.h ├── legacy.cc └── main.cc ├── partitions ├── binary.cc ├── commands.sh ├── main.cc ├── main_base.cc └── main_internal.cc └── writing_modules ├── advanced_mathematics.cc ├── bread.cc ├── butter.cc ├── commands.sh ├── jam.cc ├── main.cc └── spreadables.cc /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 RNDr. Simon Toth 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C++ 20 Modules - Complete Guide 2 | 3 | This is a repository containing example code for the C++20 Modules article and 4 | videos. 5 | 6 | The article: https://itnext.io/c-20-modules-complete-guide-ae741ddbae3d 7 | 8 | The video: https://www.youtube.com/watch?v=WRCwciJ5MTE 9 | 10 | To test out the code, you can use docker images I created based on the conan 11 | docker images. 12 | 13 | Download the repository: https://github.com/HappyCerberus/conan-docker-tools 14 | 15 | For Clang trunk: 16 | 17 | ``` 18 | > cd modern 19 | > docker-compose run clang-14 20 | ``` 21 | 22 | For GCC trunk: 23 | 24 | ``` 25 | > cd modern 26 | > docker-compose run gcc-12 27 | ``` 28 | -------------------------------------------------------------------------------- /hello_world/commands.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Pre-process non-modular hello_world.cc with clang++ 4 | echo "Size of pre-processed non-modular hello world in bytes:" 5 | clang++ -std=c++20 -stdlib=libc++ -E hello_world.cc | wc -c 6 | echo "" 7 | 8 | # Pre-process modular hello_modular_world.cc with clang++ 9 | echo "Size of pre-processed modular hello world in bytes:" 10 | clang++ -std=c++20 -stdlib=libc++ -fmodules -fbuiltin-module-map -E hello_modular_world.cc | wc -c 11 | echo "" 12 | 13 | # Non-modular compile time 14 | echo "Compiling non-modular hello world:" 15 | time clang++ -std=c++20 -stdlib=libc++ hello_world.cc -o hello_world 16 | ./hello_world 17 | echo "" 18 | 19 | echo "Compiling modular hello world:" 20 | time clang++ -std=c++20 -stdlib=libc++ -fmodules -fbuiltin-module-map hello_modular_world.cc -o hello_modular_world 21 | ./hello_modular_world 22 | echo "" 23 | 24 | echo "Compiling modular hello world using GCC" 25 | g++ -std=c++20 -fmodules-ts -xc++-system-header iostream 26 | g++ -std=c++20 -fmodules-ts hello_modular_world.cc -o gcc_world 27 | ./gcc_world 28 | echo "" 29 | 30 | -------------------------------------------------------------------------------- /hello_world/hello_modular_world.cc: -------------------------------------------------------------------------------- 1 | import ; 2 | 3 | int main() { 4 | std::cout << "Hello Modular World!\n"; 5 | } 6 | -------------------------------------------------------------------------------- /hello_world/hello_world.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << "Hello World!\n"; 5 | } 6 | -------------------------------------------------------------------------------- /legacy/commands.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | g++ -std=c++20 -fmodules-ts -xc++-system-header iostream 4 | g++ -std=c++20 -fmodules-ts -c legacy.cc 5 | g++ -std=c++20 -fmodules-ts -c main.cc 6 | g++ main.o legacy.o -o main 7 | ./main 8 | -------------------------------------------------------------------------------- /legacy/header.h: -------------------------------------------------------------------------------- 1 | #ifndef HEADER_H_ 2 | #define HEADER_H_ 3 | 4 | inline auto function() { 5 | return RESULT; 6 | } 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /legacy/legacy.cc: -------------------------------------------------------------------------------- 1 | module; 2 | 3 | #define RESULT 42 4 | #include "header.h" 5 | 6 | export module testmodule; 7 | 8 | export auto testfunction() { 9 | return function(); 10 | } 11 | -------------------------------------------------------------------------------- /legacy/main.cc: -------------------------------------------------------------------------------- 1 | import ; 2 | import testmodule; 3 | 4 | int main() { 5 | std::cout << "Function returns " << testfunction() << "\n"; 6 | } 7 | -------------------------------------------------------------------------------- /partitions/binary.cc: -------------------------------------------------------------------------------- 1 | import main; 2 | 3 | int main() { 4 | function(); // from main module directly 5 | visible(); // from main:base 6 | } 7 | -------------------------------------------------------------------------------- /partitions/commands.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CXXFLAGS="-std=c++20 -fmodules-ts" 4 | 5 | g++ $CXXFLAGS -xc++ -c main_internal.cc 6 | g++ $CXXFLAGS -xc++ -c main_base.cc 7 | g++ $CXXFLAGS -xc++ -c main.cc 8 | g++ $CXXFLAGS -xc++ -c binary.cc 9 | g++ binary.o main.o main_base.o main_internal.o -o binary 10 | -------------------------------------------------------------------------------- /partitions/main.cc: -------------------------------------------------------------------------------- 1 | module; 2 | 3 | #include 4 | 5 | export module main; 6 | 7 | // Import partition internal, cannot be re-exported 8 | import :internal; 9 | 10 | // Import partition base and re-export its exported symbols 11 | export import :base; 12 | 13 | export void function() { 14 | internal_test_symbol(); 15 | visible(); 16 | internal_base(); 17 | 18 | if (identity(3) != 3) abort(); 19 | } 20 | -------------------------------------------------------------------------------- /partitions/main_base.cc: -------------------------------------------------------------------------------- 1 | export module main:base; 2 | 3 | export void visible() {} // will be visible to users of main 4 | void internal_base() {} // will be visible to main module only 5 | -------------------------------------------------------------------------------- /partitions/main_internal.cc: -------------------------------------------------------------------------------- 1 | module main:internal; 2 | 3 | void internal_test_symbol() {} // will be visible in main module 4 | 5 | // template inside of non-interface unit works just fine 6 | template 7 | T identity(T x) { return x; } 8 | -------------------------------------------------------------------------------- /writing_modules/advanced_mathematics.cc: -------------------------------------------------------------------------------- 1 | export module AdvancedMathematics; 2 | 3 | export auto plus(auto x, auto y) -> decltype(x+y) { 4 | return x + y; 5 | } 6 | 7 | export namespace AdvancedMathematics { 8 | auto minus(auto x, auto y) -> decltype(x-y) { 9 | return x - y; 10 | } 11 | } 12 | 13 | void this_function_will_not_be_exported() {} 14 | -------------------------------------------------------------------------------- /writing_modules/bread.cc: -------------------------------------------------------------------------------- 1 | import ; 2 | 3 | import Spreadables; 4 | 5 | int main() { 6 | 7 | std::cout << "Taking some bread.\n"; 8 | std::cout << butter() << "\n"; 9 | std::cout << jam() << "\n"; 10 | } 11 | -------------------------------------------------------------------------------- /writing_modules/butter.cc: -------------------------------------------------------------------------------- 1 | module Spreadables; 2 | 3 | import ; 4 | 5 | std::string butter() { 6 | return "Spreading some butter."; 7 | } 8 | -------------------------------------------------------------------------------- /writing_modules/commands.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #!/bin/bash 3 | 4 | echo "Compiling AdvancedMathematics module with GCC:" 5 | g++ -std=c++20 -fmodules-ts -xc++-system-header iostream 6 | g++ -std=c++20 -fmodules-ts -c advanced_mathematics.cc 7 | g++ -std=c++20 -fmodules-ts -c main.cc 8 | g++ -std=c++20 main.o advanced_mathematics.o -o main 9 | ./main 10 | 11 | 12 | echo "Compiling Bread example with GCC:" 13 | g++ -std=c++20 -fmodules-ts -xc++-system-header iostream 14 | g++ -std=c++20 -fmodules-ts -xc++-system-header string 15 | g++ -std=c++20 -fmodules-ts -c spreadables.cc 16 | g++ -std=c++20 -fmodules-ts -c jam.cc 17 | g++ -std=c++20 -fmodules-ts -c butter.cc 18 | g++ -std=c++20 -fmodules-ts -c bread.cc 19 | g++ -std=c++20 bread.o spreadables.o jam.o butter.o -o bread 20 | ./bread 21 | 22 | 23 | 24 | echo "Compiling AdvancedMathematics module with Clang:" 25 | clang++ -std=c++20 -stdlib=libc++ -fmodules -fmodules-ts -fbuiltin-module-map -Xclang -emit-module-interface -c advanced_mathematics.cc -o AdvancedMathematics.pcm 26 | clang++ -std=c++20 -stdlib=libc++ -fmodules -fbuiltin-module-map -c advanced_mathematics.cc 27 | clang++ -std=c++20 -stdlib=libc++ -fmodules -fbuiltin-module-map -fprebuilt-module-path=. -c main.cc 28 | clang++ -std=c++20 -stdlib=libc++ main.o advanced_mathematics.o -o main 29 | ./main 30 | 31 | echo "Compiling Bread example with Clang:" 32 | clang++ -std=c++20 -stdlib=libc++ -fmodules -fmodules-ts -fbuiltin-module-map -Xclang -emit-module-interface -c spreadables.cc -o Spreadables.pcm 33 | clang++ -std=c++20 -stdlib=libc++ -fmodules -fbuiltin-module-map -c spreadables.cc 34 | clang++ -std=c++20 -stdlib=libc++ -fmodules -fbuiltin-module-map -fmodule-file=Spreadables.pcm -c butter.cc 35 | clang++ -std=c++20 -stdlib=libc++ -fmodules -fbuiltin-module-map -fmodule-file=Spreadables.pcm -c jam.cc 36 | clang++ -std=c++20 -stdlib=libc++ -fmodules -fbuiltin-module-map -fprebuilt-module-path=. -c bread.cc 37 | clang++ -std=c++20 -stdlib=libc++ bread.o spreadables.o butter.o jam.o -o bread 38 | ./bread 39 | -------------------------------------------------------------------------------- /writing_modules/jam.cc: -------------------------------------------------------------------------------- 1 | module Spreadables; 2 | 3 | import ; 4 | 5 | std::string jam() { 6 | return "Spreading some jam."; 7 | } 8 | -------------------------------------------------------------------------------- /writing_modules/main.cc: -------------------------------------------------------------------------------- 1 | import ; 2 | import AdvancedMathematics; 3 | 4 | int main() { 5 | 6 | std::cout << "1+2 = " << plus(1,2) << "\n"; 7 | std::cout << "3-2 = " << AdvancedMathematics::minus(3,2) << "\n"; 8 | } 9 | -------------------------------------------------------------------------------- /writing_modules/spreadables.cc: -------------------------------------------------------------------------------- 1 | export module Spreadables; 2 | 3 | import ; 4 | 5 | export { 6 | std::string butter(); 7 | std::string jam(); 8 | } 9 | --------------------------------------------------------------------------------