/****************************************************************************
**
** Copyright (C) 2024 Ivan Komissarov (abbapoh@gmail.com).
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \previouspage module-providers.html
    \page tutorial.html
    \nextpage tutorial-1.html

    \title Tutorial

    The tutorial describes the process of creating a typical \QBS project and explains core
    concepts.

    \list
        \li  \l{tutorial-1.html}{Console Application}
        \li  \l{tutorial-2.html}{Static Library}
        \li  \l{tutorial-3.html}{Dynamic Library}
        \li  \l{tutorial-4.html}{Convenience Items}
        \li  \l{tutorial-5.html}{Autotest}
        \li  \l{tutorial-6.html}{Project Properties}
        \li  \l{tutorial-7.html}{Buildconfig Module}
        \li  \l{tutorial-8.html}{Configurable Library}
        \li  \l{tutorial-9.html}{Version Header}
        \li  \l{tutorial-10.html}{C++20 Modules}
    \endlist
*/

/*!
    \previouspage tutorial.html
    \page tutorial-1.html
    \nextpage tutorial-2.html

    \title Console Application

    Let's start with a mandatory Hello World example. There is a Hello World example in the
    \l{overview.html#well-defined-language}{overview section}, but this time we will create a
    real-world project.

    We will start with a simple \QBS project file:
    \snippet ../tutorial/chapter-1/myproject.qbs 0

    Here, we set the \l{Project::name}{name} of the project to \c "My Project" - it is mainly
    used for IDEs but can also be used to reference a project when setting properties from
    command-line. We also set the \l{Project::minimumQbsVersion}{minimumQbsVersion} - this property
    can be useful if the project depends on features that are not present in earlier \QBS
    versions.

    The \l{Project::references}{references} property contains the path to a file
    that describes our application. This file is located in a separate \c app directory -
    typically, projects tend to have quite a complicated structure but \QBS does not enforce any
    specific layout, so we will simply put each product in a separate directory.

    The application file sets several properties:
    \snippet ../tutorial/chapter-1/app/app.qbs 0

    The \l{Product::name}{name} property identifies the product.
    The \l{Product::targetName}{targetName} property sets the name of the resulting binary
    (without the \c .exe extension on Windows, which is appended automatically). By default,
    \l{Product::targetName}{targetName} defaults to \l{Product::name}{name}. The
    \l{Product::files}{files} property contains a single \c main.c file which is a trivial
    \e{hello world} application:
    \snippet ../tutorial/chapter-1/app/main.c 0

    We set \l{Product::consoleApplication}{consoleApplication} to \c true to indicate that our
    application is going to be used from a terminal. For example, on Windows, this will spawn a
    new console window if you double-click the resulting binary, while on macOS it will create a
    standalone binary file instead of an
    \l{https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html}{application bundle}.

    By default, \QBS installs binaries into an \e{installation root}
    folder which by default is named \c install-root and located under the build directory.
    This folder will contain only resulting artifacts without the build leftovers and files will
    have the same layout as in the target system. In order to skip installation of the specific
    Application product, set the \l{Application::install}{CppApplication.install} property to
    \c false.
    See the \l{installing-files.html}{Installing Files} section for more details.

    We can now build and run our application from the project directory:
    \code
    chapter-1 $ qbs build
    ...
    Building for configuration default
    compiling main.c [My Application]
    ...
    linking myapp [My Application]
    ...
    Build done for configuration default.

    chapter-1 $ qbs run
    ...
    Starting target. Full command line: .../default/install-root/usr/local/bin/myapp
    Hello, world
    \endcode

    The \QBS output to console and default installation location may vary between different
    platforms.

    In most cases, \QBS should be able to find the default compiler (for example, GCC or
    Clang on Linux, Visual Studio on Windows, or Xcode on macOS), but if that's not the
    case, see the \l{configuring.html}{configuring} section.

    In the following chapters, we will continue to improve our project: we will add a library and
    make it configurable.
*/

