Qbs Quick Reference: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
(Use syntaxhighlight tag)
 
(12 intermediate revisions by 11 users not shown)
Line 1: Line 1:
{{LangSwitch}}
{{LangSwitch}}
[[Category:Tools::qbs]]
[[Category:Tools::qbs]]
{{WarningBox|text=On October 29th, 2018, The Qt Company announced that Qbs is [https://blog.qt.io/blog/2018/10/29/deprecation-of-qbs/ deprecated].}}


== Introduction ==
== Introduction ==
Line 12: Line 14:
The full Qbs Manual is found at http://doc.qt.io/qbs
The full Qbs Manual is found at http://doc.qt.io/qbs


== qbs equivalents ==
== Migrating from other build systems ==
 
=== TEMPLATE = app ===
 
Use Application or CppApplication as the product:
 
<code>CppApplication {
name: "helloworld"
files: "main.cpp"
}
</code>
 
This is roughly equivalent to:
 
<code>Product {
name: "helloworld"
type: "application"
files: "main.cpp"
Depends { name: "cpp" }
}
</code>
 
 
=== TEMPLATE = lib ===
 
Use DynamicLibrary as the product:
 
<code>
DynamicLibrary {
name: "mydll"
files: ["stuff.cpp"]
Depends { name: "cpp" }
}
</code>
 
=== TARGET = myappname ===
 
Use the "name" property, see the TEMPLATE example above.
 
=== HEADERS, SOURCES, FORMS, RESOURCES ===
 
Include in files section, eg
 
<code>files: ['thing.h', 'thing.cpp', 'thing.ui', 'myapp.qrc']
</code>
 
qbs will use file taggers to figure out what kind of file it is dealing with.
 
=== CONFIG = console ===
 
<code>Application {
name: "helloworld"
files: "main.cpp"
consoleApplication: true
}
</code>
 
=== CONFIG = designer_defines ===
 
<code>DynamicLibrary {
name: "myplugin"
files: ["foo.cpp", …]
Depends { name: "cpp" }
cpp.defines: ["QDESIGNER_EXPORT_WIDGETS"]
}
</code>
 
=== QT = modulename ===
 
Add an appropriate Depends section to the product. For example:
 
<code>Product {
Depends { name: "Qt.core" }
// …or…
Depends { name: "Qt"; submodules: ["core", "gui", "network"] }
}
</code>
 
Both forms are equivalent, the first form being quicker to type if you depend on just one module and the second more flexible if you have more complex dependencies.
 
=== DEFINES = MACRO ===
 
Use the following: Note that in order to reference cpp.defines you must specify a dependency on the cpp module.
<code>Depends { name: 'cpp' }
cpp.defines: ['SUPPORT_COOL_STUFF']
</code>
 
The cpp module might define default preprocessor macros. For example on Windows UNICODE is predefined.
These are stored in the property cpp.platformDefines.
To override these macros do:
<code>Product {
Depends { name: 'cpp' }
cpp.platformDefines: ['MY_SPECIAL_DEFINE', 'UNICODE']
</code>
 
To add macros within a group, you need to use outer.concat rather than base.concat(), because you are adding additional macros to what is specified in the outer scope:
 
<code>Product {
Depends { name: 'cpp' }
cpp.defines: ['MACRO_EVERYWHERE'] // This is defined for all files in this product (unless a group overrides it!)
Group {
cpp.defines: outer.concat('MACRO_GROUP')
files: groupFile.cpp
// MACRO_GROUP is only defined in groupFile.cpp
// MACRO_EVERYWHERE is also defined in groupFile.cpp because of the outer.concat
}
}
</code>
 
cpp.defines statements inside a group only apply to the files in that group - therefore you cannot use a group to include a bunch of files and globally-visible macros - the macros must go in a Properties block at the same level as the group if they need to be visible to files outside the group:
 
<code>Product {
Depends { name: 'cpp' }
Group {
condition: supportFoobar === true
files: fooFile.cpp
}
 
property stringList commonDefines: ["ONE", "TWO"]
Properties {
condition: supportFoobar === true
cpp.defines: commonDefines.concat("FOOBAR_SUPPORTED")
}
Properties {
cpp.defines: commonDefines // else case for the Properties chain
}
}
</code>
 
=== INCLUDEPATH = dir ===
 
<code>cpp.includePaths: [ '..', 'some/other/dir']</code>
 
=== CONFIG -= Qt ===
 
Just don't declare Qt as a dependency. Probably you'd want:
 
<code>Depends { name: "cpp" }</code>
 
=== RC_FILE ===
 
Just add the file to the "files" list.
 
=== QMAKE_INFO_PLIST ===
 
Set the cpp.infoPlistFile property.
 
=== ICON ===
 
Not yet implemented. See [https://bugreports.qt.io/browse/QBS-73 QBS-73].
 
=== TEMPLATE = subdirs ===
 
Inside a "Project" item, use "references":
 
<code>Project {
references: [
"app/app.qbs",
"lib/lib.qbs"
]
}
</code>
 
=== CONFIG = ordered ===
QBS uses a different approach of deciding in which order subprojects are compiled than qmake.
Instead of referencing them in order in .qbs file user needs to add Depends sections into subprojects.
<code>
Depends{name: "subproject"}
</code>


QBS then parses all of the included qbs files and computes what should be compiled first based on those Depends.
For up-to-date information, see:


For example considering the Project in the previous section:  
[http://doc-snapshots.qt.io/qbs/porting-to-qbs.html#migrating-from-qmake Migrating from qmake]
 
<code>
-- in app.qbs --
Product{
name:"app"
Depends{name: "lib"}
}
 
-- in lib.qbs --
Product{
name:"lib"
}
</code>
Lib will automatically be compiled first.
 
=== DESTDIR ===
 
Use the destinationDirectory property:
 
<code>
DynamicLibrary {
name: "mydll"
destinationDirectory: "libDir"
}
</code>
 
Using it is not recommended, however; you should rather use the installation mechanism (see below).
 
=== message(), warning(), error() ===
 
You can use the JavaScript function print for printing messages and throw exceptions on the right hand side of property bindings.
 
<code>Product {
name: {
print("—-> now evaluating the product name");
return "theName";
}
Depends {name: "cpp"}
cpp.includePath: {
throw "I don't know. Something bad happened."
return [];
}
}</code>
 
 
=== Others not mentioned above ===
 
Either I've missed them, or they're not yet implemented.


== .pro and .pri ==
== .pro and .pri ==
Line 250: Line 26:
.qbs files can also be used like .pri files in that a top-level .qbs can include sections defined in another .qbs. For example:
.qbs files can also be used like .pri files in that a top-level .qbs can include sections defined in another .qbs. For example:


<code>
<syntaxhighlight lang="qml">
—CrazyProduct.qbs—
/* CrazyProduct.qbs */
import qbs.base 1.0
import qbs.base 1.0


Product {
Product {
property string craziness: "low"
  property string craziness: "low"
}
}


—hellocrazyworld.qbs—
/* hellocrazyworld.qbs */
CrazyProduct {
CrazyProduct {
craziness: "enormous"
  craziness: "enormous"
name: "hellocrazyworld"
  name: "hellocrazyworld"
// …
  // …
}
}
</code>
</syntaxhighlight>


.qbs files in the same directory as the top-level .qbs file are picked up automatically. Others must be explicitly imported and named using an "import … as …" statement:
.qbs files in the same directory as the top-level .qbs file are picked up automatically. Others must be explicitly imported and named using an "import … as …" statement:


<code>
<syntaxhighlight lang="qml">
import qbs.base 1.0
import qbs.base 1.0
import "../CrazyProduct.qbs" as CrazyProduct
import "../CrazyProduct.qbs" as CrazyProduct
CrazyProduct {
CrazyProduct {
craziness: "enormous"
  craziness: "enormous"
name: "hellocrazyworld"
  name: "hellocrazyworld"
// …
  // …
}
}
</code>
</syntaxhighlight>




It is also possible pick groups of source files externally like with .pri files, by importing a .qbs with a Group defined in it and declaring this imported group inside the Product declaration.
It is also possible pick groups of source files externally like with .pri files, by importing a .qbs with a Group defined in it and declaring this imported group inside the Product declaration.


<code>
<syntaxhighlight lang="qml">
-- in external.qbs file--
/* external.qbs */
import qbs
import qbs
Group{
Group {
files:["file1.cpp", "file2.cpp"]
  files: ["file1.cpp", "file2.cpp"]
}
}
-- in product.qbs file--
 
/* product.qbs */
import qbs
import qbs
import external.qbs as SourceGroup
import "external.qbs" as SourceGroup
Product{
 
name: "SomeProduct"
Product {
SourceGroup{}
  name: "SomeProduct"
  SourceGroup {}
}
}
</syntaxhighlight>
If opened with qtcreator, files from external.qbs will be visible in a group belonging to SomeProduct
If opened with qtcreator, files from external.qbs will be visible in a group belonging to SomeProduct
</code>


== Conditionals ==
== Conditionals ==
Line 302: Line 81:
Instead of the qmake syntax of "windows { … }" or "macx:…", you specify a "condition" property in the relevant block. Conditionally-compiled files should be collected in a "Group" block, while platform-specific properties should go in a "Properties" block rather than being put in the main (outer) block:
Instead of the qmake syntax of "windows { … }" or "macx:…", you specify a "condition" property in the relevant block. Conditionally-compiled files should be collected in a "Group" block, while platform-specific properties should go in a "Properties" block rather than being put in the main (outer) block:


<code>
<syntaxhighlight lang="qml">
Group {
Group {
condition: qbs.targetOS == "windows"
  condition: qbs.targetOS.contains("windows")
files: [
  files: [
"harddiskdeleter_win.cpp",
    "harddiskdeleter_win.cpp",
"blowupmonitor_win.cpp",
    "blowupmonitor_win.cpp",
"setkeyboardonfire_win.cpp"
    "setkeyboardonfire_win.cpp"
]
  ]
}
}


Properties {
Properties {
condition: qbs.targetOS == "linux"
  condition: qbs.targetOS.contains("linux")
cpp.defines: outer.concat([ "USE_BUILTIN_DESTRUCTORS"])
  cpp.defines: outer.concat(["USE_BUILTIN_DESTRUCTORS"])
}
}
</code>
</syntaxhighlight>


See the DEFINES section above for important information about how conditionals and cpp.defines interact.
See the DEFINES section above for important information about how conditionals and cpp.defines interact.
Line 324: Line 103:
Here is a selection of options that are supported. The full list can be found in share/qbs/modules/cpp/CppModule.qbs in the qbs source tree, these are some of the more useful:
Here is a selection of options that are supported. The full list can be found in share/qbs/modules/cpp/CppModule.qbs in the qbs source tree, these are some of the more useful:


<code>
<syntaxhighlight lang="qml">
cpp.optimization: "none" // or "fast"
cpp.optimization: "none" // or "fast"
cpp.debugInformation: true
cpp.debugInformation: true
cpp.staticLibraries: "libraryName"
cpp.staticLibraries: "libraryName"
cpp.dynamicLibraries: "libraryName"
cpp.dynamicLibraries: "libraryName"
cpp.frameworks: "osxFrameworkName"
cpp.frameworks: "frameworkName"
cpp.precompiledHeader: "myheader.pch"
cpp.precompiledHeader: "myheader.pch"
cpp.warningLevel: "all" // or "none", "default"
cpp.warningLevel: "all" // or "none", "default"
cpp.treatWarningsAsErrors: true
cpp.treatWarningsAsErrors: true
cpp.cxxLanguageVersion // E.g. "c++11"
cpp.cxxLanguageVersion // E.g. "c++11"
</code>
</syntaxhighlight>


Note that setting things like cflags directly is discouraged (because they are compiler-dependent), and higher-level alternatives like cpp.optimization: "fast" should be used if available.
Note that setting things like cflags directly is discouraged (because they are compiler-dependent), and higher-level alternatives like cpp.optimization: "fast" should be used if available.
Line 342: Line 121:
Create a group containing the files, and set qbs.install and qbs.installDir:
Create a group containing the files, and set qbs.install and qbs.installDir:


<code>
<syntaxhighlight lang="qml">
Group {
Group {
qbs.install: true
  qbs.install: true
qbs.installDir: "lib/myproj/"
  qbs.installDir: "lib/myproj/"
files: [
  files: [
"Menu.qml",
    "Menu.qml",
"SomeImportantFile.bin"
    "SomeImportantFile.bin"
]
  ]
}
}
</code>
</syntaxhighlight>


For files generated by the build (e.g. an executable), you need to match them by their file tag:
For files generated by the build (e.g. an executable), you need to match them by their file tag:
<code>
 
<syntaxhighlight lang="qml">
Group {
Group {
qbs.install: true
  qbs.install: true
qbs.installDir: "bin"
  qbs.installDir: "bin"
fileTagsFilter: "application"
  fileTagsFilter: "application"
}
}
</code>
</syntaxhighlight>


By default, installation happens automatically when building. The default installation root is called
By default, installation happens automatically when building. The default installation root is called
Line 369: Line 149:


64-bit:
64-bit:
<code>qbs -f /path/to/project.qbs --products productname qbs.architecture:x86_64
 
</code>
<syntaxhighlight lang="sh">
$ qbs -f /path/to/project.qbs --products productname qbs.architecture:x86_64
</syntaxhighlight>


== "Magic" variables ==
== "Magic" variables ==
Line 378: Line 160:
=== qbs ===
=== qbs ===


This has lots of useful things in, such as: targetOS ("windows", "linux", "osx", …); buildVariant ("debug", "release"); architecture ("x86", "x86_64", …)
This has lots of useful things in, such as: targetOS ("windows", "linux", "darwin", …); buildVariant ("debug", "release"); architecture ("x86", "x86_64", …)


=== project ===
=== project ===
Line 384: Line 166:
Valid anywhere in your project, needed to refer to project properties from within a product:
Valid anywhere in your project, needed to refer to project properties from within a product:


<code>Project {
<syntaxhighlight lang="qml">
property string version: "1.0"
Project {
  property string version: "1.0"


Product {
  Product {
cpp.defines: ["PROJECT_VERSION=" + project.version]
    cpp.defines: ["PROJECT_VERSION=" + project.version]
}
  }
}
}
</code>
</syntaxhighlight>


=== buildDirectory ===
=== buildDirectory ===
Line 402: Line 185:
Modules that are declared as dependencies can be referred to by their name and their properties accessed. For example:
Modules that are declared as dependencies can be referred to by their name and their properties accessed. For example:


<code>Product {
<syntaxhighlight lang="qml">
Depends { name: "Qt.quick" }
Product {
Qt.quick.qmlDebugging: false
  Depends { name: "Qt.quick" }
}
  Qt.quick.qmlDebugging: false
</code>
 
=== Inside custom javascript ===
 
Generally when writing custom JavaScript logic, things are referenced through the top-level "product" variable. In particular, to get the product's value of the property "baz" of a module "foo", use product.moduleProperty("foo", "baz"). For list values that get automatically combined, like includePaths, use product.moduleProperties("foo", "baz").
 
<code>Group {
condition: qbs.targetOS === "windows"
files: [ "hcf.cpp" ]
}
</code>
 
and
 
<code>Group {
files: {
if (product.moduleProperty("qbs", "targetOS") === "windows") {
return [ "hcf.cpp" ];
} else {
return [];
}
}
}
}
</code>
</syntaxhighlight>

Latest revision as of 14:18, 20 September 2021

En Ar Bg De El Es Fa Fi Fr Hi Hu It Ja Kn Ko Ms Nl Pl Pt Ru Sq Th Tr Uk Zh

On October 29th, 2018, The Qt Company announced that Qbs is deprecated.

Introduction

Qbs is the next-generation build system "initially introduced in the Qt Labs Blog. This page is intended as a quick guide to porting project files from qmake .pro syntax to .qbs. It is not intended to supplant the official documentation, rather to be a quick summary of the current status of qbs functionality with a focus on how to port from qmake.

Some things at the time of writing have no equivalent qbs syntax. Bugtracker links are included for missing functionality, where known.

Qbs Manual

The full Qbs Manual is found at http://doc.qt.io/qbs

Migrating from other build systems

For up-to-date information, see:

Migrating from qmake

.pro and .pri

The top-level .qbs file contains the "Project" definition. A project can contain multiple products, so you may find that multiple .pro files can be expressed in a single .qbs. The subdirs pattern will typically convert to a single .qbs containing references to multiple .qbs files. Each .qbs file would then define a single product or sub-project.

.qbs files can also be used like .pri files in that a top-level .qbs can include sections defined in another .qbs. For example:

/* CrazyProduct.qbs */
import qbs.base 1.0

Product {
  property string craziness: "low"
}

/* hellocrazyworld.qbs */
CrazyProduct {
  craziness: "enormous"
  name: "hellocrazyworld"
  // …
}

.qbs files in the same directory as the top-level .qbs file are picked up automatically. Others must be explicitly imported and named using an "import … as …" statement:

import qbs.base 1.0
import "../CrazyProduct.qbs" as CrazyProduct

CrazyProduct {
  craziness: "enormous"
  name: "hellocrazyworld"
  // …
}


It is also possible pick groups of source files externally like with .pri files, by importing a .qbs with a Group defined in it and declaring this imported group inside the Product declaration.

/* external.qbs */
import qbs
Group {
  files: ["file1.cpp", "file2.cpp"]
}

/* product.qbs */
import qbs
import "external.qbs" as SourceGroup

Product {
  name: "SomeProduct"
  SourceGroup {}
}

If opened with qtcreator, files from external.qbs will be visible in a group belonging to SomeProduct

Conditionals

Instead of the qmake syntax of "windows { … }" or "macx:…", you specify a "condition" property in the relevant block. Conditionally-compiled files should be collected in a "Group" block, while platform-specific properties should go in a "Properties" block rather than being put in the main (outer) block:

Group {
  condition: qbs.targetOS.contains("windows")
  files: [
    "harddiskdeleter_win.cpp",
    "blowupmonitor_win.cpp",
    "setkeyboardonfire_win.cpp"
  ]
}

Properties {
  condition: qbs.targetOS.contains("linux")
  cpp.defines: outer.concat(["USE_BUILTIN_DESTRUCTORS"])
}

See the DEFINES section above for important information about how conditionals and cpp.defines interact.

C++ compiler options

Here is a selection of options that are supported. The full list can be found in share/qbs/modules/cpp/CppModule.qbs in the qbs source tree, these are some of the more useful:

cpp.optimization: "none" // or "fast"
cpp.debugInformation: true
cpp.staticLibraries: "libraryName"
cpp.dynamicLibraries: "libraryName"
cpp.frameworks: "frameworkName"
cpp.precompiledHeader: "myheader.pch"
cpp.warningLevel: "all" // or "none", "default"
cpp.treatWarningsAsErrors: true
cpp.cxxLanguageVersion // E.g. "c++11"

Note that setting things like cflags directly is discouraged (because they are compiler-dependent), and higher-level alternatives like cpp.optimization: "fast" should be used if available.

Installing files

Create a group containing the files, and set qbs.install and qbs.installDir:

Group {
  qbs.install: true
  qbs.installDir: "lib/myproj/"
  files: [
    "Menu.qml",
    "SomeImportantFile.bin"
  ]
}

For files generated by the build (e.g. an executable), you need to match them by their file tag:

Group {
  qbs.install: true
  qbs.installDir: "bin"
  fileTagsFilter: "application"
}

By default, installation happens automatically when building. The default installation root is called "install_root" and is located at the top level of the build directory. It can be overwritten by setting the qbs.installRoot property on the command line.

Command-line examples

64-bit:

$ qbs -f /path/to/project.qbs --products productname qbs.architecture:x86_64

"Magic" variables

Variables defined in various scopes, which may not be obvious:

qbs

This has lots of useful things in, such as: targetOS ("windows", "linux", "darwin", …); buildVariant ("debug", "release"); architecture ("x86", "x86_64", …)

project

Valid anywhere in your project, needed to refer to project properties from within a product:

Project {
  property string version: "1.0"

  Product {
    cpp.defines: ["PROJECT_VERSION=" + project.version]
  }
}

buildDirectory

The top-level build directory. By default will be a subdirectory in the directory where you invoked qbs from, whose name is derived from the current profile. It can also be explicitly specified via the -d option.

Module names

Modules that are declared as dependencies can be referred to by their name and their properties accessed. For example:

Product {
  Depends { name: "Qt.quick" }
  Qt.quick.qmlDebugging: false
}