- Qbs Manual
- C++20 Modules
- Qbs 3.3.1

Version Header ◦ How-tos

# C++20 Modules

This tutorial implies you have some knowledge about C++20 modules. If not, see Overview of modules in C++ for introduction.

## Named Modules

Using C++20 modules with Qbs is pretty straightforward. Let's suppose you have a module file that exports a single function `printHello`:

     // hello.cppm
     module;

     #include <iostream>
     #include <string_view>

     export module hello;

     export namespace Hello {

     void printHello(std::string_view name)
     {
         std::cout << "Hello, " << name << '!' << std::endl;
     }

     } // namespace Hello

Note: Currently, Clang only recognizes `.cppm` files as modules, however, for GCC and MSVC Qbs also recognizes `.ixx` files as C++ modules. Qbs assigns the `"cppm"` file tag to these files. You can assign this tag manually to module files with different extensions.

This function is later used in the `main.cpp` file as follows:

     // main.cpp

     import hello;

     int main()
     {
         Hello::printHello("World");
     }

The project file simply lists files and sets the cpp.forceUseCxxModules property to `true`.

     // myproject.qbs
     CppApplication {
         consoleApplication: true
         files: ["hello.cppm", "main.cpp"]
         cpp.cxxLanguageVersion: "c++20"
         cpp.forceUseCxxModules: true
     }

Now, you can build the project by simply calling `qbs`, assuming that your compiler supports C++20 modules.

## Module Partitions

Module partitions are treated as regular modules and should also have the same extension or assigned the `"cppm"` tag manually. See this example on how to use both interface module and partitions.

## Modules and Libraries

Using modules in dynamic libraries requires using the same export/import macros as it was shown in the Dynamic Library section:

     // lib/hello.cppm
     module;

     #include "lib_global.h"
     #include <iostream>
     #include <string_view>

     export module hello;

     export namespace Hello {

     void MYLIB_EXPORT printHello(std::string_view name)
     {
         std::cout << "Hello, " << name << '!' << std::endl;
     }

     } // namespace Hello

As shown in that section, the library `.qbs` file should also define the `MYLIB_LIBRARY` macro in order to mark symbols as exported:

     // lib/lib.qbs
     DynamicLibrary {
         name: "mylib"
         files: ["hello.cppm", "lib_global.h"]
         version: "1.0.0"

         Depends { name: "cpp" }
         cpp.defines: "MYLIB_LIBRARY"
         cpp.cxxLanguageVersion: "c++20"
         cpp.forceUseCxxModules: true
         // ...
     }

For more details, see the complete example.

## Import std module

Starting with C++23, you can use the standard library as a module by using `import std;` or `import std.compat;`.

In order to use `import std;`, you need to define the CppStd product somewhere in your project and add a dependency on it to products that require the `std` module:

     Project {
         CppStd {}
         CppApplication {
             Depends { name: "CppStd" }
         }
     }

Here's a simple example that demonstrates the use of the standard library module:

     // main.cpp

     import std;

     int main()
     {
         std::vector<int> numbers = {1, 2, 3, 4, 5};
         std::ranges::for_each(numbers, [](int n) { std::cout << n << ' '; });
         std::cout << std::endl;
         return 0;
     }

The project file needs to be configured to use C++23 and enable the standard library module:

     cpp.forceUseCxxModules: true
     cpp.cxxLanguageVersion: "c++23"

Note: This feature requires a compiler and standard library that support the C++23 standard library module. Currently, this feature is experimental and may not be available in all toolchains.

The full product file may look like this:

     // myproject.qbs
     Project {
         CppStd {}

         CppApplication {
             name: "myapp"
             Depends { name: "CppStd" }
             condition: {
                 if (qbs.toolchainType === "msvc"
                     || ((qbs.toolchainType === "gcc")
                         && cpp.compilerVersionMajor >= 15)
                     || (qbs.toolchainType === "clang" && cpp.compilerVersionMajor >= 18)) {
                     return true;
                 }
                 console.info("Unsupported toolchainType " + qbs.toolchainType);
                 return false;
             }
             consoleApplication: true
             install: true
             files: ["main.cpp" ]
             cpp.forceUseCxxModules: true
             cpp.cxxLanguageVersion: "c++23"
             Properties {
                 condition: qbs.toolchainType === "clang"
                 cpp.cxxFlags: ["-Wno-reserved-module-identifier"]
                 cpp.cxxStandardLibrary: "libc++"
             }
         }
     }

In order to use `import std.compat;`, you will also need to set the CppStd.useStdCompat property to `true`:

     CppStd {
         useStdCompat: true
     }