/*!
    \previouspage tutorial-1.html
    \page tutorial-2.html
    \nextpage tutorial-3.html

    \title Static Library

    Let's add a static library to our project so we can reuse some code. Analogous to what we did
    for the application, we put the file into the \c{lib} directory and add it to the
    \l{Project::references}{references} property in our project. The modified project may look
    like this:

    \snippet ../tutorial/chapter-2/myproject.qbs 0

    Let's take a look at the the library file now:

    \snippet ../tutorial/chapter-2/lib/lib.qbs 0
    It contains the \l{StaticLibrary} item which sets the \l{Product::type}{type} of the product
    to \c "staticlibrary" and sets some defaults like where to install that library.
    As before, we set the \l{Product::files}{files} property with a header:
    \snippet ../tutorial/chapter-2/lib/lib.h 0
    And we set the implementation file of our library:
    \snippet ../tutorial/chapter-2/lib/lib.c 0

    We will keep our library really simple - it only contains one function, which we will later use
    in our application. The source file requires a \c "CRUCIAL_DEFINE" to be
    passed to a preprocessor. That is why we set the \l{cpp::defines}{cpp.defines} property:
    \snippet ../tutorial/chapter-2/lib/lib.qbs 1

    Note that unlike the \l{CppApplication} item, the \l{StaticLibrary} does not pull in the
    dependency on the \l{cpp} module automatically - that is why we have to pull it in manually
    using the \l{Depends} item. Without the \l{cpp} module, \QBS would not know how to turn a
    \c{.c} file into an object file and the object file into a library. See
    \l{Rules and Product Types} for details.

    Next, we need to tell \QBS where to look for public headers of our library when building
    products that depend on it. By default, \QBS knows nothing about the layout of our
    library, so we tell it to look for headers in the library's source directory using the
    \l{Export} item:

    \snippet ../tutorial/chapter-2/lib/lib.qbs 2
    You can export any \l{Module} property within the \l{Export} item - it will be merged in the
    depending product with other properties. For example, you can export
    \l{cpp::defines}{cpp.defines} or specific \l{cpp::commonCompilerFlags}{compiler flags} that
    are required to use this product.

    We depend on the \l{cpp} module twice - once within the \l{StaticLibrary}
    item and once in the \l{Export} item. This is because by default \QBS does not export anything
    when depending on this product and the dependencies in this item (as well as
    properties set in this item) are private to this product while dependencies and properties
    set in the \l{Export} item are for export only.

    Finally, we have some Apple-specific settings. You can skip this part of the tutorial if you
    are using some other platform. We depend on the \l{bundle} module and set the
    \l{bundle::isBundle}{bundle.isBundle} to false:
    \snippet ../tutorial/chapter-2/lib/lib.qbs 3
    By default, \QBS builds static and dynamic libraries as
    \l{https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WhatAreFrameworks.html}{Frameworks}
    on macOS. So, to keep things simple, we disable the framework build and build a plain old
    static library file here.
*/

/*!
    \previouspage tutorial-2.html
    \page tutorial-3.html
    \nextpage tutorial-4.html

    \title Dynamic Library

    Let's now turn our static library into a dynamic library. It is a bit trickier with dynamic
    libraries since several things should be tweaked. First, we need to be able to mark methods
    (or classes) in our library as exported. Second, we need to tell our application where to look
    for our library at run time using \l{https://en.wikipedia.org/wiki/Rpath}{rpaths}.

    Some compilers, like MSVC, require us to mark which symbols we want to export or import. The
    \l{https://stackoverflow.com/a/6840659}{canonical} way would be to define some helper macros.
    Let's start with a header that defines those helper macros:
    \snippet ../tutorial/chapter-3/lib/lib_global.h 0

    This header defines the \c MYLIB_EXPORT macro that expands either to an "export" or to an
    "import" directive based on the presence of the \c MYLIB_LIBRARY macro. We can use this macro
    to mark a function as follows:
    \snippet ../tutorial/chapter-3/lib/lib.h 0

    The modified library product may look like this:

    \snippet ../tutorial/chapter-3/lib/lib.qbs 0

    The most important change is that we changed the item type from \l{StaticLibrary} to
    \l{DynamicLibrary}. We also added the \c MYLIB_LIBRARY to the list of
    \l{cpp::defines}{defines}. We do this only when building the library but we are not exporting
    it - that way the users of our library will have methods marked for import rather than export.

    Finally, we set \l{cpp::sonamePrefix}{cpp.sonamePrefix} to \c "@rpath". This is required only
    for Apple platforms, see
    \l{https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/RunpathDependentLibraries.html}{Run-Path Dependent Libraries}
    for details.

    It is also required to set \l{cpp::rpaths}{cpp.rpaths} in our application file. Since the
    library is installed to the \c{lib} directory and the application is installed to the \c{bin}
    directory, we need to tell the loader to look in the \c{lib} directory. The
    \l{jsextension-fileinfo.html#relativePath}{FileInfo.relativePath} method can help us:
    \snippet ../tutorial/chapter-3/app/app.qbs 0

    On Linux, this expression would be equivalent to this: \c{cpp.rpaths: ["$ORIGIN/../lib"]}.
    Don't forget to \c{import qbs.FileInfo} in order to be able to use the
    \l{jsextension-fileinfo.html} extension.

    To make the example complete, here's how the full \c app/app.qbs file should look like:
    \snippet ../tutorial/chapter-3/app/app.qbs 1
*/

