# Релиз CQtDeployer v1.4.0 (Binary Box)

Релиз утилиты развертывания С++/Qt и QML приложений CQtDeployer v1.4.0 (Binary Box)

Спустя почти полгода, вышло мажорное обновление утилиты развёртывания CQtDeployer.
В данном обновлении множество нововведений, но основной упор в сделан на создание пакетов. 

## Полный список всех изменений

### Исправления 
- Исправлен вывод справки в консоли, теперь перед выводом пересчитывается реальный размер консоли, что позволяет выполнять переносы текста правильно. 
- Исправлена работа с развертыванием плагинов Qt. Теперь плагины не тянут за собой все системные зависимости, а только qt. Захват системных зависимостей приводил к падению приложений из-за несовместимости библиотек плагинов.
- Мелкие исправления и улучшения. 
### Нововведения
- Добавлена поддержка поиска qmake из системного окружения.
- Добавлена возможность инициализировать репозиторий для дальнейшей упаковки аналогично git init.
- Добавлена поддержка Qt Install Framework пакетов. Теперь можно запаковать дистрибутив в инсталлятор.
- Добавлена возможность разбивать конечный дистрибутив на несколько пакетов.
- Добавлен механизм, позволяющий унифицировать создание пакетов для конечного дистрибутива. 
- Добавлена поддержка добавления пользовательских скриптов в скрипты запуска приложений.
- Добавлена поддержка сборки системных зависимостей для Windows.
- Добавлена поддержка RPATH для Linux. Теперь cqtdeployer может самостоятельно определить нужный qmake для развертывания приложения.
- Добавлена поддержка поиска необходимой зависимости по имени библиотеки. 
- Добавлена поддержка Qt библиотек из репозиториев Linux дистрибутивов.
### Новые опции
- init - инициализирует файл cqtdeployer.json (файл конфигурации). Например: «cqtdeployer init» - для инициализации конфигурации одного пакета. "cqtdeployer -init multiPackage" - для инициализации конфигурации нескольких пакетов.
- noCheckRPATH - отключает автоматический поиск путей к qmake в исполняемых файлах (Только Linux).
- noCheckPATH - отключает автоматический поиск путей к qmake в системном окружении.
- extractPlugins - заставляет извлекать все зависимости плагинов.
- qif - создает инсталлятор в конце развертывания. 
- extraLibs - добавляет шаблон дополнительной библиотеки, которая должна будет попасть в дистрибутив. 
- customScript - добавляет пользовательский скрипт в скрип запуска приложения. 
- -targetPackage [package;tar1,package;tar2] - используется для формирования пакетов, обозначает списки целевых файлов для определенных пакетов. 
- recOut - указывает в какую папку будут складываться ресурсы после развертывания. 
- name - устанавливает имя пакета.
- description - устанавливает описание пакета
- deployVersion - устанавливает версию пакета
- releaseDate - дата релиза пакета.
- icon - иконка пакета.
- publisher - издатель пакета. 
- qifStyle - Устанавливает путь к CSS файлу стиля или устанавливает стиль по умолчанию. Доступные стили: quasar
- qifBanner - Устанавливает путь к png-файлу баннера.
- qifLogo - Устанавливает путь к файлу логотипа png.

## Подробный разбор самых интересных изменений.

Первое, на что стоит обратить внимание, это то что CQtDeployer научился работать с RPATH (Только Linux) и PATH. Это значит, что если ваше приложение собранно с поддержкой RPATH (а RPATH в qt включен по молчанию) или ваш qmake прописан в PATH, то вам не нужно указывать путь к qmakе. CQtDeployer сам найдет нужный ему qmake. 
Давайте проверим это на практике.
Я написал простое консольное приложение с использованием Qt. 
``` cpp
#include <QString>
#include <QDebug>
int main(int, char *[])
{
    QString str = "hello CQtDeployer 1.4";
    qInfo() << str;
    return 0;
}
```

Я буду использовать сборочную систему cmake, так как она более актуальная чем qmake.

``` bash
andrei@HP:~/Hello$ tree 
.
├── CMakeLists.txt
├── CMakeLists.txt.user
└── main.cpp

0 directories, 3 files
```

Создадим папку для сборки.
``` bash
andrei@HP:~/Hello$ mkdir build 
```

Выполним в созданной папке cmake.

``` 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
```

Выполняем сборку.

``` 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
```

