Qt wiki will be updated on October 12th 2023 starting at 11:30 AM (EEST) and the maintenance will last around 2-3 hours. During the maintenance the site will be unavailable.

Qbs Quick Reference: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 1: Line 1:
[[Category:Tools::qbs]]
[[Category:Tools::qbs]]


[toc align_right="yes" depth="2"]
[toc align_right="yes" depth="2"]


= Introduction =
= Introduction =


Qbs is the next-generation build system "initially introduced in the Qt Labs Blog":https://blog.qt.io/blog/2012/02/15/introducing-qbs/. 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.
Qbs is the next-generation build system "initially introduced in the Qt Labs Blog":https://blog.qt.io/blog/2012/02/15/introducing-qbs/. 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. And finally this is based on my incomplete current understanding of qbs, so there may be errors or indeed things which have changed by the time you read this :)
Some things at the time of writing have no equivalent qbs syntax. Bugtracker links are included for missing functionality, where known. And finally this is based on my incomplete current understanding of qbs, so there may be errors or indeed things which have changed by the time you read this :)
Line 19: Line 19:
Use Application or CppApplication as the product:
Use Application or CppApplication as the product:


<code>CppApplication {<br /> name: &quot;helloworld&amp;quot;<br /> files: &quot;main.cpp&amp;quot;<br /> <br />}<br /></code>
<code>CppApplication {
name: "helloworld"
files: "main.cpp"
}
</code>


This is roughly equivalent to:
This is roughly equivalent to:


<code>Product {<br /> name: &quot;helloworld&amp;quot;<br /> type: &quot;application&amp;quot;<br /> files: &quot;main.cpp&amp;quot;<br /> Depends { name: &quot;cpp&amp;quot; }<br /> <br />}<br /></code>
<code>Product {
name: "helloworld"
type: "application"
files: "main.cpp"
Depends { name: "cpp" }
}
</code>


except that in the first example, the type is &quot;applicationbundle&amp;quot; on OSX.
except that in the first example, the type is "applicationbundle" on OSX.


== TEMPLATE = lib ==
== TEMPLATE = lib ==
Line 31: Line 43:
Use DynamicLibrary as the product:
Use DynamicLibrary as the product:


<code><br />DynamicLibrary {<br /> name: &quot;mydll&amp;quot;<br /> files: [&quot;stuff.cpp&amp;quot;]<br /> Depends { name: &quot;cpp&amp;quot; }<br /> <br />}<br /></code>
<code>
DynamicLibrary {
name: "mydll"
files: ["stuff.cpp"]
Depends { name: "cpp" }
}
</code>


== TARGET = myappname ==
== TARGET = myappname ==


Use the &quot;name&amp;quot; property, see the TEMPLATE example above.
Use the "name" property, see the TEMPLATE example above.


== HEADERS, SOURCES, FORMS, RESOURCES ==
== HEADERS, SOURCES, FORMS, RESOURCES ==
Line 41: Line 60:
Include in files section, eg
Include in files section, eg


<code>files: ['thing.h', 'thing.cpp', 'thing.ui', 'myapp.qrc']<br /></code>
<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.
qbs will use file taggers to figure out what kind of file it is dealing with.


== CONFIG ''= console
== CONFIG ''= console
<br /><code>Application {<br /> name: &quot;helloworld&amp;quot;<br /> files: &quot;main.cpp&amp;quot;<br /> consoleApplication: true<br /> …<br />}<br /></code>
<br />h2. CONFIG''= designer_defines ==


<code>DynamicLibrary {<br /> name: &quot;myplugin&amp;quot;<br /> files: [&quot;foo.cpp&amp;quot;, …]<br /> Depends { name: &quot;cpp&amp;quot; }<br /> cpp.defines: [&quot;QDESIGNER_EXPORT_WIDGETS&amp;quot;]<br /> <br />}<br /></code>
<code>Application {
name: "helloworld"
files: "main.cpp"
consoleApplication: true
}
</code>
 
h2. CONFIG''= designer_defines ==
 
<code>DynamicLibrary {
name: "myplugin"
files: ["foo.cpp", …]
Depends { name: "cpp" }
cpp.defines: ["QDESIGNER_EXPORT_WIDGETS"]
}
</code>