/*!
    \previouspage tutorial-3.html
    \page tutorial-4.html
    \nextpage tutorial-5.html

    \title Convenience Items

    As you might have noticed, we are repeating ourselves when setting the same properties in our
    products - we set \l{Product::version}{version}, \l{cpp::rpaths}{cpp.rpaths}, and so on.
    For a single application and a library, that is not a big deal, but what if we have a dozen
    libraries? Luckily, this can be achieved using item
    \l{language-introduction.html#reusing-project-file-code}{inheritance} - we move the common code
    to the base item and in the real product we will only set what is specific to that product (for
    example, the list of \l{Product::files}{files}).

    First, we need to tell \QBS where to look for our new base items. This can be achieved using
    the \l{Project::qbsSearchPaths}{qbsSearchPaths} property. We set this property to \c "qbs" so
    that \QBS will search our items in the \c{qbs} directory located in the project directory:
    \snippet ../tutorial/chapter-4/myproject.qbs 0

    \note This directory has a pre-defined structure: base items should be located under the
    \c{imports} subdirectory. See \l{Custom Modules and Items} for details.

    Let's create a base item for all our applications and move common code there:
    \snippet ../tutorial/chapter-4/qbs/imports/MyApplication.qbs 0

    As you see, we managed to extract most of the code here, and our application file now only
    contains what's relevant to it:
    \snippet ../tutorial/chapter-4/app/app.qbs 0

    Now let's do the same for our library:
    \snippet ../tutorial/chapter-4/qbs/imports/MyLibrary.qbs 0

    Here, we introduce a helper property, \c libraryMacro, with a default value calculated based
    on the capitalized product name. Since the name of out library product is \c "mylib", this
    property will expand to \c "MYLIB_LIBRARY". We can also override the default value
    for the macro in products that inherit our item like this:
    \code
    MyLibrary {
        libraryMacro: "SOME_OTHER_LIBRARY_MACRO"
    }
    \endcode

    Let's take a look at the refactored library file:
    \snippet ../tutorial/chapter-4/lib/lib.qbs 0

    We managed to extract the reusable parts to common base items leaving the actual products clean
    and simple.

    Unfortunately, item inheritance comes with a price - when both parent and child items set the
    same property (\l{cpp::defines}{cpp.defines} in our case), the value in the child item wins.
    To work around this, the special \l{special-property-values.html#base}{base} value
    exists - it gives access to the base item's value of the current property and makes it possible
    to extend its value rather than override it. Here, we concatenate the list of defines from the
    base item \c{["MYLIB_LIBRARY"]} with a new list, specific to this product (namely,
    \c{['CRUCIAL_DEFINE']}).
*/

