diff options
Diffstat (limited to 'doc')
24 files changed, 1282 insertions, 103 deletions
diff --git a/doc/appendix/json-api.qdoc b/doc/appendix/json-api.qdoc index b555825f9..7b093bc4e 100644 --- a/doc/appendix/json-api.qdoc +++ b/doc/appendix/json-api.qdoc @@ -94,6 +94,7 @@ \header \li Property \li Type \row \li api-level \li int \row \li api-compat-level \li int + \row \li lsp-socket \li string \endtable The value of \c api-level is increased whenever the API is extended, for instance @@ -108,6 +109,10 @@ The value of \c api-compat-level is always less than or equal to the value of \c api-level. + The value of \c lsp-socket is a path to a local domain socket (on Unix) or + a named pipe (on Windows). It provides a server implementing the + \l{https://microsoft.github.io/language-server-protocol}{Language Server Protocol}. + \section1 Resolving a Project To instruct \QBS to load a project from disk, a request of type @@ -121,10 +126,10 @@ \row \li dry-run \li bool \li no \row \li environment \li \l Environment \li no \row \li error-handling-mode \li string \li no - \row \li fallback-provider-enabled \li bool \li no \row \li force-probe-execution \li bool \li no \row \li log-time \li bool \li no \row \li log-level \li \l LogLevel \li no + \row \li max-job-count \li int \li no \row \li module-properties \li list of strings \li no \row \li overridden-properties \li object \li no \row \li project-file-path \li FilePath \li if resolving from scratch diff --git a/doc/config/macros.qdocconf b/doc/config/macros.qdocconf index 6811215c0..31b9b9a8d 100644 --- a/doc/config/macros.qdocconf +++ b/doc/config/macros.qdocconf @@ -51,6 +51,8 @@ macro.endfloat.HTML = "</div>" macro.clearfloat.HTML = "<br style=\"clear: both\" />" macro.emptyspan.HTML = "<span></span>" +macro.CMAKE = "CMake" + # Embed YouTube content by video ID - Example: \youtube dQw4w9WgXcQ # Also requires a <ID>.jpg thumbnail for offline docs. In .qdocconf, add: # diff --git a/doc/doc.qbs b/doc/doc.qbs index 03c82e18c..0dfc5f474 100644 --- a/doc/doc.qbs +++ b/doc/doc.qbs @@ -30,6 +30,7 @@ Project { "fixnavi.pl", "howtos.qdoc", "qbs.qdoc", + "tutorial.qdoc", "qbs-online.qdocconf", "config/*.qdocconf", "config/style/qt5-sidebar.html", diff --git a/doc/howtos.qdoc b/doc/howtos.qdoc index 268bee7c0..9a81318ee 100644 --- a/doc/howtos.qdoc +++ b/doc/howtos.qdoc @@ -25,7 +25,7 @@ ** ****************************************************************************/ /*! - \previouspage custom-modules.html + \previouspage tutorial-8.html \nextpage reference.html \page howtos.html @@ -467,15 +467,17 @@ \section1 How do I build against libraries that provide pkg-config files? - Just add a \l Depends item that matches the name of the pkg-config module, and \QBS - will automatically employ \l{https://www.freedesktop.org/wiki/Software/pkg-config}{pkg-config} + Just add a \l Depends item that matches the name of the pkg-config module, + set the \l Product::qbsModuleProviders property to \c "qbspkgconfig", + and \QBS will employ + \l{https://www.freedesktop.org/wiki/Software/pkg-config}{pkg-config} to find the headers and libraries if no matching \QBS module can be found. For instance, to build against the OpenSSL library, you would write this: \code + qbsModuleProviders: "qbspkgconfig" Depends { name: "openssl" } \endcode - That's it. The pkg-config behavior can be fine-tuned via the \l pkgconfig module, - but normally you will not need to pull it in explicitly. + That's it. The pkg-config behavior can be fine-tuned via the \l qbspkgconfig provider. Internally, this functionality is implemented via \l {Module Providers} diff --git a/doc/qbs.qdoc b/doc/qbs.qdoc index c77dae824..83e461f29 100644 --- a/doc/qbs.qdoc +++ b/doc/qbs.qdoc @@ -70,6 +70,18 @@ \li \l{Special Property Values} \li \l{Module Providers} \endlist + \li \l{Tutorial} + \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} + \endlist \li \l{How-tos} \li \l{Reference} \list @@ -462,7 +474,7 @@ To build \QBS from the source, you need: \list - \li Qt 5.14, or later + \li Qt 5.15, or later \li Windows: MinGW with GCC 4.9 or Microsoft Visual Studio 2015, or later \li Linux: GCC 4.9, or later, or Clang 3.9.0, or later @@ -1068,7 +1080,6 @@ */ - /*! \previouspage usage.html \page language-introduction.html @@ -1881,7 +1892,7 @@ /*! \previouspage special-property-values.html \page module-providers.html - \nextpage howtos.html + \nextpage tutorial.html \title Module Providers @@ -1916,12 +1927,6 @@ a second attempt will be made to locate the dependency using the new paths. The search for a matching module provider ends as soon as one was found, regardless of whether it created any modules or not. - \li If no matching module provider was found in any of the search paths, \QBS will fall back - to a generic module provider, which creates a module that attempts to locate the - dependency via \c pkg-config. - This fallback mechanism can be disabled in the respective - \l{Depends::enableFallback}{Depends} item or globally via the - \l{no-fallback-module-provider}{--no-fallback-module-provider} option. \endlist \section1 Selecting Module Providers diff --git a/doc/reference/cli/builtin/cli-build.qdoc b/doc/reference/cli/builtin/cli-build.qdoc index 683b1ebb8..8547a78d2 100644 --- a/doc/reference/cli/builtin/cli-build.qdoc +++ b/doc/reference/cli/builtin/cli-build.qdoc @@ -78,8 +78,6 @@ \include cli-options.qdocinc products-specified \include cli-options.qdocinc settings-dir \include cli-options.qdocinc show-progress - \target no-fallback-module-provider - \include cli-options.qdocinc no-fallback-module-provider \include cli-options.qdocinc wait-lock \section1 Parameters diff --git a/doc/reference/cli/builtin/cli-resolve.qdoc b/doc/reference/cli/builtin/cli-resolve.qdoc index 4569980bd..99f1658ea 100644 --- a/doc/reference/cli/builtin/cli-resolve.qdoc +++ b/doc/reference/cli/builtin/cli-resolve.qdoc @@ -55,7 +55,6 @@ \include cli-options.qdocinc more-verbose \include cli-options.qdocinc settings-dir \include cli-options.qdocinc show-progress - \include cli-options.qdocinc no-fallback-module-provider \include cli-options.qdocinc deprecation-warnings \section1 Parameters diff --git a/doc/reference/items/convenience/appleapplicationdiskimage.qdoc b/doc/reference/items/convenience/appleapplicationdiskimage.qdoc index 8db7bc4db..d1fa15052 100644 --- a/doc/reference/items/convenience/appleapplicationdiskimage.qdoc +++ b/doc/reference/items/convenience/appleapplicationdiskimage.qdoc @@ -77,10 +77,11 @@ The base directory from which artifacts installed into the disk image will be copied. This directory is always considered to be relative to \l{qbs::installRoot} - {qbs.installRoot}. + {qbs.installRoot}/\l{qbs::installPrefix} + {qbs.installPrefix}. For example, if the application Example.app exists at - \c{qbs.installRoot/Applications/Example.app}, and the value of this property - is \c{"/Applications"}, the application will be located at\c{/Example.app} + \c{qbs.installRoot/qbs.installPrefix/Applications/Example.app}, and the value of this property + is \c{"/Applications"}, the application will be located at \c{/Example.app} relative to the disk image root. Therefore, its full path when the disk image is mounted would be something like \c{/Volumes/Example-1.0/Example.app}. diff --git a/doc/reference/items/language/depends.qdoc b/doc/reference/items/language/depends.qdoc index 7cc270483..937828b8c 100644 --- a/doc/reference/items/language/depends.qdoc +++ b/doc/reference/items/language/depends.qdoc @@ -197,12 +197,3 @@ \nodefaultvalue */ - -/*! - \qmlproperty bool Depends::enableFallback - - Whether to fall back to a pkg-config based \l{Module Providers}{module provider} - if the dependency is not found. - - \defaultvalue \c true -*/ diff --git a/doc/reference/items/language/group.qdoc b/doc/reference/items/language/group.qdoc index c9b6dd1cf..fa6784ca6 100644 --- a/doc/reference/items/language/group.qdoc +++ b/doc/reference/items/language/group.qdoc @@ -74,10 +74,13 @@ } } \endcode - When specifying files, you can use the wildcards "*", "?" and "[]", which have their usual meaning. - By default, matching files are only picked up directly from the parent directory, but you can tell \QBS to - consider the whole directory tree. It is also possible to exclude certain files from the list. - The pattern ** used in a pathname expansion context will match all files and zero or more + When specifying files, you can use the wildcards \c "*", \c "?" and \c "[]", which + have their + \l{https://en.wikipedia.org/wiki/Wildcard_character#File_and_directory_patterns}{usual meaning} + as in Unix Shell. By default, matching files are only picked up directly from the + parent directory, but you can tell \QBS to consider the whole directory tree. + It is also possible to exclude certain files from the list. + The pattern \c "**" used in a pathname expansion context will match all files and zero or more directories and subdirectories. For example: \snippet reference/items/language/group.qbs 0 @@ -114,13 +117,15 @@ */ /*! - \qmlproperty list Group::files + \qmlproperty pathList Group::files The files in the group. Mutually exclusive with \l{fileTagsFilter}. Relative paths are resolved using the parent directory of the file that contains the Group item. However, if the \l{prefix} property is set to an absolute path, then that one becomes the base directory. + The values can contain wildcards. + \defaultvalue An empty list */ @@ -146,7 +151,7 @@ */ /*! - \qmlproperty list Group::fileTagsFilter + \qmlproperty stringList Group::fileTagsFilter List of \l{Artifact::fileTags}{artifact.fileTags} to match. Any properties set in this group will be applied to the product's artifacts whose file tags @@ -170,7 +175,7 @@ */ /*! - \qmlproperty list Group::fileTags + \qmlproperty stringList Group::fileTags A list of file tags to attach to the group's files. These can then be matched by a \l{Rule}{rule}. @@ -196,10 +201,13 @@ */ /*! - \qmlproperty list Group::excludeFiles + \qmlproperty pathList Group::excludeFiles + + A list of files that are \e subtracted from the \l{files} list. - A list of files that are \e subtracted from the files list. Useful when - using wildcards. + The values can contain wildcards. + + This property is ignored if \l{fileTagsFilter} is set. \defaultvalue An empty list */ diff --git a/doc/reference/items/language/moduleprovider.qdoc b/doc/reference/items/language/moduleprovider.qdoc index 81a09a66b..09cabb39b 100644 --- a/doc/reference/items/language/moduleprovider.qdoc +++ b/doc/reference/items/language/moduleprovider.qdoc @@ -67,6 +67,19 @@ */ /*! + \qmlproperty bool ModuleProvider::isEager + + Holds whether provider is eager. + + Eager provider is executed only once and should create multiple modules at once when executed). + A non-eager provider is executed multiple times, one time for each module \QBS tries to + instantiate. + + \sa ModuleProvider::moduleName + \default true +*/ + +/*! \qmlproperty string ModuleProvider::name The name of the module provider. @@ -83,6 +96,17 @@ */ /*! + \qmlproperty string ModuleProvider::moduleName + + This property is set by QBS for non-eager providers and contains the name of the module + that is currently being instantiated by the provider. + + For eager providers, the value of this property is \c undefined. + + \sa ModuleProvider::isEager +*/ + +/*! \qmlproperty string ModuleProvider::outputBaseDir The path under which the new modules should be created when \l relativeSearchPaths diff --git a/doc/reference/items/language/parameters.qdoc b/doc/reference/items/language/parameters.qdoc index 325f1680e..fb7653528 100644 --- a/doc/reference/items/language/parameters.qdoc +++ b/doc/reference/items/language/parameters.qdoc @@ -32,10 +32,10 @@ \ingroup list-of-items \keyword QML.Parameters - \brief Defines default values for dependency parameters within Export items. + \brief Defines default values for dependency parameters within Module and Export items. The Parameters item defines default values for dependency parameters within - \l{Export} items. + \l{Module} and \l{Export} items. Example: \code diff --git a/doc/reference/items/probe/binary-probe.qdoc b/doc/reference/items/probe/binary-probe.qdoc index 7c8cd2f42..919d0b89e 100644 --- a/doc/reference/items/probe/binary-probe.qdoc +++ b/doc/reference/items/probe/binary-probe.qdoc @@ -50,6 +50,7 @@ For example, BinaryProbe can be used to search for a protobuf compiler executable as follows: \code + // Assuming module is called "myproto" import qbs.File import qbs.Probes @@ -70,10 +71,10 @@ Rule { // rule input/outputs here... - // run executable + // run executable for the module called "myproto": prepare: { var args = // initialize arguments... - var cmd = new Command(executableFilePath, args); + var cmd = new Command(input.myproto.executableFilePath, args); cmd.highlight = "codegen"; cmd.description = "generating protobuf files for " + input.fileName; return [cmd]; diff --git a/doc/reference/items/probe/pkgconfig-probe.qdoc b/doc/reference/items/probe/pkgconfig-probe.qdoc index 22fd510ac..66e008601 100644 --- a/doc/reference/items/probe/pkgconfig-probe.qdoc +++ b/doc/reference/items/probe/pkgconfig-probe.qdoc @@ -51,8 +51,12 @@ maxVersion: '5.99.99' } files: 'main.cpp' - cpp.cxxFlags: pkgConfig.cflags - cpp.linkerFlags: pkgConfig.libs + cpp.defines : pkgConfig.defines + cpp.includePaths: pkgConfig.includePaths + cpp.dynamicLibraries: pkgConfig.libraries + cpp.libraryPaths: pkgConfig.libraryPaths + cpp.commonCompilerFlags: pkgConfig.compilerFlags + cpp.linkerFlags: pkgConfig.linkerFlags } \endcode */ @@ -194,9 +198,6 @@ This output property contains the list of library paths that should be passed to a linker when using requested package. - This property sets the value of the PKG_CONFIG_LIBDIR environment variable passed to - the \c pkg-config binary. - \nodefaultvalue */ diff --git a/doc/reference/module-providers/conan-module-provider.qdoc b/doc/reference/module-providers/conan-module-provider.qdoc new file mode 100644 index 000000000..4edba94d8 --- /dev/null +++ b/doc/reference/module-providers/conan-module-provider.qdoc @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +/*! + \qmltype conan + \inqmlmodule QbsModuleProviders + \since 2.4 + + \brief Module provider for the Conan package manager. + + This module provider allows integration with the \l{https://conan.io}{Conan} package manager. + + \section1 Prerequisites + In order to use this provider, you will need to install the + \l{https://github.com/qbs/qbs/blob/master/src/conan/extensions/generators/qbsdeps.py}{QbsDeps generator} + first. In order to do so, clone the \QBS repository and run the following command from the \QBS + source directory: + \code + $ conan config install src/conan/ + \endcode + This will copy the generator to \c .conan2/extensions/generators/qbsdeps.py in the user's home + directory. + Alternatively, you can use \c curl to download the file: + \code + $ curl 'https://github.com/qbs/qbs/raw/master/src/conan/extensions/generators/qbsdeps.py' -o ~/.conan2/extensions/generators/qbsdeps.py + \endcode + + \section1 Example + For details on how to setup a project to use with Conan, see the \ + l{https://github.com/qbs/qbs/blob/master/examples/protobuf/addressbook_conan}{addressbook_conan} + folder in examples. + First, you will need a \l{https://docs.conan.io/2/reference/conanfile_txt.html}{conanfile} as + shown below. + \code + [requires] + protobuf/3.21.12 + [tool_requires] + protobuf/3.21.12 + [generators] + QbsDeps + \endcode + We use the text version for simplicity, but you can use the Python conanfile as well. + + Next, set the \l{Product::qbsModuleProviders}{qbsModuleProviders} property to \c "conan": + \snippet ../examples/protobuf/addressbook_conan/addressbook_conan.qbs 0 + + Install Conan dependencies and run the QbsDeps generator from the \c addressbook_conan dir: + \code + $ conan install . -g=QbsDeps --output-folder=build --build missing + \endcode + This will create the \c{./build/qbs-deps} directory contaning files for provider. Now you can + pass the conan install directory to the provider: + \code + $ qbs moduleProviders.conan.installDirectory:build + \endcode + You should see the following output if everything is correct: + \code + Build graph does not yet exist for configuration 'default'. Starting from scratch. + Resolving project for configuration default + Setting up Conan module 'protobuflib' + Setting up Conan module 'zlib' + ... + Build done for configuration default. + \endcode +*/ + +/*! + \qmlproperty string conan::installDirectory + + The path to the conan install installDirectory. + + \QBS searches for files created by the QbsDeps generator in that directory. + + If not set, the provider will not be run. + + \defaultvalue undefined +*/ diff --git a/doc/reference/module-providers/qbspkgconfig-module-provider.qdoc b/doc/reference/module-providers/qbspkgconfig-module-provider.qdoc index f9c4e9ade..a7f6fe6b7 100644 --- a/doc/reference/module-providers/qbspkgconfig-module-provider.qdoc +++ b/doc/reference/module-providers/qbspkgconfig-module-provider.qdoc @@ -87,6 +87,29 @@ */ /*! + \qmlproperty bool qbspkgconfig::definePrefix + + If this property is \c true, then \QBS will override the ${prefix} variable in the packages + with a value that is guessed based on the location of the .pc file. + + This option corresponds to the \c --define-prefix / \c --dont-define-prefix command line + options of the \c pkg-config tool. + + \defaultvalue \c true on Windows, \c false otherwise +*/ + +/*! + \qmlproperty stringList qbspkgconfig::executableNames + + The names of the \c pkg-config executable to search for. + + Note that since newer distributions use \l{http://pkgconf.org}{pkgconf} by default, it has + higher priority over \c pkg-config. + + \defaultvalue \c{["pkgconf", "pkg-config"]} +*/ + +/*! \qmlproperty path qbspkgconfig::sysroot Set this property if you need to overwrite the default search sysroot path used by @@ -100,7 +123,7 @@ Setting this property to \c undefined or empty (\c "") value will use pkg-config's default search paths: \code - qbs build module-providers.pkgconfig.sysroot:undefined + qbs resolve moduleProviders.qbspkgconfig.sysroot:undefined \endcode This property is the equivalent of the \c{PKG_CONFIG_SYSROOT_DIR} variable for the @@ -108,15 +131,3 @@ \defaultvalue \c "" on macOS, \c qbs.sysroot on other platforms */ - -/*! - \qmlproperty bool qbspkgconfig::mergeDependencies - - Holds whether dependencies should be merged by pkg-config or \QBS. - - If set to true, dependencies are merged by pkg-config meaning each generated module - is self-contained and does not depend on other modules. If set to false, generated modules - may depend on other modules and property merging is done by \QBS. - - \defaultvalue \c false -*/ diff --git a/doc/reference/modules/capnprotocpp-module.qdoc b/doc/reference/modules/capnprotocpp-module.qdoc index c3c8660c9..7635edd9e 100644 --- a/doc/reference/modules/capnprotocpp-module.qdoc +++ b/doc/reference/modules/capnprotocpp-module.qdoc @@ -104,12 +104,10 @@ /*! \qmlproperty string capnproto.cpp::outputDir - \readonly The directory where the \c capnpc compiler generated files are placed. - The value of this property is automatically set by \QBS and cannot be - changed by the user. + \defaultvalue \c product.buildDirectory + "/capnp" */ /*! diff --git a/doc/reference/modules/cpp-module.qdoc b/doc/reference/modules/cpp-module.qdoc index f0b6de063..2b344aac2 100644 --- a/doc/reference/modules/cpp-module.qdoc +++ b/doc/reference/modules/cpp-module.qdoc @@ -80,6 +80,7 @@ May contain the values: "weak", "lazy", "reexport", and "upward"; refer to the Apple ld64 man page for full details. \c{undefined} uses normal linking. Currently only applies when linking for Apple platforms. + Note that \c "lazy" mode is deprecated and doesn't work with Xcode 15 and above. \endtable \section2 Relevant File Tags @@ -1402,8 +1403,8 @@ will result in the \c {-fuse-ld} option being emitted when linking with \c gcc, \c clang or \c clang-cl. Other toolchains do not support this property. - The possible values for \c clang and \c gcc are \c "bfd", \c "gold" and \c "lld", - the possible values for \c clang-cl are \c "link" and \c "lld". + The possible values for \c clang and \c gcc are \c "bfd", \c "gold", \c "lld" + and \c "mold", the possible values for \c clang-cl are \c "link" and \c "lld". The following example demonstrates how to change the linker for different toolchains: diff --git a/doc/reference/modules/exporter-cmake.qdoc b/doc/reference/modules/exporter-cmake.qdoc new file mode 100644 index 000000000..2f4191a76 --- /dev/null +++ b/doc/reference/modules/exporter-cmake.qdoc @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2024 Raphael Cotty (raphael.cotty@gmail.com) +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \qmltype Exporter.cmake + \inqmlmodule QbsModules + \since Qbs 2.3 + + \brief Provides support for generating \CMAKE packages from dynamic, static and header library + products. + + The Exporter.cmake module contains the properties and rules to create a \CMAKE config + \l{https://cmake.org/cmake/help/v3.29/manual/cmake-packages.7.html#config-file-packages}{files} + from the \l Export item of a \l Product. + + For instance, suppose you are creating a library. To allow exporting to \CMAKE, you would write + something like the following: + \code + DynamicLibrary { + name: "mylibrary" + qbs.installPrefix: "/opt/mylibrary" + Depends { name: "Exporter.cmake" } + Exporter.cmake.packageName: "MyLibrary" + property string headersInstallDir: "include" + // ... + Group { + name: "API headers" + files: ["mylib.h"] + qbs.install: true + qbs.installDir: headersInstallDir + } + Group { + fileTagsFilter: ["Exporter.cmake.package"] + qbs.installDir: "lib/cmake/MyLibrary" + } + Export { + Depends { name: "cpp" } + cpp.includePaths: FileInfo.joinPaths( + exportingProduct.qbs.installRoot, + exportingProduct.qbs.installPrefix, + exportingProduct.headersInstallDir) + } + } + \endcode + To build against this library, from within your \CMAKE project, you simply + use \l{https://cmake.org/cmake/help/v3.29/command/find_package.html}{find_package}: + \code + find_package(MyLibrary PATHS REQUIRED) + add_executable(Consumer main.cpp) + target_link_libraries(Consumer MyLibrary) + \endcode + + \section2 Relevant File Tags + \target filetags-exporter-qbs + + \table + \header + \li Tag + \li Since + \li Description + \row + \li \c{"Exporter.cmake.package"} + \li 2.3.0 + \li This tag is attached to all generated module files. + \row + \li \c{"Exporter.cmake.configFile"} + \li 2.3.0 + \li This tag is attached to the generated config file. + \row + \li \c{"Exporter.cmake.versionFile"} + \li 2.3.0 + \li This tag is attached to the generated version file. + \endtable +*/ + +/*! + \qmlproperty string Exporter.cmake::configFileName + + The name of the generated config file. + + \defaultvalue \c{packageName + "Config.cmake"} +*/ + +/*! + \qmlproperty string Exporter.cmake::versionFileName + + The name of the generated version file. + + \defaultvalue \c{packageName + "ConfigVersion.cmake"} +*/ + +/*! + \qmlproperty string Exporter.cmake::packageName + + The name of the \CMAKE package. + + \defaultvalue \l{Product::targetName}{Product.targetName} +*/ + diff --git a/doc/reference/modules/flatbuf-c-module.qdoc b/doc/reference/modules/flatbuf-c-module.qdoc new file mode 100644 index 000000000..d486ab3bf --- /dev/null +++ b/doc/reference/modules/flatbuf-c-module.qdoc @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +/*! + \qmltype flatbuf.c + \inqmlmodule QbsModules + \since Qbs 2.4 + + \brief Provides support for \l{https://google.github.io/flatbuffers/}{FlatBuffers} for the + C language. + + The \c flatbuf.c module provides support for generating C headers + and sources from flatbuffers definition files using the \c flatcc tool. + + \section2 Relevant File Tags + + \table + \header + \li Tag + \li Auto-tagged File Names + \li Since + \li Description + \row + \li \c{"flatbuffers.input"} + \li \c{*.fbs} + \li 2.4.0 + \li Source files with this tag are considered inputs to the \c flatcc compiler. + \endtable + + \section2 Dependencies + This module depends on the \c flatcc module which can be created via the \l{conan}{Conan} + module provider. +*/ + +/*! + \qmlproperty string flatbuf.c::compilerName + + The name of the \c flatcc binary. + + \defaultvalue \c "flatcc" +*/ + +/*! + \qmlproperty string flatbuf.c::compilerPath + + The path to the \c flatcc binary. + + Use this property to override the auto-detected location. + + \defaultvalue \c auto-detected +*/ + +/*! + \qmlproperty pathList flatbuf.c::importPaths + + The list of import paths that are passed to the \c flatcc tool via the \c -I option. + + \defaultvalue \c [] +*/ diff --git a/doc/reference/modules/flatbuf-cpp-module.qdoc b/doc/reference/modules/flatbuf-cpp-module.qdoc new file mode 100644 index 000000000..a4b6915ab --- /dev/null +++ b/doc/reference/modules/flatbuf-cpp-module.qdoc @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +/*! + \qmltype flatbuf.cpp + \inqmlmodule QbsModules + \since Qbs 2.4 + + \brief Provides support for \l{https://google.github.io/flatbuf/}{flatbuf} for the + C++ language. + + The \c flatbuf.cpp module provides support for generating C++ headers + and sources from flatbuf definition files using the \c flatc tool. + + A simple qbs file that uses flatbuf can be written as follows: + \code + CppApplication { + Depends { name: "flatbuf.cpp" } + files: ["foo.fbs", "main.cpp"] + } + \endcode + A generated header now can be included in the C++ sources: + \code + #include <foo_generated.h> + + int main(int argc, char* argv[]) { + flatbuf::FlatBufferBuilder builder; + + auto foo = QbsTest::CreateFoo(builder, 42); + return 0; + } + \endcode + + \section2 Relevant File Tags + + \table + \header + \li Tag + \li Auto-tagged File Names + \li Since + \li Description + \row + \li \c{"flatbuf.input"} + \li \c{*.fbs} + \li 2.4.0 + \li Source files with this tag are considered inputs to the \c flatc compiler. + \endtable + + \section2 Dependencies + This module depends on the \c flatbuffers module which can be created via the \l{conan}{Conan} + module provider. +*/ + +/*! + \qmlproperty string flatbuf.cpp::compilerName + + The name of the \c flatc binary. + + \defaultvalue \c "flatc" +*/ + +/*! + \qmlproperty string flatbuf.cpp::compilerPath + + The path to the \c flatc binary. + + Use this property to override the auto-detected location. + + \defaultvalue \c auto-detected +*/ + +/*! + \qmlproperty string flatbuf.cpp::filenameExtension + + The extension appended to the generated file names. If not specified, the default extension + (\c ".h") is used. + + This property corresponds to the \c --filename-ext option of the \c flatc tool. + + \nodefaultvalue +*/ + +/*! + \qmlproperty string flatbuf.cpp::filenameSuffix + + The suffix appended to the generated file names. If not specified, the default suffix + (\c "_generated") is used. + + This property corresponds to the \c --filename-suffix option of the \c flatc tool. + + \nodefaultvalue +*/ + +/*! + \qmlproperty pathList flatbuf.cpp::importPaths + + The list of import paths that are passed to the \c flatc tool via the \c -I option. + + \defaultvalue \c [] +*/ + +/*! + \qmlproperty string flatbuf.cpp::includePrefix + + Prefix path prepended to any generated include statements. + + This property corresponds to the \c --include-prefix option of the \c flatc tool. + + \nodefaultvalue +*/ + +/*! + \qmlproperty bool flatbuf.cpp::keepPrefix + + Whether to keep original prefix of schema include statement. + + This property corresponds to the \c --keep-prefix option of the \c flatc tool. + + \defaultvalue \c false +*/ diff --git a/doc/reference/modules/protobufcpp-module.qdoc b/doc/reference/modules/protobufcpp-module.qdoc index 85851c4ae..2c96eaeef 100644 --- a/doc/reference/modules/protobufcpp-module.qdoc +++ b/doc/reference/modules/protobufcpp-module.qdoc @@ -78,6 +78,13 @@ \li 1.18.0 \li This tag is attached to the header files generated by \c protoc compiler. \endtable + + \section2 Dependencies + + The \l protobuf.cpp module requires runtime libraries to be operational. It depends on the + \c "protobuflib" module which can be created by the \l qbspkgconfig or fallback module + providers (the corresponding packages are \c protobuf or \c protobuf-lite). If \l useGrpc is + set to true, the \l protobuf.cpp module also depends on the \c "grpc++" module. */ /*! @@ -101,24 +108,6 @@ */ /*! - \qmlproperty string protobuf.cpp::grpcIncludePath - - The path where grpc++ headers are located. Set this property to override the - default location. - - \defaultvalue \c auto-detected -*/ - -/*! - \qmlproperty string protobuf.cpp::grpcLibraryPath - - The path where the grpc++ library is located. Set this property to override the - default location. - - \defaultvalue \c auto-detected -*/ - -/*! \qmlproperty pathList protobuf.cpp::importPaths The list of imports that are passed to the \c protoc tool via the \c --proto_path option. @@ -131,24 +120,6 @@ */ /*! - \qmlproperty string protobuf.cpp::includePath - - The path where protobuf C++ headers are located. Set this property to override the - default location. - - \defaultvalue \c auto-detected -*/ - -/*! - \qmlproperty string protobuf.cpp::libraryPath - - The path where the protobuf C++ library is located. Set this property to override the - default location. - - \defaultvalue \c auto-detected -*/ - -/*! \qmlproperty string protobuf.cpp::outputDir \readonly diff --git a/doc/reference/modules/qt-core-module.qdoc b/doc/reference/modules/qt-core-module.qdoc index afc4a0f11..6aedf2a69 100644 --- a/doc/reference/modules/qt-core-module.qdoc +++ b/doc/reference/modules/qt-core-module.qdoc @@ -211,6 +211,32 @@ */ /*! + \qmlproperty string Qt.core::generatedHeadersDir + + The directory where tools that generate headers (such as \c moc or \c uic) put resulting + files. + + Normally, you don't need to change this property. The one use-case is when there are several + files with the same file name in the Product. The file name produced by \c moc is based + only on the source file's base file name (without the directory path) which leads to a conflict + in the mentioned case. You can resolve the conflict by setting this property to a non-default + value for one of the files. For example: + + \code + QtApplication { + files: ["my_cool_header.h", "main.cpp"] + Group { + name: "legacy" + files: "legacy/my_cool_header.h" + Qt.core.generatedHeadersDir: "qt.legacy.headers" + } + } + \endcode + + \defaultvalue \c product.buildDirectory + "/qt.headers" +*/ + +/*! \qmlproperty bool Qt.core::metaTypesInstallDir The directory to install the metatypes file into. If this property is empty or undefined, @@ -352,6 +378,14 @@ */ /*! + \qmlproperty string Qt.core::qdocOutputDir + + The directory name where the \c qdoc tool writes its output. + + \defaultvalue \c{product.buildDirectory + "/qdoc_html"} +*/ + +/*! \qmlproperty string Qt.core::qmBaseName The base name of the \c .qm file to be built from the \c .ts files in the @@ -363,6 +397,14 @@ */ /*! + \qmlproperty string Qt.core::qmDir + + The directory name where to put the \c .qm file to be built. + + \defaultvalue \l{Product::destinationDirectory}{product.destinationDirectory} +*/ + +/*! \qmlproperty string Qt.core::qtBuildVariant Specifies the type of Qt libraries to build against: \c "debug" or @@ -468,3 +510,11 @@ \defaultvalue \c{versionParts[2]} */ + +/*! + \qmlproperty bool Qt.core::useRPaths + + Whether to add \l{Qt.core::libPath}{Qt.core.libPath} to \l{cpp::rpaths}{cpp.rpaths}. + + \defaultvalue \c true on Linux, \c false everywhere else. +*/ diff --git a/doc/tutorial.qdoc b/doc/tutorial.qdoc new file mode 100644 index 000000000..b17cf4faf --- /dev/null +++ b/doc/tutorial.qdoc @@ -0,0 +1,647 @@ +/**************************************************************************** +** +** 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} + \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, the \l{Application::install}{CppApplication.install} property is \c false and thus + \QBS does not install the binary. If the \l{Application::install}{install} property is + \c true, when building a project, \QBS will also install it 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. The \l{Application::install}{install} property should + be set to \c true for all products that are to be distributed. + 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{Application::install}{install}, + \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. + We also use the \l{Application::installDebugInformation}{installDebugInformation} + property here. By default, it has the same value as \l{Application::install}{install} but we + want to make the debug information install optional. + + 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 Buildconfig 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. + + You can also use a \l{Module} that \l{Product}{products} may depend on. That way, a + \l{Product} only uses properties of the module it depends on without the need to know about + the top-level project. + + Let's create a file named \c{mybuildconfig.qbs} and put it into the + \c{qbs/modules/mybuildconfig} directory, near the \c{qbs/imports} directory: + \code + // qbs/modules/mybuildconfig.qbs + Module { + } + \endcode + + So far, this is just an empty \l{Module} so let's add some properties to it: + \snippet ../tutorial/chapter-7/qbs/modules/mybuildconfig/mybuildconfig.qbs 0 + + We added the \c appInstallDir and \c libInstallDir properties that will allow us to configure + the installation location of the our application and library, respectively. + + Now we can use our module in the \c{MyApplication.qbs} item: + \snippet ../tutorial/chapter-7/qbs/imports/MyApplication.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 also set the \l{Application::installDir}{installDir} + property to the corresponding module property, namely to \c{mybuildconfig.appInstallDir}. + + \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/modules/mybuildconfig/mybuildconfig.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 \c{libInstallDir}). 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{mybuildconfig} module. + + Now, we can also use our new module in the library item: + \snippet ../tutorial/chapter-7/qbs/imports/MyLibrary.qbs 0 + + Let's change the library folder name from \c{"lib"} to \c{"lib64"} when building our project: + \code + $ qbs modules.mybuildconfig.libDirName:lib64 + ... + $ ls default/install-root/usr/local/ + bin lib64 + \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. We will add configuration options + to be able to choose between static and dynamic builds. + + We start with some new properties in the \c mybuildconfig module: + \code + Module { + ... + property bool staticBuild: false + property bool installStaticLib: true + ... + } + \endcode + + 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 the \l{Product::type}{type} of the product so it depends on the \c staticBuild + property: + \code + type: mybuildconfig.staticBuild ? "staticlibrary" : "dynamiclibrary" + \endcode + + Third, 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: mybuildconfig.staticBuild ? [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.mybuildconfig.staticBuild + ? [exportingProduct.staticLibraryMacro] : [] + } + \endcode + + Now we can build our project in dynamic or static mode: + \code + $ qbs resolve modules.mybuildconfig.staticBuild:false && 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.mybuildconfig.staticBuild:true && qbs build + ... + $ $ ls default/install-root/usr/local/lib/ + libmylib.a + \endcode +*/ + +/*! + \previouspage tutorial-8.html + \page tutorial-9.html + \nextpage howtos.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 mybuildconfig module: + \snippet ../tutorial/chapter-9/qbs/modules/mybuildconfig/mybuildconfig.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 mybuildconfig module to use the new + \c mybuildconfig.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.mybuildconfig.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 +*/ |