Almost half a year later, a major update of the CQtDeployer deployment utility was released.
This update has many innovations, 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.
Download links
Installer:
The installer can be downloaded on the social page github
Snap
Attention
In the snap version, be sure to give the program access to read other processes. Since this is necessary to create an installer and a correct qt search.
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.
#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.
andrei@HP:~/Hello$ tree . ├── CMakeLists.txt ├── CMakeLists.txt.user └── main.cpp 0 directories, 3 files
Create a folder for the assembly.
andrei@HP:~/Hello$ mkdir build
Run the cmake in the created folder.
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
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.
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.
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.
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:
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.
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.
cqtdeployer init
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.
{ "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.
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.
1. Dstro1 - contains the application Hello1
2. 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, .
{ "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 .
-
Example:
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)
спасибо, за обзор!
Если будут вопросы, пишите. Найдем решение)
Супер. Спасибо!
Добрый день. У меня есть приложение с библиотеками собранными отдельно. Как мне сделать так, чтобы эти библиотеки помещались в установщик и при установке приложение были вместе с исполняемым файлом? И почему утилита при использовании -bin или -bindir создает ярылки для каких-то библиотек, но не для исполняемого файла? Я использую Windows.
Если все ваши библиотеки требуются для работы ./path/to/my/file.exe т они автоматически попадут в инсталятор. если ваши библиотеки очень далеко запрятаны от расположения json файла то можете по больше выставить значение "recursiveDepth": 5,
путь "./path/to/my/file.exe", должен обязательно начинается с "." и быть относительным от json файла.
Обратите внимание на то что в Windows версии все еще нужно явно указывать путь к qmake которым был собран проект.
Исключение составляет тот факт что если qmake уже прописан у вас в окружении PATH, тогда cqtdeployer будет использовать значение из PATH.
затем сохраняете ваш файл и повторно запускаете cqtdeployer.
что касается ярлыков на библиотеки то звучит как ошибка. Собирите максимум информации о ваших дествиях и опишите ошибку на GitHub
можно еще так:
это тоже самое, просто гораздо удобнее когда инициализация будет у вас записана в файл, и вам не придется постоянно водить эту длинную строку для развертывания.
LibDir вообще не видит библиотеки. Пробовал разные попытки записи, исходя из вашего сообщения. Библиотеки лежат рядом с исполняемым файлом, json там же. Если использовать binDir вместо bin тогда библиотеки добавляются. А при установке создадутся ярлыки на все библиотеки, но не на исполняемый файл. Оно так и должно работать?
нет, так не должно быть, вы уверены что ваш исполняемый файл зависит от ваших библиотек ? или он подключает их как плагины?
а с ярлыками это точно ошибка, уже завел задачу на это .
@Den125 можно взгялнуть на ваш проект ?
Мой исполняемый файл не зависит от библиотек. Библиотеки подключаются при необходимости в процессе работы программы.
тогда это плагины )
для них есть отделный флаг extraPlugin
Это сработало, но библиотеки при установке находятся в папке plugins. А можно их вынести к исполняемому файлу? Можно ли в установщик закинуть файл не библиотеку и не исполняемый, например *.jar?
тогда переместите ваши библиотеки из extraPlugin в bin
но появятся ярлыки, сейчас поправим
Ошибка с ярлыками в Windows исправлена в версиии 1.4.0.4