/*!
    \previouspage tutorial-4.html
    \page tutorial-5.html
    \nextpage tutorial-6.html

    \title Autotest

    Now that we can re-use our base items, let's add a simple autotest. We inherit the new item
    from the \c MyApplication item and add an \c "autotest" type:

    \snippet ../tutorial/chapter-5/qbs/imports/MyAutoTest.qbs 0

    This additional type is required for the helper \l{AutotestRunner} item. This item runs all
    products with the \c "autotest" type when it is being built. It also implicitly depends on all
    such products, so they will be built before running as well.

    Let's add this item to our top-level \l{Project} item:

    \code
    Project {
        name: "My Project"
        minimumQbsVersion: "2.0"
        // ...
        AutotestRunner {
            timeout: 60
        }
    }
    \endcode
    Here we set the \l{AutotestRunner::timeout}{timeout} property to 60 seconds so that our runner
    kills tests that run way too long.

    Now we need to add our first test. Let's create a new product with the following content:

    \snippet ../tutorial/chapter-5/test/test.qbs 0

    Here we depend on our library (which we are going to test), set the product
    \l{Product::name}{name}, and specify the source file, which looks like this:
    \snippet ../tutorial/chapter-5/test/test.c 0

    The test compares the value from the library with the value from the command line.

    Don't forget to add the new test product to the references property in the Project:
    \snippet ../tutorial/chapter-5/myproject.qbs 0

    Now we can build the autotest product - this will also launch our test:
    \code
    $ qbs build -p "autotest-runner"
    ...
    running test mytest [autotest-runner]
    Build done for configuration default.
    \endcode
*/

/*!
    \previouspage tutorial-5.html
    \page tutorial-6.html
    \nextpage tutorial-7.html

    \title Project Properties

    It would be nice if our project was configurable. Let's add some properties to our root project
    file:
    \snippet ../tutorial/chapter-6/myproject.qbs 0

    Now we can use those properties in our helper items and in products:

    \snippet ../tutorial/chapter-6/qbs/imports/MyApplication.qbs 0

    Here, we access the project file using the special
    \l{special-property-values.html#project}{project} value. If the nearest project in the project
    tree does not have the desired property, \QBS looks it up in the parent project, potentially
    all the way up to the top-level project.

    Let's now disable the tests if \c project.withTests is \c false:

    \snippet ../tutorial/chapter-6/myproject.qbs 1

    Here we use the \l{Properties} item within the \l{SubProject} item. This item allows to
    override a subproject's properties which can be useful when adding some other \QBS project as a
    Git submodule. Of course, it is not very useful in our particular case since we only set the
    \l{Project::condition}{Project.condition} property. We could achieve the same effect by
    setting the \l{SubProject::condition}{condition} property of the \l{SubProject} item:
    \code
        SubProject {
            filePath: "test/test.qbs"
            condition: parent.withTests
        }
    \endcode
    Another way would be to disable the test product. That way, an IDE would still show the whole
    project tree including disabled tests:
    \code
        // qbs/imports/MyAutoTest.qbs
        MyApplication {
            condition: project.withTests
            type: base.concat(["autotest"])
        }
    \endcode

    Let's finally make our \l{AutotestRunner} configurable too:
    \snippet ../tutorial/chapter-6/myproject.qbs 2

    There are several ways to override project properties from the command line. First, the special
    \c project variable can be used to set the properties of the top-level project:
    \code
        $ qbs resolve project.withTests:false
    \endcode

    You can also refer to properties using project's \l{Project::name}{name}:

    \code
        $ qbs resolve "projects.My Project.withTests:false"
    \endcode

    This can again be useful for accessing the properties of external sub-projects. Note that since
    the project name contains spaces, we use quotes here.
*/

