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/ru: Difference between revisions
m (small fix) |
(Translating .pro and .pri) |
||
(11 intermediate revisions by the same user not shown) | |||
Line 10: | Line 10: | ||
== Qbs руководство == | == Qbs руководство == | ||
Полное руководство по Qbs можно посмотреть в [https://doc.qt.io/qbs Qt Documentation]. | |||
== | == Qbs эквиваленты == | ||
=== TEMPLATE = app === | === TEMPLATE = app === | ||
Используйте '''Application''' или '''CppApplication''' как продукт: | |||
<code>CppApplication { | <code>CppApplication { | ||
Line 25: | Line 25: | ||
</code> | </code> | ||
Что аналогично такой записи: | |||
<code>Product { | <code>Product { | ||
Line 39: | Line 39: | ||
=== TEMPLATE = lib === | === TEMPLATE = lib === | ||
Используйте '''DynamicLibrary''' как продукт: | |||
<code> | <code> | ||
Line 52: | Line 52: | ||
=== TARGET = myappname === | === TARGET = myappname === | ||
Используйте свойство '''name''', см. примеры TEMPLATE выше. | |||
=== HEADERS, SOURCES, FORMS, RESOURCES === | === HEADERS, SOURCES, FORMS, RESOURCES === | ||
Просто перечислите эти файлы в свойстве '''files''': | |||
<code>files: ['thing.h', 'thing.cpp', 'thing.ui', 'myapp.qrc'] | <code>files: ['thing.h', 'thing.cpp', 'thing.ui', 'myapp.qrc'] | ||
</code> | </code> | ||
Qbs использует тегирование файлов, чтобы иметь представление с какими файлами работает. | |||
=== CONFIG = console === | === CONFIG = console === | ||
Line 86: | Line 86: | ||
=== QT = modulename === | === QT = modulename === | ||
Добавьте объект '''Depends''' в продукт, например: | |||
<code>Product { | <code>Product { | ||
Depends { name: "Qt.core" } | Depends { name: "Qt.core" } | ||
// | // …или… | ||
Depends { name: "Qt"; submodules: ["core", "gui", "network"] } | Depends { name: "Qt"; submodules: ["core", "gui", "network"] } | ||
} | } | ||
</code> | </code> | ||
Обе записи эквивалентны, но первую удобнее использовать при подключении одного модуля, а вторую для целого комплекса зависимостей. | |||
=== DEFINES = MACRO === | === DEFINES = MACRO === | ||
Используйте следующие примеры, но обратите внимание, что конструкцию '''cpp.defines''' можно использовать только в cpp-модуле. | |||
<code>Depends { name: 'cpp' } | <code>Depends { name: 'cpp' } | ||
… | … | ||
Line 105: | Line 105: | ||
</code> | </code> | ||
В cpp-модуле можно определить предпроцессорные макросы используемые по умолчанию. Например в Windows'е заранее определён UNICODE. | |||
Он хранится в свойстве '''cpp.platformDefines'''. | |||
Чтобы переопределить макрос, пишем: | |||
<code>Product { | <code>Product { | ||
Depends { name: 'cpp' } | Depends { name: 'cpp' } | ||
Line 115: | Line 115: | ||
</code> | </code> | ||
Для добавления макроса внутри группы, нужно использовать '''outer.concat''' вместо '''base.concat''', так как дополнительные макросы вы указываете во внешней области: | |||
<code>Product { | <code>Product { | ||
Depends { name: 'cpp' } | Depends { name: 'cpp' } | ||
… | … | ||
cpp.defines: ['MACRO_EVERYWHERE'] // | cpp.defines: ['MACRO_EVERYWHERE'] // Это определено для всех файлов в продукте (если группа не переопределит это!) | ||
Group { | Group { | ||
cpp.defines: outer.concat('MACRO_GROUP') | cpp.defines: outer.concat('MACRO_GROUP') | ||
files: groupFile.cpp | files: groupFile.cpp | ||
// MACRO_GROUP | // MACRO_GROUP определён только для файла groupFile.cpp | ||
// MACRO_EVERYWHERE | // MACRO_EVERYWHERE тоже определён в groupFile.cpp, из-за использования outer.concat | ||
} | } | ||
} | } | ||
</code> | </code> | ||
cpp.defines | cpp.defines выражение применяется к файлам только в этой группе, поэтому вы не можете использовать группу для добавления глобально-видимых макросов - такие макросы должны определяться в объекте '''Properties''' расположенном на том же уровне, что и группа, если макросу нужно быть видимым за пределами группы: | ||
<code>Product { | <code>Product { | ||
Line 140: | Line 140: | ||
} | } | ||
property stringList commonDefines: ["ONE", "TWO"] | property stringList commonDefines: ["ONE", "TWO"] | ||
Properties { | Properties { | ||
condition: supportFoobar === true | condition: supportFoobar === true | ||
Line 146: | Line 146: | ||
} | } | ||
Properties { | Properties { | ||
cpp.defines: commonDefines // else | cpp.defines: commonDefines // блок else для цепочки объектов Properties | ||
} | } | ||
} | } | ||
Line 157: | Line 157: | ||
=== CONFIG -= Qt === | === CONFIG -= Qt === | ||
Просто не добавляйте зависимость от Qt. Возможно вам нужен просто C++: | |||
<code>Depends { name: "cpp" }</code> | <code>Depends { name: "cpp" }</code> | ||
Line 163: | Line 163: | ||
=== RC_FILE === | === RC_FILE === | ||
Просто добавьте файл к остальному списку в свойстве '''files'''. | |||
=== QMAKE_INFO_PLIST === | === QMAKE_INFO_PLIST === | ||
Line 172: | Line 172: | ||
=== ICON === | === ICON === | ||
К сожалению ещё не реализовано. Смотрим [https://bugreports.qt.io/browse/QBS-73 QBS-73]. | |||
=== TEMPLATE = subdirs === | === TEMPLATE = subdirs === | ||
Line 187: | Line 187: | ||
=== CONFIG = ordered === | === CONFIG = ordered === | ||
Дурная фишка qmake'а, которой нет в qbs. | |||
Очередь сборки определяется зависимостями. | |||
<code> | <code> | ||
CppApplication { | CppApplication { | ||
Line 195: | Line 197: | ||
} | } | ||
</code> | </code> | ||
"myapp" зависит от "mylib", потому и соберётся после него. | |||
=== DESTDIR === | === DESTDIR === | ||
Используйте свойство '''destinationDirectory''': | |||
<code> | <code> | ||
Line 208: | Line 212: | ||
</code> | </code> | ||
Но это не рекомендуется. Вместо этого лучше использовать механизм установки (смотрим дальше). | |||
=== QML_IMPORT_PATH === | === QML_IMPORT_PATH === | ||
Используется только для подсветки QML-синтаксиса QtCreator'ом. Внутри продукта ('Product', 'Application', 'CppApplication' и т.п.) создайте свойство '''qmlImportPaths''': | |||
<code>Product { | <code>Product { | ||
Line 217: | Line 222: | ||
readonly property stringList qmlImportPaths: [sourceDirectory + "/path/to/qml/"] | readonly property stringList qmlImportPaths: [sourceDirectory + "/path/to/qml/"] | ||
}</code> | }</code> | ||
=== message(), warning(), error() === | === message(), warning(), error() === | ||
Вы можете использовать JavaScript-функцию '''print''' для вывода сообщений и '''throw''' для генерации исключений во время определения значений свойств. | |||
<code>Product { | <code>Product { | ||
name: { | name: { | ||
print("—-> | print("—-> устанавливаем название продукта"); | ||
return "theName"; | return "theName"; | ||
} | } | ||
Depends {name: "cpp"} | Depends {name: "cpp"} | ||
cpp.includePath: { | cpp.includePath: { | ||
throw " | throw "ХЗ. Что-то плохое приключилось" | ||
return []; | return []; | ||
} | } | ||
Line 234: | Line 240: | ||
=== QTPLUGIN.platforms = qminimal === | === QTPLUGIN.platforms = qminimal === | ||
Собирая статическое приложение, часто надо ссылаться на статические Qt-плагины. | |||
Вы можете использовать следующий код для того, чтобы Qbs сослался на требуемые плагины: | |||
<code> | <code> | ||
Product{ | Product{ | ||
Line 243: | Line 251: | ||
} | } | ||
</code> | </code> | ||
=== | Это приводит к статической компоновке с plugins/platforms/qminimal плагинами в приложении. | ||
=== Остальное, не упомянутое выше === | |||
Либо Я упустил это, либо оно ещё не реализовано. | |||
== .pro and .pri == | == .pro and .pri == | ||
Самый верхний по уровню .qbs-файл содержит проект (Project объект). Проект может содержать множество продуктов, а множество .pro-файлов можно выразить одним .qbs-файлом. Обычно подпапки объединяют одним .qbs ссылаясь на множество .qbs-файлов. Один .qbs-файл определяет один продукт или подпроект. | |||
.qbs | .qbs-файлы можно использовать как .pri-файлы и .qbs верхнего уровня может содержать секции, определённые в других .qbs. Например: | ||
<code> | <code> | ||
-- файл CrazyProduct.qbs -- | |||
import qbs.base 1.0 | import qbs.base 1.0 | ||
Line 263: | Line 272: | ||
} | } | ||
-- файл hellocrazyworld.qbs -- | |||
CrazyProduct { | CrazyProduct { | ||
craziness: "enormous" | craziness: "enormous" | ||
Line 271: | Line 280: | ||
</code> | </code> | ||
.qbs | .qbs-файлы лежащие в той же директории, ровно как и .qbs-файл верхнего уровня подхватываются автоматически. Остальные же необходимо импортировать и именовать вручную, используя "import … as …" структуру: | ||
<code> | <code> | ||
Line 283: | Line 292: | ||
</code> | </code> | ||
Это позволяет подхватывать дополнительные группы с файлами, как с .pri-файлами, импортируя .qbs с определением группы и декларируя эту группу в продукте. | |||
<code> | <code> | ||
-- | -- файл external.qbs -- | ||
import qbs | import qbs | ||
Group { | Group { | ||
files:["file1.cpp", "file2.cpp"] | files:["file1.cpp", "file2.cpp"] | ||
} | } | ||
-- | |||
-- файл product.qbs -- | |||
import qbs | import qbs | ||
import "external.qbs" as SourceGroup | import "external.qbs" as SourceGroup | ||
Line 300: | Line 309: | ||
} | } | ||
</code> | </code> | ||
Если открыть в QtCreator'е, файлы из external.qbs будут видимы в группе продукта SomeProduct. | |||
== Conditionals == | == Conditionals == |
Latest revision as of 12:10, 6 February 2017
Вступление
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
}