
Note (06/17/2013): The syntax of the examples in the article does not correspond to the latest versions. Check the documentation. Also in March,
Qt Creator 2.7 was released with QBS support.
Not so long ago, the Qt development team
introduced a new build system - QBS. Of course, the main reaction was “Yes, what did not suit you QMAKE”, “Just adapt CMAKE”, “Another build system [xkcd, standards]”. The promised advantages of the new system: flexibility, understandable syntax for all developers (QML is a javascript-like declarative language), build speed (pure and incremental), as well as easy extensibility.
We have already heard all this somewhere, so in this article we will try to figure out how the developers came to this system, consider the simplest examples, study the basic constructs and see what kind of support is present at the IDE level at the moment.
Story
Now together we will try to repeat the path of Jörg Bornemann, the developer of QBS.
Criticism make (and derivatives)
The 1999 article by
Peter Miller discusses the problems of recursive make and the convenience of makefiles in general.
- The traditional UNIX build system make gives an inadmissibly long build time for large projects (especially for incremental builds);
- Using the recursive make call from the root directory leads to dependency violations between modules, to eliminate which you have to run the assembly two or three times (and an increase in the build time, of course);
- Using a single makefile eliminates flaws, but support becomes unbearable. There is no talk of any sufficient support for makingfile changes using the IDE.
The 2005
Adrian Neagu article discusses more common make issues:
- The portability of make is greatly inflated, since make does not work by itself, dozens of other utilities that are specific to the platform may be listed in the makefile;
- Scalability is terrible when using recursive make (the same opinion as in the previous article), and is insufficient when using include or other extensions. In particular, assembly performance drops very quickly.
')
In the article "
What's wrong with GNU Make "
The minuses of the language and the same problems as before are described in more detail (I will not repeat)
- Unobvious and frankly flawed elements of the language (which are only ifeq, ifneq, ifdef, and ifndef)
- Type Problems (String Only)
- Poor dependency resolution when changing command line options
- Problems with simultaneous start and parallelization
- It is easy to "kill" the assembly tree by suddenly stopping the program.
- And many other small shoals, which indicate inappropriate architecture for contemporary needs (according to the author).
A short note from
Ian Lance Taylor , 2007, discusses the main drawback of Cmake as a replacement for Make-It. Too. Complicated This is a hell of a mixture of several languages; only development and debugging gurus can support it (for really complex systems) (debugging it is also problematic). Another disadvantage is that for flexibility (even FLEXIBILITY), you have to pay the loss of performance in the generated scripts.
What is wrong with QMake?
The Qt infrastructure today widely uses the Qmake build system, which is officially supported and is still being finalized. Why did the “just another one” build system need?
The article
Marius Storm-Olsen analyzes the following qmake flaws:
- Own, original syntax of the language.
Try looking at 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 }
To understand this immediately, even the "half a liter" is not enough. Although with this still CMake can contend.
Let the programmer know C ++, Pascal, Javascript, win & unix shell and SQL - all this knowledge will be useless in mastering the build system.
From myself I can add that a lot of trouble was brought to me by the "#" symbol in the paths and scuffling with $$ LITERAL_HASH (why invent a way of escaping special characters of the language? Let's introduce our macros better).
- IDE support.
Qt creator supports adding new files to the project, but as soon as the “usual” syntax is added, it can simply add a new HEADERS or FILES construct to the end.
- The lack of assembly as such in qmake.
Qmake does not build your project. The name is deceptive. It only generates a Makefile, and builds one of the utilities Make (* nix - gnu make, win-nkeke, jom or mingw-make). - Lack of transparent support for cross-compilation, package building and deployment.
Finally, we come to the point when the Qt mailing list
discussed the new build system and the requirements for it:
- It must be VERY fast (stealth time to produce stat () of all files);
Changing a node somewhere deep in the tree assembly should not lead to a change in the configuration of the entire tree; - It should have a simple and understandable language that can be easily understood by people and served by scripts;
The language should be well specialized;
It should be declarative in its structure, with small imperative fragments, tightly isolated from the rest;
The language should be based on properties, not commands. No CFLAGS. (cmake halfway to this); - There must be full support for modularity. Also, any subproject should be able to easily separate from the parent (and join another). That is, roughly speaking, they took the folder with the configuration of the assembly, inserted it into another project - they are also going to do everything well (without taking into account dependencies, of course);
- Clear and clear support for IDE;
- It should be possible to build different configurations for different platforms in one pass.
Introducing the “lifeline” - Qt Build System
On February 15, 2012, in Qt labs, Jorg Borneman presented the draft QBS to the public. Now he is not even able to alpha, but somewhere in the middle between the prototype and the alpha version. In justification, we can say that Qt Creator is already going with it.
The basic principles of designing a new system:
- Declarativity - QML syntax is used;
- Extensibility - there is an opportunity to write your own modules for assembly, or code generators, etc. (below we will try to write our own module for building Delphi projects);
- Speed;
- Building directly is not qmake, it is not a “middleman”. Qbs itself calls compilers, linker, and what else is needed.
What is not yet: checking the system configuration (using the qmake request to configure the toolchains), building packages, deploying, running tests and, most importantly, supporting any ide, except for the special QtCreator branch.
Let's start trying!
The author advises to build qbs
from source , but you can bear in mind that
there are binary builds for win and linux users
win - compiled under MSVC2010. I would also advise you to build a version from git (I had problems with plug-ins and MOC).
In binary form, qbs depends on the QtCore and QtScript libraries (+ Concurrent for Qt5)
Create a Hello World C ++ project:
main.cpp #include <iostream> using namespace std; int main() { cout << "Hello world!" << endl; return 0; }
Let's also create a minimal project on qbs:
hello.qbp import qbs.base 1.0 CppApplication { name: "HelloWorld" files: "main.cpp" }
LINUX:
1. Open the shell in the current folder.
2. Add the path where you unpacked / assembled qbs, in the PATH (or rather, bin folder)
PATH = ~ / qbs / bin /: $ PATH
3. start 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.
After that, the build program will start parsing the project and collect the executable file in the build / debug folder (well, haven't you specified the destination folder yet?)
WINDOWS:
4. Since under Windows, as a rule, the compiler and qt are not in the PATH, qbs may ask you to run “
qbs platform probe ”, which is necessary to do.
5. then you may need to run
qbs config update or the like (if he asks, it may have been fixed already).
6. after that, when you start
qbs [build] - you will get the “HelloWorld.exe” binary
We continue to study
Now we will try to master the assembly of something more complex, and at the same time, deal with the language.
To begin with, we will create a new folder and copy the
2dpainting and
collidingmice folders from the examples folder with Qt.
Why just two? We will create a configuration for the assembly of two products at once.
The product is the target “output” of the build system, a kind of “.pro” file when building Qmake. In a single qbs project, there may be several products.
To begin, create the
examples.qbp project.
Open the console and try to build, the error “ERROR: Error while setting up the environment: qt.core.incPath not set. Set qt.core.incPath or qt.core.path in your profile. "
Let's close our eyes for a not too user-friendly way of configuration, and create a file "
qbs.config " with the following contents (WINDOWS):
modules.qbs.platform: MSVC2010 profile: default profiles.default.qt.core.path: C:/QtSDK/Desktop/Qt/4.8.1/msvc2010/
either under 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
and run
qbs config --import qbs.config
After this, qbs will normally be able to build the project and place the output file in the build / debug folder.
To build a project into a release, execute “
qbs build release ”.
To clean all build files (i.e. “build” folders) execute “
qbs clean ”.
Now we will try to organize an expandable structure for two projects. Create in the subdirectories "
2dpainting " and "
collidingmice " the
names tags of your directories with the extension ".qbs" with the following contents:
import qbs.base 1.0 Product { name: "2dpainting" type: "application" Depends { name: "cpp" } Depends { name: "Qt"; submodules: ["core", "gui", "opengl"] } files: [
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"] }
Those. we break the code into independent products that can be built in parallel. Make changes to examples.qbp:
You can run qbs again. Note that for the “.qrc” file the “rcc” will be automatically called and all this is linked together. All files are indicated by one list, without division into HEADERS, SOURCES, etc., as was the case with qmake.
How does all this work?
For starters, I recommend to get acquainted with the
helpThe basic concepts of the language are: Project (Project), Product (Product), Artifact (Artifact), Module (Module), Rule (Rule), Group (Group), Dependency (Depends), Tag (Tag).
The product is an analogue of pro or vcproj, i.e., one target for assembly.
A project is a collection of your products along with dependencies, perceived by the build system as one unit. One project - one graph assembly.
Tag - file classification system. For example, "* .cpp" => "cpp"
Rule - Conversion of project files marked with specific tags. Generates other files called artifacts. Typically, these are compilers or other build systems.
Artifact - the file over which is the output for the rule (and possibly the input for other rules). These are usually “obj”, “exe” files.
Many QML objects have a condition property that is responsible for whether or not they will be built. And if we need to split the files? To do this, they can be combined into a group (Group)
Group { condition: qbs.targetOS == "windows" files: [ "file1", ...] }
something like this.
What next?
A logical question, examples are great, but how can you go on a free swim with this system? Can:
- Read the documentation;
- Download the Qt Creator source and see how QBS is used there;
- To study the source code of QBS itself (as a last resort).
Conclusion
QBS provides us with the following advantages:
- Convenient and clear format config assembly
- High speed
- Clear modular architecture
But, unfortunately, it has the following (temporary disadvantages)
- The presence of a large number of bugs (this is not the alpha);
- Lack of IDE support (waiting in Qt Creator);
- The lack of a system for building packages, installers (in the plans).
Unfortunately, the format of the article does not allow to reveal all the details, in future plans to open the topic:
- Creating your own module (it is included in the archive with examples);
- Writing rules for the assembly;
- Creating js-modules and their inclusion;
- Creating your own product types;
- Work with global config and module configs;
- Writing your own plugin (for parsing dependencies of the .drpoj file).
All this can be in this article, and something that will write in the comments.
Link to the archive with all the examples for the article:
narod.ru/disk/49759080001.18d6748f8ef86e26c6dea2e2c5ed7d13/examples.zip.htmlArchive BONUS! an example of a module for assembling a DELPHI 2007 project not mentioned in the article (it is planned to do analysis in the next article)
Links
labs.qt.nokia.com/2012/02/15/introducing-qbs - presentation
doc-snapshot.qt-project.org/qbs - documentation
qt.gitorious.org/qt-labs/qbs - git
bugreports.qt-project.org/browse/QBS - bugtracker.
Note: Qt Build Salvation (Rescue for Qt Build) is the internal name of QBS, in the source tree's README.