== QT ''= modulename
== QT ''= modulename
<br />Add an appropriate Depends section to the product. For example:
<br /><code>Product {<br /> Depends { name: &quot;Qt.core&amp;quot; }<br /> // …or…<br /> Depends { name: &quot;Qt&amp;quot;; submodules: [&quot;core&amp;quot;, &quot;gui&amp;quot;, &quot;network&amp;quot;] }<br />}<br /></code>
<br />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.
<br />h2. DEFINES''= MACRO ==


Use the following: Note that in order to reference cpp.defines you must specify a dependency on the cpp module.<br /><code>Depends { name: 'cpp' }<br />…<br />cpp.defines: ['SUPPORT_COOL_STUFF']<br /></code>
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>


The cpp module might define default preprocessor macros. For example on Windows UNICODE is predefined.<br />These are stored in the property cpp.platformDefines.<br />To override these macros do:<br /><code>Product {<br /> Depends { name: 'cpp' }<br /> <br /> cpp.platformDefines: ['MY_SPECIAL_DEFINE', 'UNICODE']<br /></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.
 
h2. 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:
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 {<br /> Depends { name: 'cpp' }<br /> <br /> cpp.defines: ['MACRO_EVERYWHERE'] // This is defined for all files in this product (unless a group overrides it!)<br /> Group {<br /> cpp.defines: outer.concat('MACRO_GROUP')<br /> files: groupFile.cpp<br /> // MACRO_GROUP is only defined in groupFile.cpp<br /> // MACRO_EVERYWHERE is also defined in groupFile.cpp because of the outer.concat<br /> }<br />}<br /></code>
<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:
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 {<br /> Depends { name: 'cpp' }<br /> <br /> Group {<br /> condition: supportFoobar === true<br /> files: fooFile.cpp<br /> }
<code>Product {
Depends { name: 'cpp' }
Group {
condition: supportFoobar === true
files: fooFile.cpp
}


property stringList commonDefines: [&quot;ONE&amp;quot;, &quot;TWO&amp;quot;]<br /> Properties {<br /> condition: supportFoobar === true<br /> cpp.defines: commonDefines.concat(&quot;FOOBAR_SUPPORTED&amp;quot;)<br /> }<br /> Properties {<br /> cpp.defines: commonDefines // else case for the Properties chain<br /> }<br />}<br /></code>
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
== INCLUDEPATH ''= dir
<br /><code>cpp.includePaths: [ '..', 'some/other/dir']<code>
<br />h2. CONFIG <s>= Qt
<br />Just don't declare Qt as a dependency. Probably you'd want:
<br /></code>Depends { name: &quot;cpp&amp;quot; }</code>
<br />h2. RC_FILE
<br />Just add the file to the &quot;files&amp;quot; list.
<br />h2. QMAKE_INFO_PLIST
<br />Set the cpp.infoPlistFile property.
<br />h2. ICON,
<br />Not yet implemented. See &quot;QBS-73&amp;quot;:https://bugreports.qt.io/browse/QBS-73.
<br />h2. TEMPLATE = subdirs
<br />Inside a &quot;Project&amp;quot; item, use &quot;references&amp;quot;:
<br /><code>Project {<br /> references: [<br /> &quot;app/app.qbs&amp;quot;,<br /> &quot;lib/lib.qbs&amp;quot;<br /> ]<br />}<br /></code>
<br />h2. DESTDIR
<br />Use the destinationDirectory property:
<br /><code><br />DynamicLibrary {<br /> name: &quot;mydll&amp;quot;<br /> destinationDirectory: &quot;libDir&amp;quot;<br /> …<br />}<br /></code>
<br />h2. message(), warning(), error()
<br />You can use the JavaScript function print for printing messages and throw exceptions on the right hand side of property bindings.
<br /><code>Product {<br /> name: {<br /> print(&quot;—</s>&amp;gt; now evaluating the product name&amp;quot;);<br /> return &quot;theName&amp;quot;;<br /> }<br /> Depends {name: &quot;cpp&amp;quot;}<br /> cpp.includePath: {<br /> throw &quot;I don't know. Something bad happened.&quot;<br /> return [];<br /> }<br />}</code>


<br />h2. Others not mentioned above
<code>cpp.includePaths: [ '..', 'some/other/dir']<code>
<br />Either I've missed them, or they're not yet implemented.
 
<br />h1. .pro and .pri
h2. CONFIG -= Qt
<br />The top-level .qbs file contains the &quot;Project&amp;quot; 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.
 
<br />.qbs files can also be used like .pri files in that a top-level .qbs can include sections defined in another .qbs. For example:
Just don't declare Qt as a dependency. Probably you'd want:
<br /><code><br /> —CrazyProduct.qbs—<br /> import qbs.base 1.0
 
<br /> Product {<br /> property string craziness: &quot;low&amp;quot;<br /> }
</code>Depends { name: "cpp" }</code>
<br /> —hellocrazyworld.qbs—<br /> CrazyProduct {<br /> craziness: &quot;enormous&amp;quot;<br /> name: &quot;hellocrazyworld&amp;quot;<br /> // …<br /> }<br /></code>
 
<br />.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 &quot;import … as …&quot; statement:
h2. RC_FILE
<br /><code><br />import qbs.base 1.0<br />import &quot;../CrazyProduct.qbs&amp;quot; as CrazyProduct<br />CrazyProduct {<br /> craziness: &quot;enormous&amp;quot;<br /> name: &quot;hellocrazyworld&amp;quot;<br /> // …<br />}<br /></code>
 
<br />h1. Conditionals
Just add the file to the "files" list.
<br />Instead of the qmake syntax of &quot;windows { … }&quot; or &quot;macx:…&quot;, you specify a &quot;condition&amp;quot; property in the relevant block. Conditionally-compiled files should be collected in a &quot;Group&amp;quot; block, while platform-specific properties should go in a &quot;Properties&amp;quot; block rather than being put in the main (outer) block:
 
<br /><code><br />Group {<br /> condition: qbs.targetOS == &quot;windows&amp;quot;<br /> files: [<br /> &quot;harddiskdeleter_win.cpp&amp;quot;,<br /> &quot;blowupmonitor_win.cpp&amp;quot;,<br /> &quot;setkeyboardonfire_win.cpp&amp;quot;<br /> ]<br />}
h2. QMAKE_INFO_PLIST
<br />Properties {<br /> condition: qbs.targetOS == &quot;linux&amp;quot;<br /> cpp.defines: outer.concat([ &quot;USE_BUILTIN_DESTRUCTORS&amp;quot;])<br />}<br /></code>
 
<br />See the DEFINES section above for important information about how conditionals and cpp.defines interact.
Set the cpp.infoPlistFile property.
<br />h1. C''+ compiler options ==
 
h2. ICON,
 
Not yet implemented. See "QBS-73":https://bugreports.qt.io/browse/QBS-73.
 
h2. TEMPLATE = subdirs
 
Inside a "Project" item, use "references":
 
<code>Project {
references: [
"app/app.qbs",
"lib/lib.qbs"
]
}
</code>
 
h2. DESTDIR
 
Use the destinationDirectory property:
 
<code>
DynamicLibrary {
name: "mydll"
destinationDirectory: "libDir"
}
</code>
 
h2. 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>
 
 
h2. Others not mentioned above
 
Either I've missed them, or they're not yet implemented.
 
h1. .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:
 
<code>
—CrazyProduct.qbs—
import qbs.base 1.0
 
Product {
property string craziness: "low"
}
 
—hellocrazyworld.qbs—
CrazyProduct {
craziness: "enormous"
name: "hellocrazyworld"
// …
}
</code>
 
.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>
import qbs.base 1.0
import "../CrazyProduct.qbs" as CrazyProduct
CrazyProduct {
craziness: "enormous"
name: "hellocrazyworld"
// …
}
</code>
 
h1. 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:
 
<code>
Group {
condition: qbs.targetOS == "windows"
files: [
"harddiskdeleter_win.cpp",
"blowupmonitor_win.cpp",
"setkeyboardonfire_win.cpp"
]
}
 
Properties {
condition: qbs.targetOS == "linux"
cpp.defines: outer.concat([ "USE_BUILTIN_DESTRUCTORS"])
}
</code>
 
See the DEFINES section above for important information about how conditionals and cpp.defines interact.
 
h1. 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:
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><br />cpp.optimization: &quot;none&amp;quot; // or &quot;fast&amp;quot;<br />cpp.debugInformation: true<br />cpp.staticLibraries: &quot;libraryName&amp;quot;<br />cpp.dynamicLibraries: &quot;libraryName&amp;quot;<br />cpp.frameworks: &quot;osxFrameworkName&amp;quot;<br />cpp.precompiledHeader: &quot;myheader.pch&amp;quot;<br />cpp.warningLevel: &quot;all&amp;quot; // or &quot;none&amp;quot;, &quot;default&amp;quot;<br />cpp.treatWarningsAsErrors: true<br /></code>
<code>
cpp.optimization: "none" // or "fast"
cpp.debugInformation: true
cpp.staticLibraries: "libraryName"
cpp.dynamicLibraries: "libraryName"
cpp.frameworks: "osxFrameworkName"
cpp.precompiledHeader: "myheader.pch"
cpp.warningLevel: "all" // or "none", "default"
cpp.treatWarningsAsErrors: true
</code>


Note that setting things like cflags directly is discouraged (because they are compiler-dependent), and higher-level alternatives like cpp.optimization: &quot;fast&amp;quot; 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.


= Installing files =
= Installing files =
Line 119: Line 296:
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><br />Group {<br /> qbs.install: true<br /> qbs.installDir: &quot;lib/myproj/&amp;quot;<br /> files: [<br /> &quot;Menu.qml&amp;quot;,<br /> &quot;SomeImportantFile.bin&amp;quot;<br /> ]<br />}<br /></code>
<code>
Group {
qbs.install: true
qbs.installDir: "lib/myproj/"
files: [
"Menu.qml",
"SomeImportantFile.bin"
]
}
</code>


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


The installation happens by invoking the &quot;qbs install&amp;quot; command:<br /><code><br />$ qbs install —install-root /tmp/myProject<br /></code>
The installation happens by invoking the "qbs install" command:
<code>
$ qbs install —install-root /tmp/myProject
</code>


= Command-line examples =
= Command-line examples =


64-bit:<br /><code>qbs <s>f /path/to/project.qbs —products productname qbs.architecture:x86_64<br /></code>
64-bit:
<br />h1. &quot;Magic&amp;quot; variables
<code>qbs -f /path/to/project.qbs —products productname qbs.architecture:x86_64
<br />Variables defined in various scopes, which may not be obvious:
</code>
<br />h2. qbs
 
<br />This has lots of useful things in, such as: targetOS (&quot;windows&amp;quot;, &quot;linux&amp;quot;, &quot;macx&amp;quot;, …); buildVariant (&quot;debug&amp;quot;, &quot;release&amp;quot;); architecture (&quot;x86&amp;quot;, &quot;x86_64&amp;quot;, …)
h1. "Magic" variables
<br />h2. project
 
<br />Valid anywhere in your project, needed to refer to project properties from within a product:
Variables defined in various scopes, which may not be obvious:
<br /><code>Project {<br /> property string version: &quot;1.0&amp;quot;
 
<br /> Product {<br /> cpp.defines: [&quot;PROJECT_VERSION=&quot; + project.version]<br /> }<br />}<br /></code>
h2. qbs
<br />h2. buildDirectory
 
<br />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.
This has lots of useful things in, such as: targetOS ("windows", "linux", "macx", …); buildVariant ("debug", "release"); architecture ("x86", "x86_64", …)
<br />h2. Module names
 
<br />Modules that are declared as dependencies can be referred to by their name and their properties accessed</s> for example:
h2. project
 
Valid anywhere in your project, needed to refer to project properties from within a product:
 
<code>Project {
property string version: "1.0"
 
Product {
cpp.defines: ["PROJECT_VERSION=" + project.version]
}
}
</code>
 
h2. 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.
 
h2. Module names
 
Modules that are declared as dependencies can be referred to by their name and their properties accessed- for example:


<code>Product {<br /> Depends { name: &quot;Qt.quick&amp;quot; }<br /> Qt.quick.qmlDebugging: false<br />}<br /></code>
<code>Product {
Depends { name: "Qt.quick" }
Qt.quick.qmlDebugging: false
}
</code>


== Inside custom javascript ==
== Inside custom javascript ==


Generally when writing custom JavaScript logic, things are referenced through the top-level &quot;product&amp;quot; variable. In particular, to get the product's value of the property &quot;baz&amp;quot; of a module &quot;foo&amp;quot;, use product.moduleProperty(&quot;foo&amp;quot;, &quot;baz&amp;quot;). For list values that get automatically combined, like includePaths, use product.moduleProperties(&quot;foo&amp;quot;, &quot;baz&amp;quot;).
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 {<br /> condition: qbs.targetOS === &quot;windows&amp;quot;<br /> files: [ &quot;hcf.cpp&amp;quot; ]<br />}<br /></code>
<code>Group {
condition: qbs.targetOS === "windows"
files: [ "hcf.cpp" ]
}
</code>


and
and


<code>Group {<br /> files: {<br /> if (product.moduleProperty(&quot;qbs&amp;quot;, &quot;targetOS&amp;quot;) === &quot;windows&amp;quot;) {<br /> return [ &quot;hcf.cpp&amp;quot; ];<br /> } else {<br /> return [];<br /> }<br /> }<br />}
<code>Group {
files: {
if (product.moduleProperty("qbs", "targetOS") === "windows") {
return [ "hcf.cpp" ];
} else {
return [];
}
}
}

Revision as of 08:46, 25 February 2015


[toc align_right="yes" depth="2"]

Introduction

Qbs is the next-generation build system "initially introduced in the Qt Labs Blog":https://blog.qt.io/blog/2012/02/15/introducing-qbs/. 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. And finally this is based on my incomplete current understanding of qbs, so there may be errors or indeed things which have changed by the time you read this :)

Qbs Manual

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

qbs equivalents

TEMPLATE = app

Use Application or CppApplication as the product:

CppApplication {
 name: "helloworld"
 files: "main.cpp"
 
}

This is roughly equivalent to:

Product {
 name: "helloworld"
 type: "application"
 files: "main.cpp"
 Depends { name: "cpp" }
 
}

except that in the first example, the type is "applicationbundle" on OSX.

TEMPLATE = lib

Use DynamicLibrary as the product:

DynamicLibrary {
 name: "mydll"
 files: ["stuff.cpp"]
 Depends { name: "cpp" }
 
}

TARGET = myappname

Use the "name" property, see the TEMPLATE example above.

HEADERS, SOURCES, FORMS, RESOURCES

Include in files section, eg

files: ['thing.h', 'thing.cpp', 'thing.ui', 'myapp.qrc']

qbs will use file taggers to figure out what kind of file it is dealing with.

== CONFIG = console

Application {
 name: "helloworld"
 files: "main.cpp"
 consoleApplication: true
 
}

h2. CONFIG= designer_defines ==

DynamicLibrary {
 name: "myplugin"
 files: ["foo.cpp", ]
 Depends { name: "cpp" }
 cpp.defines: ["QDESIGNER_EXPORT_WIDGETS"]
 
}

== QT = modulename

Add an appropriate Depends section to the product. For example:

Product {
 Depends { name: "Qt.core" }
 // …or…
 Depends { name: "Qt"; submodules: ["core", "gui", "network"] }
}

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.

h2. DEFINES= MACRO ==

Use the following: Note that in order to reference cpp.defines you must specify a dependency on the cpp module.

Depends { name: 'cpp' }

cpp.defines: ['SUPPORT_COOL_STUFF']

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:

Product {
 Depends { name: 'cpp' }
 
 cpp.platformDefines: ['MY_SPECIAL_DEFINE', 'UNICODE']

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:

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
 }
}

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:

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
 }
}

== INCLUDEPATH = dir

cpp.includePaths: [ '..', 'some/other/dir']<code>

h2. CONFIG -= Qt

Just don't declare Qt as a dependency. Probably you'd want:

Depends { name: "cpp" }

h2. RC_FILE

Just add the file to the "files" list.

h2. QMAKE_INFO_PLIST

Set the cpp.infoPlistFile property.

h2. ICON,

Not yet implemented. See "QBS-73":https://bugreports.qt.io/browse/QBS-73.

h2. TEMPLATE = subdirs

Inside a "Project" item, use "references":

Project {
 references: [
 "app/app.qbs",
 "lib/lib.qbs"
 ]
}

h2. DESTDIR

Use the destinationDirectory property:

DynamicLibrary {
 name: "mydll"
 destinationDirectory: "libDir"
 
}

h2. message(), warning(), error()

You can use the JavaScript function print for printing messages and throw exceptions on the right hand side of property bindings.

Product {
 name: {
 print("—-> now evaluating the product name");
 return "theName";
 }
 Depends {name: "cpp"}
 cpp.includePath: {
 throw "I don't know. Something bad happened."
 return [];
 }
}


h2. Others not mentioned above

Either I've missed them, or they're not yet implemented.

h1. .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"
 // …
}

h1. 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 == "windows"
 files: [
 "harddiskdeleter_win.cpp",
 "blowupmonitor_win.cpp",
 "setkeyboardonfire_win.cpp"
 ]
}

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

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

h1. 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: "osxFrameworkName"
cpp.precompiledHeader: "myheader.pch"
cpp.warningLevel: "all" // or "none", "default"
cpp.treatWarningsAsErrors: true

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"
}

The installation happens by invoking the "qbs install" command:

$ qbs install install-root /tmp/myProject

Command-line examples

64-bit:

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

h1. "Magic" variables

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

h2. qbs

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

h2. 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]
 }
}

h2. 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.

h2. 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
}

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").

Group {
 condition: qbs.targetOS === "windows"
 files: [ "hcf.cpp" ]
}

and

Group {

files: {
if (product.moduleProperty("qbs", "targetOS") === "windows") {
return [ "hcf.cpp" ];
} else {
return [];
}
}

}