/*!
    \previouspage tutorial-6.html
    \page tutorial-7.html
    \nextpage tutorial-8.html

    \title Config Module

    In the previous chapter, we added some properties to our main \l{Project} file. While this is a
    perfect approach for \e public properties of the project, sometimes we want
    to add some \e private properties for better tuning. Of course, we could put everything
    in the \l{Project} file, but that would make it very convoluted. Also, accessing the top-level
    project all the way from products makes things strongly tied.

    Let's create a file named \c{module.qbs} and put it into the
    \c{qbs/modules/config/install} directory, near the \c{qbs/imports} directory:
    \code
        // qbs/modules/config/install/module.qbs
        ConfigInstall {
        }
    \endcode
    Here we inherit the \l{ConfigInstall} item in order to re-use its properies. Since custom
    \l{Project::qbsSearchPaths}{qbsSearchPaths} are searched first, now our version
    will be used instead of built-in one.

    First, let's change the default value of the
    \l{ConfigInstall::importLibraries}{config.install.importLibraries} in order to install
    import libraries on Windows:
    \code
        // qbs/modules/config/install/module.qbs
        ConfigInstall {
            importLibraries: true
        }
    \endcode

    We could extend the \l{config.install} module with additional properties, but that could create
    collisions when someone tries to include the source code of your project into their project.
    Thus, we will create a new \c{config.myproject} module and use the same approach with the base
    item as \QBS does for the \c{config.install} module.

    Let's create a new item and add a new property to it:
    \snippet ../tutorial/chapter-7/qbs/imports/ConfigMyProject.qbs 0

    We added the \c{installPublicHeaders} property that will allow us to configure whether we
    need to install public headers for our library.

    Now let's use the item in a module:
    \snippet ../tutorial/chapter-7/qbs/modules/config/myproject/module.qbs 0

    Now we can use our module in the \c{MyLibrary.qbs} item:
    \snippet ../tutorial/chapter-7/qbs/imports/MyLibrary.qbs 0

    We pull in the new module using the \l{Depends} item, similar to how we pulled in
    the \l{cpp} module dependency earlier.

    We add a new \c{publicHeaders} property that will contain the list of headers we want to
    install.

    Finally, we create a \l{Group} item that installs headers listed by the \c{publicHeaders}
    property to the \l{installpaths::include}{installpaths.include} directory.

    Note that we use the \l{installpaths} module - it is pulled in by the
    \l{DynamicLibrary} item and is available in all items that inherit that item.

    Now we can rewrite the \c{lib/lib.qbs} to use the new property:

    \snippet ../tutorial/chapter-7/lib/lib.qbs 0

    Instead of the \c{config.myproject.installPublicHeaders} property, we could also use the
    property in the \l{Project} item similar to how we did in the previous
    chapter. There is no strong preference which way to use, however using modules for
    configuration is more flexible as it is also possible to set properties of other modules
    as described below.

    \QBS \l{Module}{modules} have the feature to automatically export properties of other modules.
    Those exported properties are merged in the resulting product. We can use this feature to set
    the \l{cpp::rpaths}{cpp.rpaths} in our module rather than in products:

    \snippet ../tutorial/chapter-7/qbs/imports/ConfigMyProject.qbs 1

    Here, we inject the dependency on the \l{cpp} module and calculate the \c{libRPaths} property.
    This is a relative path from the \c{product.installDir} (which is either \c{"bin"}
    or \c{"lib"}, depending on product type) to
    \l{ConfigInstall::dynamicLibrariesDirectory}{dynamicLibrariesDirectory} (which is \c{"lib"}
    by default). Finally, we set \l{cpp::rpaths}{cpp.rpaths} to this property. This way, those
    \c rpaths will be automatically exported to all products that depend on the
    \c{config.myproject} module.

    We should also update the \c{MyApplication} item to add a dependency on the
    \c{"config.myproject"} in order to inject \l{cpp::rpaths}{cpp.rpaths} we set in the module:
    \snippet ../tutorial/chapter-7/qbs/imports/MyApplication.qbs 0

    Let's change whether to install public headers when building our project:
    \code
        $ qbs modules.config.myproject.installPublicHeaders:true
        ...
        $ ls default/install-root/usr/local/include/
        lib.h
    \endcode
*/