Проверяем нашу программу.
``` bash
andrei@HP:~/Hello/build$ ls
CMakeCache.txt  CMakeFiles  cmake_install.cmake  Hello  Hello_autogen  Makefile
```
И запускаем cqtdeployer передав ему программу без 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!
```

О чудо, теперь наше приложение полностью автономно. 
Проверяем это. 

``` 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$ 
```
Корень программы: 

![image](https://user-images.githubusercontent.com/12465465/77245272-619a0280-6c2e-11ea-92f2-447563f72dcc.png)

Библиотеки,нужные для работы программы:

![image](https://user-images.githubusercontent.com/12465465/77245274-6363c600-6c2e-11ea-8729-7d494a073b66.png)


Как видно из примера, приложение полностью собрано.

## Qt Installer Framework
Второе нововведение, о котором стоит знать, это возможность из коробки формировать установщики QIF. Все, что нужно для нашего примера, это добавить в команду на упаковку опцию qif.

Пример использования. 

```
andrei@HP:~/Hello/build$ cqtdeployer -bin Hello qif 
```

Всего одна простая команда и программа получает презентабельный вид.

![image](https://user-images.githubusercontent.com/12465465/77245315-b3428d00-6c2e-11ea-9326-c23229020eb5.png)

Этот установщик поддерживает минимальную интеграцию Linux дистрибутивами и Windows. А именно: создание ярлыков, и регистрация приложения в OС. 
Если по каким то причинам вас не устраивает внешний вид данного установщика, его можно изменить при помощи флага qifStyle . На момент версии 1.4 cqtdeployer поддерживает всего 2 стиля (native и quasar). 

Пример стиля quasar:

![image](https://user-images.githubusercontent.com/12465465/77245334-d2d9b580-6c2e-11ea-9e55-e205499a9219.png)

Вы также можете использовать свою собственную таблицу стилей qss. Для этого вместо названия стиля передайте путь к вашему qss или css файлу.
Для примера можно рассмотреть следующую таблицу стилей qss. 

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%));
}
```       

Давайте проверим, что у нас получится в таком случае.
``` bash
cqtdeployer -bin Hello qif -qifStyle ./../style.qss
```

![image](https://user-images.githubusercontent.com/12465465/77245346-00266380-6c2f-11ea-8426-42bf58038458.png)

Вот,собственно, и тёмная тема установщика. 

## Разбиение на пакеты  
И,наверное, последнее важное обновление, о котором стоит знать — это возможность разделять большой многобинарный проект на подпроекты. 

Эта возможность самая сложная из всех перечисленных, так как требует много текста для ее использования. Так что я рекоммендую использовать файл конфигураций. 

Для начала усложним наш проект, добавив в него ещё 2 исполняемого файла. Я не стал заморачиваться и просто сделал 2 копии моей Hello утилиты. 

Для упрощения работы с пакетами нужно инициализировать директорию.  

``` bash
cqtdeployer init
```

Это еще одна новая функция, которая создаёт CQtDeployer.json файл, в котором мы и будем писать наши конфигурации, вместо передачи опций в утилиту.

``` js
{
    "binDir": ".",
    "clear": true,
    "libDir": "./",
    "recursiveDepth": 5
}
```

Теперь давайте сделаем 2 пакета из 3х наших программ. Для этого нужно указать:
```js
{
    "binDir": ".",
    "clear": true,
    "libDir": "./",
    "recursiveDepth": 5,
    "targetPackage": [
        ["Dstro1", "Hello1"],
        ["Dstro2", "Hello2"],
        ["Dstro2", "Hello3"]
    ]
}
```

Обратите внимание на то, что мне пришлось явно указать привязку для Dstro2 к  Hello2  Hello3, К сожалению, на момент версии 1.4 cqtdeployer не умеет парсить перечисления целей. Обратите внимание, что если я напишу вместо Hello1 Hello, то выборка будет сделана по всем совпадениям и будут выбраны все 3 программы. 
Итак, смотрим что получилось.

``` 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
```

Как видно из дерева результата, у нас получилось 2 дистрибутива. 
1. Dstro1 — содержит в себе приложение Hello1
2. Distro2 — содержит оставшиеся 2.

А теперь давайте проверим, что будет, если все это запаковать а установщик. Добавим в CQtDeployer.json опцию qif **"qif": true,**.

``` js
{
    "binDir": ".",
    "clear": true,
    "qif": true,
    "libDir": "./",
    "recursiveDepth": 5,
    "targetPackage": [
        ["Dstro1", "Hello1"],
        ["Dstro2", "Hello2"],
        ["Dstro2", "Hello3"]
    ]
```

![image](https://user-images.githubusercontent.com/12465465/77245542-534ce600-6c30-11ea-9323-72ec5e200f39.png)

Кака видно из скриншота, теперь у нас 2 пакета при установке.

## Новые алиасы

И последнее небольшое но приятное дополнение: теперь в cqtdeployer добавлены новые команды.
* сqt — бывстрый способ задеплоить ваше приложение. Он упрощает вызов развертывания.
    * Пример:
        **cqt myApp** — это тоже самое что и **cqtdeployer -bin  myApp**.
* cqtdeployer.cqt — тоже что и cqt но для snap пакета.
* В windows-версии теперь не нужно добовлять знак % для вызова утилиты. 
Теперь вызов выглядит так, как и в Linux. (cqtdeployer)
