Qbs Quick Reference/ru
Вступление
Qbs - это система сборки нового поколения, впервые представленная в Qt Blog. Эта страница задумана как краткое руководство к переводу проектов из qmake .pro в .qbs. Это руководство не заменяет официальную документацию, а скорее кратко описывает текущее состояние функциональности qbs с упором на переход с qmake'а.
На момент написания этого руководства в qbs'е реализован не весь функционал из qmake'а. На подобные функции приложена ссылка на Qt Bug Tracker.
Qbs руководство
Полное руководство по Qbs можно посмотреть в Qt Documentation.
Qbs эквиваленты
TEMPLATE = app
Используйте Application или CppApplication как продукт:
CppApplication {
name: "helloworld"
files: "main.cpp"
…
}
Что аналогично такой записи:
Product {
name: "helloworld"
type: "application"
files: "main.cpp"
Depends { name: "cpp" }
…
}
TEMPLATE = lib
Используйте DynamicLibrary как продукт:
DynamicLibrary {
name: "mydll"
files: ["stuff.cpp"]
Depends { name: "cpp" }
…
}
TARGET = myappname
Используйте свойство name, см. примеры TEMPLATE выше.
HEADERS, SOURCES, FORMS, RESOURCES
Просто перечислите эти файлы в свойстве files:
files: ['thing.h', 'thing.cpp', 'thing.ui', 'myapp.qrc']
Qbs использует тегирование файлов, чтобы иметь представление с какими файлами работает.
CONFIG = console
Application {
name: "helloworld"
files: "main.cpp"
consoleApplication: true
…
}
CONFIG = designer_defines
DynamicLibrary {
name: "myplugin"
files: ["foo.cpp", …]
Depends { name: "cpp" }
cpp.defines: ["QDESIGNER_EXPORT_WIDGETS"]
…
}
QT = modulename
Добавьте объект Depends в продукт, например:
Product {
Depends { name: "Qt.core" }
// …или…
Depends { name: "Qt"; submodules: ["core", "gui", "network"] }
}
Обе записи эквивалентны, но первую удобнее использовать при подключении одного модуля, а вторую для целого комплекса зависимостей.
DEFINES = MACRO
Используйте следующие примеры, но обратите внимание, что конструкцию cpp.defines можно использовать только в cpp-модуле.
Depends { name: 'cpp' }
…
cpp.defines: ['SUPPORT_COOL_STUFF']
В cpp-модуле можно определить предпроцессорные макросы используемые по умолчанию. Например в Windows'е заранее определён UNICODE. Он хранится в свойстве cpp.platformDefines. Чтобы переопределить макрос, пишем:
Product {
Depends { name: 'cpp' }
…
cpp.platformDefines: ['MY_SPECIAL_DEFINE', 'UNICODE']
}
Для добавления макроса внутри группы, нужно использовать outer.concat вместо base.concat, так как дополнительные макросы вы указываете во внешней области:
Product {
Depends { name: 'cpp' }
…
cpp.defines: ['MACRO_EVERYWHERE'] // Это определено для всех файлов в продукте (если группа не переопределит это!)
Group {
cpp.defines: outer.concat('MACRO_GROUP')
files: groupFile.cpp
// MACRO_GROUP определён только для файла groupFile.cpp
// MACRO_EVERYWHERE тоже определён в groupFile.cpp, из-за использования outer.concat
}
}
cpp.defines выражение применяется к файлам только в этой группе, поэтому вы не можете использовать группу для добавления глобально-видимых макросов - такие макросы должны определяться в объекте Properties расположенном на том же уровне, что и группа, если макросу нужно быть видимым за пределами группы:
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 для цепочки объектов Properties
}
}
INCLUDEPATH = dir
cpp.includePaths: [ '..', 'some/other/dir']
CONFIG -= Qt
Просто не добавляйте зависимость от Qt. Возможно вам нужен просто C++:
Depends { name: "cpp" }
RC_FILE
Просто добавьте файл к остальному списку в свойстве files.
QMAKE_INFO_PLIST
Set the "bundle.infoPlistFile" property of the bundle module.
Depends { name: "bundle" }
ICON
К сожалению ещё не реализовано. Смотрим QBS-73.
TEMPLATE = subdirs
Inside a "Project" item, use "references":
Project {
references: [
"app/app.qbs",
"lib/lib.qbs"
]
}
CONFIG = ordered
Дурная фишка qmake'а, которой нет в qbs. Очередь сборки определяется зависимостями.
CppApplication {
name: "myapp"
Depends { name: "mylib" }
}
"myapp" зависит от "mylib", потому и соберётся после него.
DESTDIR
Используйте свойство destinationDirectory:
DynamicLibrary {
name: "mydll"
destinationDirectory: "libDir"
…
}
Но это не рекомендуется. Вместо этого лучше использовать механизм установки (смотрим дальше).
QML_IMPORT_PATH
Используется только для подсветки QML-синтаксиса QtCreator'ом. Внутри продукта ('Product', 'Application', 'CppApplication' и т.п.) создайте свойство qmlImportPaths:
Product {
name: "myProduct"
readonly property stringList qmlImportPaths: [sourceDirectory + "/path/to/qml/"]
}
message(), warning(), error()
Вы можете использовать JavaScript-функцию print для вывода сообщений и throw для генерации исключений во время определения значений свойств.
Product {
name: {
print("—-> устанавливаем название продукта");
return "theName";
}
Depends {name: "cpp"}
cpp.includePath: {
throw "ХЗ. Что-то плохое приключилось"
return [];
}
}
QTPLUGIN.platforms = qminimal
Собирая статическое приложение, часто надо ссылаться на статические Qt-плагины. Вы можете использовать следующий код для того, чтобы Qbs сослался на требуемые плагины:
Product{
name: "myapp"
Depends { name: "Qt"; submodules: ["core", "gui", "widgets"] }
Depends { name: "Qt.qminimal"; condition: Qt.staticBuild }
}
Это приводит к статической компоновке с plugins/platforms/qminimal плагинами в приложении.
Остальное, не упомянутое выше
Либо Я упустил это, либо оно ещё не реализовано.
.pro and .pri
Самый верхний по уровню .qbs-файл содержит проект (Project объект). Проект может содержать множество продуктов, а множество .pro-файлов можно выразить одним .qbs-файлом. Обычно подпапки объединяют одним .qbs ссылаясь на множество .qbs-файлов. Один .qbs-файл определяет один продукт или подпроект.
.qbs-файлы можно использовать как .pri-файлы и .qbs верхнего уровня может содержать секции, определённые в других .qbs. Например:
-- файл CrazyProduct.qbs --
import qbs.base 1.0
Product {
property string craziness: "low"
}
-- файл hellocrazyworld.qbs --
CrazyProduct {
craziness: "enormous"
name: "hellocrazyworld"
// …
}
.qbs-файлы лежащие в той же директории, ровно как и .qbs-файл верхнего уровня подхватываются автоматически. Остальные же необходимо импортировать и именовать вручную, используя "import … as …" структуру:
import qbs.base 1.0
import "../CrazyProduct.qbs" as CrazyProduct
CrazyProduct {
craziness: "enormous"
name: "hellocrazyworld"
// …
}
Это позволяет подхватывать дополнительные группы с файлами, как с .pri-файлами, импортируя .qbs с определением группы и декларируя эту группу в продукте.
-- файл external.qbs --
import qbs
Group {
files:["file1.cpp", "file2.cpp"]
}
-- файл product.qbs --
import qbs
import "external.qbs" as SourceGroup
Product {
name: "SomeProduct"
SourceGroup {}
}
Если открыть в QtCreator'е, файлы из external.qbs будут видимы в группе продукта 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
}