Qbs

Blog Documentation Get Qbs Community
  • Qbs Manual
  • C++20 Modules
  • Qbs 3.0.1
  • 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
        install: 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"
        install: true
    
        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 set the cpp.forceUseImportStd property to true.

    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.cxxLanguageVersion: "c++23"
    cpp.forceUseCxxModules: true
    cpp.forceUseImportStd: true

    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
    CppApplication {
        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.cxxLanguageVersion: "c++23"
        cpp.forceUseCxxModules: true
        cpp.forceUseImportStd: true
        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 cpp.forceUseImportStdCompat to true:

    cpp.forceUseImportStd: true
    cpp.forceUseImportCompatStd: true