- PVSM.RU - https://www.pvsm.ru -

Не так давно команда разработчиков Qt представила [1] новую систему сборки — QBS. Разумеется, основной реакцией было «Да чем вас QMAKE не устраивал», «Просто адаптируйте CMAKE», «Ещё одна система сборки [xkcd, стандарты]». Обещанные преимущества новой системы: гибкость, понятный синтаксис для всех разработчиков (QML — javascript-подобный декларативный язык), скорость билдов (чистых и инкрементальных), а также лёгкая расширяемость.
Всё это мы где-то уже слышали, поэтому в данной статье мы попытаемся разобраться, как разработчики пришли к этой системе, рассмотрим простейшие примеры, изучим основные конструкции и посмотрим, какая поддержка на уровне IDE присутствует на настоящий момент.
Сейчас мы вместе постараемся повторить путь Йорга Борнемана (Jörg Bornemann), разработчика QBS.
В статье Peter Miller [2] 1999 года рассматривается проблематика рекурсивного make и вообще удобства makefile'ов как таковых.
В статье Adrian Neagu [3] 2005 года рассматриваются более общие проблемы make:
В статье «Что не так с GNU Make [4]»
Более подробно расписаны минусы языка и те же самые проблемы что и ранее (не буду повторяться)
В короткой заметке Ian Lance Taylor [5], 2007 г. рассмотрен основной недостаток Cmake как замены Make — Он. Слишком. Сложен. Это адская смесь нескольких языков, поддерживать её (для действительно сложных систем) могут только гуру разработки и отладки (отлаживать её тоже проблематично). Ещё одним недостатком является то, что за гибкость (даже ГИБКОСТЬ), приходится расплачиваться потерей производительность в сгенерированных скриптах.
В инфраструктуре Qt на сегодняшний день широко используется система сборки Qmake, которая поддерживается официально и все ещё дорабатывается. Зачем же возникла надобность «just another one» системы сборки?
В статье Marius Storm-Olsen [6] анализирует следующие недостатки qmake:
Попробуйте посмотреть на QTDIR/mkspecs/features/exclusive_builds.prf:
DEFINES += QT_NO_CAST_TO_ASCII
!macx:DEFINES += QT_USE_FAST_OPERATOR_PLUS QT_USE_FAST_CONCATENATION
unix {
CONFIG(debug, debug|release):OBJECTS_DIR = $${OUT_PWD}/.obj/debug-shared
CONFIG(release, debug|release):OBJECTS_DIR = $${OUT_PWD}/.obj/release-shared
CONFIG(debug, debug|release):MOC_DIR = $${OUT_PWD}/.moc/debug-shared
CONFIG(release, debug|release):MOC_DIR = $${OUT_PWD}/.moc/release-shared
RCC_DIR = $${OUT_PWD}/.rcc
UI_DIR = $${OUT_PWD}/.uic
}
Понять такое сразу, даже «поллитры» не хватит. Хотя с этим еще CMake может
Пусть программист знает С++, Pascal, Javascript, win&unix shell и SQL — все эти знания окажутся бесполезными в освоении системы сборки.
От себя могу добавить, что много хлопот мне доставил символ "#" в путях и возня с $$LITERAL_HASH (зачем придумывать способ экранирования спецсимволов языка? Введём свои макросы лучше).
Наконец, мы подошли к тому моменту, как в рассылке Qt обсуждалась новая система сборки [7] и требования для неё:
15 февраля 2012 года в Qt labs Йорг Борнеман представил общественности проект QBS. Сейчас он находится даже не в состоянии альфы, а где-то посередине между прототипом и альфа-версией. В оправдание можно сказать, что Qt Creator уже собирается с её помощью.
Основные принципы проектирования новой системы:
Чего пока нет: проверки конфигурации системы(используется запрос к qmake для конфигурирования тулчейнов), сборки пакетов, деплоймента, запуска тестов и самое главное — поддержки каких-либо ide, кроме особой ветки QtCreator-а.
Автор советует собрать qbs из исходников [8], но можно иметь ввиду, для пользователей win и linux есть бинарные сборки [9]
win — собрано под MSVC2010. Я бы тоже посоветовал собрать версию из git ( у меня проблемы были с плагинами и MOC).
В бинарном виде qbs зависит от библиотек QtCore и QtScript (+Concurrent для Qt5)
Создадим Hello World проект на С++:
main.cpp
#include <iostream>
using namespace std;
int main()
{
cout << "Hello world!" << endl;
return 0;
}
Создадим также минимальный проект на qbs:
hello.qbp
import qbs.base 1.0
CppApplication {
name: "HelloWorld"
files: "main.cpp"
}
LINUX:
1. Открываем в текущей папке шелл.
2. Добавляем путь, куда вы распаковали/собрали qbs, в PATH (вернее, bin папку)
PATH=~/qbs/bin/:$PATH
3. запускам qbs:
qbs
Found project file /home/mapron/статья/example-3/hello.qbp
loading project took: 69 ms
build graph took: 18 ms
for debug:
- [hpp, application] HelloWorld as debug
compiling main.cpp
linking HelloWorld
Build done.
После этого программа сборки запустит разбор проекта и соберет в папке build/debug исполняемый файл (ну мы же не указали пока папку назначения?)
WINDOWS:
4. Поскольку под Windows, как правило компилятор и qt не находятся в PATH, qbs может попросить вас запустить «qbs platform probe», что необходимо сделать.
5. затем возможно, понадобится запустить qbs config update или подобное (если он попросит, возможно это исправили уже).
6. после этого при запуске qbs [build] — вы получите собранный бинарник «HelloWorld.exe»
Теперь попробуем освоить сборку чего-то более сложного, и заодно, разобраться с языком.
Для начала, создадим новую папку и скопируем туда папки «2dpainting» и «collidingmice» из папки examples с Qt.
Почему сразу два? Мы создадим конфигурацию для сборки сразу двух продуктов.
Продукт — это целевой «выход» системы сборки, подобие «.pro» файла при сборке Qmake. В одном проекте qbs может быть несколько продуктов.
Для начала создадим проект «examples.qbp»
//Подключаем стандартные библиотеки в стиле QML
import qbs.base 1.0
import qbs.fileinfo 1.0 as FileInfo
Project { // основной элемент файла - проект.
moduleSearchPaths: "qbs" // Папка для поиска дополнительных модулей, таких как cpp и qt
// Один проект может состоять из нескольких продуктов - конечных целей сборки.
Product {
name: "2dpainting" // Название выходного файла (без суффикса, он зависит от цели)
type: "application" // Тип - приложение, т.е. исполняемый файл.
Depends { name: "cpp" } // этот продукт зависит от компилятора C++
Depends { name: "Qt"; submodules: ["core", "gui", "opengl"] } // И Qt модулей QtCore, QtGui, QtOpengl
files: [ // список файлов в данном проекте. пока они в поддиректории, организуем позже.
"2dpainting/glwidget.h",
"2dpainting/helper.h",
"2dpainting/widget.h",
"2dpainting/window.h",
"2dpainting/glwidget.cpp",
"2dpainting/helper.cpp",
"2dpainting/main.cpp",
"2dpainting/widget.cpp",
"2dpainting/window.cpp",
]
}
}
Откроем консоль и попробуем собрать, выведется ошибка «ERROR: Error while setting up build environment: qt.core.incPath not set. Set qt.core.incPath or qt.core.path in your profile. »
Закроем пока глаза на не слишком юзер-френдли способ конфигурации, и создадим файл «qbs.config» с таким содержимым (WINDOWS):
modules.qbs.platform: MSVC2010
profile: default
profiles.default.qt.core.path: C:/QtSDK/Desktop/Qt/4.8.1/msvc2010/
либо под LINUX (ubuntu):
modules.qbs.platform: gcc
profile: default
profiles.default.qt.core.binPath: /usr/bin/
profiles.default.qt.core.libPath: /usr/lib/qt4
profiles.default.qt.core.incPath: /usr/include/qt4
profiles.default.qt.core.mkspecsPath: /usr/share/qt4/mkspecs
и запустить qbs config --import qbs.config
После этого qbs нормально сможет собрать проект и поместит выходной файл в папку build/debug.
Для того чтобы собрать проект в релиз, выполните «qbs build release».
Для очистки всех файлов сборки (т. е. Папки «build») выполните «qbs clean».
Теперь попробуем организовать расширяемую структуру для двух проектов. Создадим в подкаталогах «2dpainting» и «collidingmice» файлы-тёзки своих каталогов с расширением «.qbs» с таким содержимым:
import qbs.base 1.0
Product {
name: "2dpainting"
type: "application"
Depends { name: "cpp" }
Depends { name: "Qt"; submodules: ["core", "gui", "opengl"] }
files: [ // чтоб не раздувать по вертикали, напишу в две колонки.
"glwidget.h", "helper.h",
"widget.h", "window.h",
"glwidget.cpp", "helper.cpp",
"main.cpp", "widget.cpp",
"window.cpp",
]
}
import qbs.base 1.0
Product {
name: "collidingmice"
type: "application"
Depends { name: "cpp" }
Depends { name: "Qt"; submodules: ["core", "gui", "opengl"] }
files: [ "mouse.h","main.cpp", "mouse.cpp" ,"mice.qrc"]
}
Т.е. мы разбиваем код на независимые продукты, которые могут собираться параллельно. Внесём изменения в examples.qbp:
//Подключаем стандартные библиотеки в стиле QML
import qbs.base 1.0
import qbs.fileinfo 1.0 as FileInfo
Project { // основной элемент файла - проект.
moduleSearchPaths: "qbs"
// Один проект может состоять из нескольких продуктов - конечных целей сборки.
// указываем связанные файлы с помощью references. Внимание: это не жестко заданный порядок!
// Порядок задается с помощью зависимостей, о них позже
references: [
"2dpainting/2dpainting.qbs",
"collidingmice/collidingmice.qbs",
]
}
Можете снова запустить «qbs». Обратите внимание, для «.qrc» файла будет автоматически вызван «rcc» и все это слинковано вместе. Все файлы при этом указываются одним списком, без разделения на HEADERS, SOURCES и т. д., как было в qmake.
Для начала рекомендую бегло ознакомиться со справкой [10]
Основные концепции языка: Проект (Project), Продукт (Product), Артефакт (Artifact), Модуль (Module), Правило (Rule), Группа(Group), Зависимость (Depends), Тег (Tag).
Продукт — это аналог pro или vcproj, т. е. одна цель для сборки.
Проект — это набор ваших продуктов вместе с зависимостями, воспринимаемый системой сборки как одно целое. Один проект — один граф сборки.
Тег — система классификации файлов. Например «*.cpp» => «cpp»
Правило — Преобразование файлов проекта, отмеченных определенными тегами. Генерирует другие файлы, называемые Артефактами. Как правило, это компиляторы или другие системы сборки.
Артефакт — файл, над который является выходным для правила (и возможно, входным для други правил). Это обычно «obj», «exe» файлы.
У многих QML-объектов есть свойство condition, которое отвечает за то, будет собираться он или нет. А если нам необходимо разделить так файлы? Для этого их можно объединить в группу (Group)
Group {
condition: qbs.targetOS == "windows"
files: [ "file1", ...]
}
примерно таким образом.
Закономерный вопрос, примеры это здорово, а как можно отправиться в свободное плавание с этой системой? Можно:
QBS предоставляет нам следующие плюсы:
Но, к сожалению имеет следующие (временные минусы)
К сожалению, формат статьи не позволяет раскрыть все тонкости, в дальнейших планах раскрыть тему:
Все это может быть в этой статье, и что-то что напишут в комментариях.
Ссылка на архив со всеми примерами к статье:
narod.ru/disk/49759080001.18d6748f8ef86e26c6dea2e2c5ed7d13/examples.zip.html [11]
labs.qt.nokia.com/2012/02/15/introducing-qbs/ [1] — представление
doc-snapshot.qt-project.org/qbs/ [12] — документация
qt.gitorious.org/qt-labs/qbs [8] — git
bugreports.qt-project.org/browse/QBS [13] — багтрекер.
Примечание: Qt Build Salvation (Спасение для сборки Qt) — внутреннее имя QBS, в README дерева исходников.
Автор: mapron
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/qt-2/7887
Ссылки в тексте:
[1] представила: http://labs.qt.nokia.com/2012/02/15/introducing-qbs/
[2] Peter Miller : http://aegis.sourceforge.net/auug97.pdf
[3] Adrian Neagu: http://freecode.com/articles/what-is-wrong-with-make
[4] Что не так с GNU Make: http://www.conifersystems.com/whitepapers/gnu-make/
[5] Ian Lance Taylor: http://www.airs.com/blog/archives/95
[6] Marius Storm-Olsen: http://labs.qt.nokia.com/2009/10/12/to-make-or-not-to-make-qmake-and-beyond/
[7] обсуждалась новая система сборки: http://lists.qt.nokia.com/pipermail/qt5-feedback/2011-June/000494.html
[8] из исходников: http://qt.gitorious.org/qt-labs/qbs
[9] есть бинарные сборки : http://builds.qt-project.org/view/QBS/
[10] справкой: http://doc-snapshot.qt-project.org/qbs/qbs-language-introduction.html
[11] narod.ru/disk/49759080001.18d6748f8ef86e26c6dea2e2c5ed7d13/examples.zip.html: http://narod.ru/disk/49759080001.18d6748f8ef86e26c6dea2e2c5ed7d13/examples.zip.html
[12] doc-snapshot.qt-project.org/qbs/: http://doc-snapshot.qt-project.org/qbs/
[13] bugreports.qt-project.org/browse/QBS: https://bugreports.qt-project.org/browse/QBS
Нажмите здесь для печати.