/*!
    \previouspage tutorial-7.html
    \page tutorial-8.html
    \nextpage tutorial-9.html

    \title Configurable Library

    In this chapter, we will make our library more configurable to be able to choose between
    static and dynamic builds.

    We need to do some modifications to export macros in the \c lib/lib_global.h header:
    \snippet ../tutorial/chapter-8/lib/lib_global.h 0

    Here' we added a new branch when \c MYLIB_STATIC_LIBRARY is defined. In that case, we make
    the \c MY_LIB_EXPORT macro empty.

    Now, let's modify the \c qbs/imports/MyLibrary.qbs file as follows:
    \snippet ../tutorial/chapter-8/qbs/imports/MyLibrary.qbs 0

    First thing to notice is that we changed the type of the item from \l{DynamicLibrary} to the
    \l{Library} item which is a common base item for dynamic and static libraries.

    Second, we change our \e{export macro} to be different in the static and dynamic builds to
    correspond with the changes we made to the \c lib_global.h:
    \code
    readonly property string _nameUpper : name.replace(" ", "_").toUpperCase()
    property string libraryMacro: _nameUpper + "_LIBRARY"
    property string staticLibraryMacro: _nameUpper + "_STATIC_LIBRARY"
    cpp.defines: config.build.libraryType === "static" ? [staticLibraryMacro] : [libraryMacro]
    \endcode

    Note that in a static build we export the \c MYLIB_STATIC_LIBRARY macro so that the dependent
    products will know whether they link to a static or dynamic library:
    \code
    Export {
        ...
        cpp.defines: exportingProduct.config.build.libraryType === "static"
            ? [exportingProduct.staticLibraryMacro] : []
    }
    \endcode

    Now we can build our project in dynamic or static mode:
    \code
    $ qbs resolve modules.config.build.libraryType:static && qbs build
    ...
    $ ls default/install-root/usr/local/lib/
        libmylib.1.0.0.so
        libmylib.1.0.so
        libmylib.1.so
        libmylib.so
    $ rm -r default
    $ qbs resolve modules.config.myproject.staticBuild:true modules.config.install.staticLibraries:true && qbs build
    ...
    $ $ ls default/install-root/usr/local/lib/
        libmylib.a
    \endcode

    \note \QBS does not install static libraries by default, thats why we set the
    \l{ConfigInstall::staticLibraries}{config.install.staticLibraries} property to \c{true} to
    enforce installation of the static library. We can also change the default in the
    \c{config.install} module:
    \code
    // qbs/modules/config/install/module.qbs
    ConfigInstall {
        ...
        importLibraries: true
        staticLibraries: true
        ...
    }
    \endcode
*/

/*!
    \previouspage tutorial-8.html
    \page tutorial-9.html
    \nextpage tutorial-10.html

    \title Version Header

    To create new files, such as version headers, during the build, use \l{Rules}. Every command
    \QBS executes, such as compile or linker commands, is described by a corresponding Rule in a
    Module or a Product.

    In this section, we will create a simple header with a string constant based on the variable
    in our project.

    First, we add this variable to our \c config.myproject base item:
    \snippet ../tutorial/chapter-9/qbs/imports/ConfigMyProject.qbs 0

    Next, we create a new file, \c{version.h.in}, located in the \c{version-header} directory. This
    file contains the template for our header:
    \snippet ../tutorial/chapter-9/version-header/version.h.in 0

    Now we create a file called \c{version-header.qbs} in the same directory. This file contains
    a \l{Product} with a \l{Rule} that turns the \c{version.h.in} into a real header.
    Let's go through the contents of the file:
    \snippet ../tutorial/chapter-9/version-header/version-header.qbs 0

    First, we import \l{TextFile Service}{TextFile}. We will need this class to read the template
    and write the resulting header. Second, we declare a new \l{Product} named \c{"version_header"}
    and with the \c{"hpp"} type. This is the type of the artifact we will create in the Rule.
    Third, we add the dependency on the \c config.myproject module to use the new
    \c config.myproject.productVersion variable.

    We also add a \l{Group} with the template file and assign the \c{version_h_in} tag to the file:
    \snippet ../tutorial/chapter-9/version-header/version-header.qbs 1

    \QBS Rules work with file tags, instead of working with files directly, which makes
    it easy to reuse rules. The name of the tag is chosen arbitrarily here. We could use the name
    of the file as a tag, but to avoid confusion between file name and file tag, we use underscores
    in the tag instead of dots.

    Now we can create a Rule itself:
    \snippet ../tutorial/chapter-9/version-header/version-header.qbs 2
    Here, we specify that our Rule takes files tagged as \c "version_h_in" and produces an
    \l{Artifact} with the name \c "version.h" and tagged \c "hpp". By default, files are created in
    the \l{Product::destinationDirectory}{Product.destinationDirectory} folder. We add the \c "hpp"
    tag for the header as this is the tag the \l{cpp}{cpp module} uses for headers. That way, \QBS
    can track changes and process our generated file the same way it treats all other
    headers. Note that earlier we set the product type to \c "hpp" as well. \QBS requires that
    artifact type should match the product type directly or be accessible via the chain of Rules.
    Otherwise, the Rule won't be executed. For details, see the \l{Rules and Product Types}
    section.

    The actual code generation happens in the \l{Rule::prepare}{Rule.prepare} script:
    \snippet ../tutorial/chapter-9/version-header/version-header.qbs 3

    In this script, we create a \l {JavaScriptCommand} object and set some meta properties, such as
    the description and highlight. For details about Commands, see
    \l{Command and JavaScriptCommand}. In the sourceCode variable, we create a JavaScript
    function that opens the \l{The inputs and outputs Variables}{input file}, reads its content
    using the \l{TextFile Service}{TextFile} object, replaces the \c "${PRODUCT_VERSION}"
    placeholder with the actual value in the \c product.config.myproject.productVersion variable,
    and writes the resulting content into the \l{The inputs and outputs Variables}{output file}.

    Finally, we export the \l{Product::buildDirectory}{exportingProduct.buildDirectory} so that
    products that depend on this product can include our generated header:

    \snippet ../tutorial/chapter-9/version-header/version-header.qbs 4

    The full content of the file should look like this:

    \snippet ../tutorial/chapter-9/version-header/version-header.qbs 5

    Let's now add our Product into the root project so \QBS will be aware of it:
    \snippet ../tutorial/chapter-9/myproject.qbs 0

    We also need to add the dependency on the \c "version_header" to our application:
    \snippet ../tutorial/chapter-9/app/app.qbs 0

    Now we can include the header in the \c main.c file and print the contents of the string
    constant:

    \snippet ../tutorial/chapter-9/app/main.c 0

    Let's try and run our application. You should see something like this:
    \code
    $ qbs run -p "My Application"
    Starting target. Full command line: .../default/install-root/usr/local/bin/myapp
    Hello, world
    Hello from library
    ProductVersion = 1.0.0
    \endcode
*/


