Release of C++/Qt and QML application deployment utility CQtDeployer v1.4.0 (Binary Box)
Almost half a year later, a major update of the CQtDeployer deployment utility was released. This update has many new futures, but the main emphasis is on creating packages.
CQtDeployer 1.4.0
Fixes
- Fixed The help output in the console, now the actual size of the console is recounted before the output, which allows you to correctly transfer text.
- Fixed work with the deployment of Qt plugins. Now plug-ins do not extract all system dependencies, but only qt. Extract system dependencies caused applications to crash due to incompatible plugin libraries.
- Minor bug fixes and improvements.
New features
- Added support for qmake search from the system environment.
- Added the ability to initialize the repository for further packaging, similar to git init.
- Added support for Qt Install Framework packages. Now you can pack the distribution into the installer.
- Added the ability to split the final distribution into several packages.
- Added the ability to unify the creation of packages for the final distribution.
- Added support for adding custom scripts to application launch scripts.
- Added support for extracting system dependencies for Windows.
- Added support for RPATH for Linux. Now cqtdeployer can independently determine the necessary qmake to deploy the application.
- Added support for finding the required dependency by library name.
- Added support for Qt libraries from Linux distributions repositories.
- Added new alias for the run command (cqt and cqtdeployer.cqt) for fast deploy of applications.
- Added support the native name of command for windows. Now you can run a cqtdeployer from cqtdeployer commnad in cmd and powershell.
New options
- init - will initialize cqtdeployer.json file (configuration file). For example: "cqtdeployer init" - to initialize the configuration of a base package. "cqtdeployer -init multi" - to initialize the configuration of several packages.
- noCheckRPATH - disables the automatic search for paths to qmake in executable files (Linux only).
- noCheckPATH - disables the automatic search for paths to qmake in the system environment.
- extractPlugins - forces to extract all plug-in dependencies.
- qif - creates an installer at the end of the deployment.
- extraLibs - adds a template for an additional library, which should be included in the distribution.
- customScript - adds a custom script to the startup script of the application.
- -targetPackage [package; tar1, package; tar2] - used to form packages, denotes lists of target files for specific packages.
- recOut - indicates in which folder the resources will be added after deployment.
- name - sets the name of the package.
- description - sets the package description
- deployVersion - sets the package version
- releaseDate - sets the release date of the package.
- icon - sets the package icon.
- publisher - sets the publisher of the package.
- qifStyle - Sets the path to the CSS style file or sets the default style. Available styles: quasar
- qifBanner - Sets path to the banner png file.
- qifLogo - Sets path to the logo png file.
A detailed analysis of the most interesting changes.
The first thing you should pay attention to is that CQtDeployer has learned to work with RPATH (Linux only) and PATH. This means that if your application is built with RPATH support (and RPATH in qt is enabled by default) or your qmake is registered in PATH, then you do not need to specify the path to qmake. CQtDeployer will find qmake for itself.
Let's test it in practice. I created a simple console application using Qt.
cpp
#include <QString>
#include <QDebug>
int main(int, char *[])
{
QString str = "hello CQtDeployer 1.4";
qInfo() << str;
return 0;
}
I will use the cmake build system, as it is more relevant than qmake.
bash
andrei@HP:~/Hello$ tree
.
├── CMakeLists.txt
├── CMakeLists.txt.user
└── main.cpp
0 directories, 3 files
Create a folder for the assembly.
bash
andrei@HP:~/Hello$ mkdir build
Run the cmake in the created folder.
bash
andrei@HP:~/Hello/build$ cmake .. -DCMAKE_PREFIX_PATH=~/Qt/5.14.1/gcc_64
-- Configuring done
-- Generating done
-- Build files have been written to: /home/andrei/Hello/build
building a project
bash
andrei@HP:~/Hello/build$ make
Scanning dependencies of target Hello_autogen
[ 25%] Automatic MOC and UIC for target Hello
[ 25%] Built target Hello_autogen
Scanning dependencies of target Hello
[ 50%] Building CXX object CMakeFiles/Hello.dir/Hello_autogen/mocs_compilation.cpp.o
[ 75%] Building CXX object CMakeFiles/Hello.dir/main.cpp.o
[100%] Linking CXX executable Hello
[100%] Built target Hello
Checking our program.
bash
andrei@HP:~/Hello/build$ ls
CMakeCache.txt CMakeFiles cmake_install.cmake Hello Hello_autogen Makefile
And we start cqtdeployer passing it the program without qmake.
bash
andrei@HP:~/Hello/build$ cqtdeployer -bin Hello
Deploy ...
flag targetDir not used. use default target dir : "/home/andrei/Hello/build/DistributionKit"
target deploy started!!
copy : "/home/andrei/Hello/build/Hello"
extract lib : "/home/andrei/Hello/build/DistributionKit//bin//Hello"
copy : "/home/andrei/Qt/5.14.1/gcc_64/lib/libQt5Core.so.5"
copy : "/home/andrei/Qt/5.14.1/gcc_64/lib/libicuuc.so.56"
copy : "/home/andrei/Qt/5.14.1/gcc_64/lib/libicui18n.so.56"
copy : "/home/andrei/Qt/5.14.1/gcc_64/lib/libicudata.so.56"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_ar.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_bg.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_ca.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_cs.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_da.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_de.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_en.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_es.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_fi.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_fr.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_gd.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_he.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_hu.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_it.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_ja.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_ko.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_lv.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_pl.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_ru.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_sk.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_uk.qm"
copy : "/home/andrei/Qt/5.14.1/gcc_64/translations/qtbase_zh_TW.qm"
try deploy msvc
deploy done!
Oh miracle, now our application is completely autonomous. Check it out.
bash
andrei@HP:~/Hello/build$ cd DistributionKit/
andrei@HP:~/Hello/build/DistributionKit$ tree
.
├── bin
│ ├── Hello
│ └── qt.conf
├── Hello.sh
├── lib
│ ├── libicudata.so.56
│ ├── libicui18n.so.56
│ ├── libicuuc.so.56
│ └── libQt5Core.so.5
└── translations
├── qtbase_ar.qm
├── qtbase_bg.qm
├── qtbase_ca.qm
├── qtbase_cs.qm
├── qtbase_da.qm
├── qtbase_de.qm
├── qtbase_en.qm
├── qtbase_es.qm
├── qtbase_fi.qm
├── qtbase_fr.qm
├── qtbase_gd.qm
├── qtbase_he.qm
├── qtbase_hu.qm
├── qtbase_it.qm
├── qtbase_ja.qm
├── qtbase_ko.qm
├── qtbase_lv.qm
├── qtbase_pl.qm
├── qtbase_ru.qm
├── qtbase_sk.qm
├── qtbase_uk.qm
└── qtbase_zh_TW.qm
3 directories, 29 files
andrei@HP:~/Hello/build/DistributionKit$
The root of the program:
Libraries needed for the program to work:
As you can see from the example, the application is fully assembled.
Qt Installer Framework
The second innovation worth knowing is the ability to form QIF installers out of the box. All that is needed for our example is to add the qif option to the packaging command.
Usage example.
andrei@HP:~/Hello/build$ cqtdeployer -bin Hello qif
Just one simple command and the program gets a presentable look.
This installer supports minimal integration of Linux distributions and Windows. Namely: creating shortcuts, and registering the application in the OS. If for some reason you are not satisfied with the appearance of this installer, you can change it using the qifStyle flag. At the time of version 1.4, cqtdeployer supports only 2 styles (native and quasar).
Example quasar style:
You can also use your own qss stylesheet. To do this, pass the path to your qss or css file instead of the style name. For example, consider the following qss stylesheet.
Style.qss:
css
QWidget
{
color: white;
background-color: rgb(65, 65, 65);
}
QPushButton
{
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(150, 150, 150, 60%), stop:1 rgba(50, 50, 50, 60%));
border-color: rgb(60, 60, 60);
border-style: solid;
border-width: 2px;
border-radius: 9px;
min-height: 20px;
max-height: 20px;
min-width: 60px;
max-width: 60px;
padding-left: 15px;
padding-right: 15px;
}
QPushButton:pressed, QPushButton:checked
{
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(50, 50, 50, 60%), stop:1 rgba(150, 150, 150, 60%));
}
Let's check what we get in this case.
bash
cqtdeployer -bin Hello qif -qifStyle ./../style.qss
Here, in fact, is the dark theme of the installer.
Splitting into packages
And, probably, the last important update worth knowing is the ability to split a large multi-binar project into subprojects.
This feature is the most difficult of all listed, since it requires a lot of text to use it. So I recommend using the configuration file.
To begin with, we will complicate our project by adding 2 more executable files to it. I did not bother and just made 2 copies of my Hello utility.
To simplify working with packages, you need to initialize the directory.
This is another new function that creates a CQtDeployer.json file, in which we will write our configurations, instead of passing options to the utility.
js
{
"binDir": ".",
"clear": true,
"libDir": "./",
"recursiveDepth": 5
}
Now let's make 2 packages of 3 of our programs. To do this, specify:
{
"binDir": ".",
"clear": true,
"libDir": "./",
"recursiveDepth": 5,
"targetPackage": [
["Dstro1", "Hello1"],
["Dstro2", "Hello2"],
["Dstro2", "Hello3"]
]
}
Please note that I had to explicitly specify the binding for Dstro2 to Hello2 Hello3. Unfortunately, at the time of version 1.4 cqtdeployer was not able to parse target enumerations. Please note that if I write Hello1 Hello instead, then the selection will be made for all matches and all 3 programs will be selected. So, let's see what happened.
bash
cqtdeployer
.
├── Dstro1
│ ├── bin
│ │ ├── Hello1
│ │ └── qt.conf
│ ├── Hello1.sh
│ ├── lib
│ │ ├── libicudata.so.56
│ │ ├── libicui18n.so.56
│ │ ├── libicuuc.so.56
│ │ └── libQt5Core.so.5
│ └── translations
│ ├── qtbase_ar.qm
│ ├── qtbase_bg.qm
│ ├── qtbase_ca.qm
│ ├── qtbase_cs.qm
│ ├── qtbase_da.qm
│ ├── qtbase_de.qm
│ ├── qtbase_en.qm
│ ├── qtbase_es.qm
│ ├── qtbase_fi.qm
│ ├── qtbase_fr.qm
│ ├── qtbase_gd.qm
│ ├── qtbase_he.qm
│ ├── qtbase_hu.qm
│ ├── qtbase_it.qm
│ ├── qtbase_ja.qm
│ ├── qtbase_ko.qm
│ ├── qtbase_lv.qm
│ ├── qtbase_pl.qm
│ ├── qtbase_ru.qm
│ ├── qtbase_sk.qm
│ ├── qtbase_uk.qm
│ └── qtbase_zh_TW.qm
└── Dstro2
├── bin
│ ├── Hello2
│ ├── Hello3
│ └── qt.conf
├── Hello2.sh
├── Hello3.sh
├── lib
│ ├── libicudata.so.56
│ ├── libicui18n.so.56
│ ├── libicuuc.so.56
│ └── libQt5Core.so.5
└── translations
├── qtbase_ar.qm
├── qtbase_bg.qm
├── qtbase_ca.qm
├── qtbase_cs.qm
├── qtbase_da.qm
├── qtbase_de.qm
├── qtbase_en.qm
├── qtbase_es.qm
├── qtbase_fi.qm
├── qtbase_fr.qm
├── qtbase_gd.qm
├── qtbase_he.qm
├── qtbase_hu.qm
├── qtbase_it.qm
├── qtbase_ja.qm
├── qtbase_ko.qm
├── qtbase_lv.qm
├── qtbase_pl.qm
├── qtbase_ru.qm
├── qtbase_sk.qm
├── qtbase_uk.qm
└── qtbase_zh_TW.qm
8 directories, 60 files
As you can see from the result tree, we got 2 distributions.
- Dstro1 - contains the application Hello1
- Dstro2 - contains the remaining 2.
Now let's check what happens if all this is packaged by the installer. Add the qif option to true in CQtDeployer.json: ** qif: true, **.
js
{
"binDir": ".",
"clear": true,
"qif": true,
"libDir": "./",
"recursiveDepth": 5,
"targetPackage": [
["Dstro1", "Hello1"],
["Dstro2", "Hello2"],
["Dstro2", "Hello3"]
]
As can be seen from the screenshot, now we have 2 packages during installation.
New aliases
And the last small but nice addition: now new commands have been added to cqtdeployer.
- сqt — is a quick way to deploy your application. It simplifies the deployment call.
- Example: cqt myApp — this is the same as cqtdeployer -bin myApp.
- cqtdeployer.cqt - same as cqt but for snap package.
- В windows-версии теперь не нужно добовлять знак % для вызова утилиты.
- In the windows version, now there is no need to add the% sign to call the utility. Now the call looks like in Linux. (cqtdeployer)