/*!
    \previouspage tutorial-9.html
    \page tutorial-10.html
    \nextpage howtos.html

    \title C++20 Modules

    This tutorial implies you have some knowledge about C++20 modules. If not, see
    \l{https://learn.microsoft.com/en-us/cpp/cpp/modules-cpp}{Overview of modules in C++} for
    introduction.

    \section1 Named Modules

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

    \snippet ../tutorial/chapter-10-1/hello.cppm 0

    \note Currently, Clang only recognizes \c .cppm files as modules, however, for GCC and MSVC
    \QBS also recognizes \c .ixx files as C++ modules. \QBS assigns the \c "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 \c main.cpp file as follows:

    \snippet ../tutorial/chapter-10-1/main.cpp 0

    The project file simply lists files and sets the
    \l{cpp::forceUseCxxModules}{cpp.forceUseCxxModules} property to \c true.
    \code
    // myproject.qbs
    CppApplication {
        consoleApplication: true
        files: ["hello.cppm", "main.cpp"]
        cpp.cxxLanguageVersion: "c++20"
        cpp.forceUseCxxModules: true
    }
    \endcode

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

    \section1 Module Partitions

    \l{https://learn.microsoft.com/en-us/cpp/cpp/modules-cpp?view=msvc-170#module-partitions}{Module partitions}
    are treated as regular modules and should also have the same extension or assigned the
    \c "cppm" tag manually. See this
    \l{https://github.com/qbs/qbs/tree/2.5/examples/cxx-modules/mod3}{example} on how to
    use both interface module and partitions.

    \section1 Modules and Libraries

    Using modules in dynamic libraries requires using the same export/import macros as it was shown
    in the \l{tutorial-3.html}{Dynamic Library} section:

    \snippet ../tutorial/chapter-10-2/lib/hello.cppm 0

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

    \code
    // 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
        // ...
    }
    \endcode

    For more details, see the complete
    \l{https://github.com/qbs/qbs/tree/2.5/tutorial/chapter-10-2}{example}.

    \section1 Import std module

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

    In order to use \c{import std;}, you need to define the \l{CppStd} product somewhere in your
    project and add a dependency on it to products that require the \c{std} module:
    \code
    Project {
        CppStd {}
        CppApplication {
            Depends { name: "CppStd" }
        }
    }
    \endcode

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

    \snippet ../tutorial/chapter-10-3/main.cpp 0

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

    \snippet ../tutorial/chapter-10-3/myproject.qbs 0

    \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:

    \snippet ../tutorial/chapter-10-3/myproject.qbs 1

    In order to use \c{import std.compat;}, you will also need to set the
    \l{CppStd::useStdCompat}{CppStd.useStdCompat} property to \c{true}:

    \code
    CppStd {
        useStdCompat: true
    }
    \endcode
*/
