Спустя почти полгода вышло крупное обновление утилиты развертывания CQtDeployer.
В этом обновлении много нововведений, но основной упор сделан на создание пакетов.
CQtDeployer 1.4.0
Исправления
- Исправлен вывод справки в консоль, теперь перед выводом пересчитывается реальный размер консоли, что позволяет корректно передавать текст.
- Исправлена работа с деплоем плагинов Qt. Теперь плагины извлекают не все системные зависимости, а только qt. Извлечение системных зависимостей приводило к сбою приложений из-за несовместимых библиотек плагинов.
- Мелкие исправления ошибок и улучшения.
Новые особенности
- Добавлена поддержка поиска qmake из системной среды.
- Добавлена возможность инициализировать репозиторий для дальнейшей упаковки, аналогично git init.
- Добавлена поддержка пакетов Qt Install Framework. Теперь можно запаковать дистрибутив в установщик.
- Добавлена возможность разбивать конечный дистрибутив на несколько пакетов.
- Добавлена возможность унифицировать создание пакетов для финальной раздачи.
- Добавлена поддержка добавления пользовательских скриптов в скрипты запуска приложений.
- Добавлена поддержка извлечения системных зависимостей для Windows.
- Добавлена поддержка RPATH для Linux. Теперь cqtdeployer может самостоятельно определить необходимый qmake для развертывания приложения.
- Добавлена поддержка поиска нужной зависимости по имени библиотеки.
- Добавлена поддержка библиотек Qt из репозиториев дистрибутивов Linux.
- Добавлен новый псевдоним для команды запуска (cqt и cqtdeployer.cqt) для быстрого развертывания приложений.
- Добавлена поддержка нативного имени команды для windows. Теперь вы можете запустить cqtdeployer из команды cqtdeployer в cmd и powershell.
Новые опции
- init - инициализирует файл cqtdeployer.json (файл конфигурации). Например: «cqtdeployer init» — для инициализации конфигурации базового пакета. «cqtdeployer -init multi» — для инициализации конфигурации нескольких пакетов.
- noCheckRPATH - отключает автоматический поиск путей к qmake в исполняемых файлах (только для Linux).
- noCheckPATH - отключает автоматический поиск путей к qmake в системном окружении.
-
ExtractPlugins - принудительно извлекает все зависимости плагинов.
-qif - создает установщик в конце развертывания. - extraLibs - добавляет шаблон для дополнительной библиотеки, которая должна быть включена в дистрибутив.
-
customScript - добавляет пользовательский скрипт в скрипт запуска приложения.
--targetPackage [пакет; tar1, пакет; tar2] — используется для формирования пакетов, обозначает списки целевых файлов для конкретных пакетов.
— recOut — указывает, в какую папку будут добавлены ресурсы после развертывания. - name - задает имя пакета.
- description - устанавливает описание пакета
- deployVersion — устанавливает версию пакета
- releaseDate — устанавливает дату выпуска пакета.
- icon - задает значок пакета.
- publisher - устанавливает издателя пакета.
- qifStyle - Задает путь к файлу стилей CSS или задает стиль по умолчанию. Доступные стили: квазар
- qifBanner - Устанавливает путь к png файлу баннера.
- qifLogo - Устанавливает путь к png файлу логотипа.
Ссылки для скачивания
Установщик:
Установщик можно скачать на социальной странице github
Snap
Внимание
В снап-версии обязательно дайте программе доступ на чтение других процессов. Так как это необходимо для создания установщика и корректного поиска qt.
Подробный разбор самых интересных изменений.
Первое, на что следует обратить внимание, это то, что CQtDeployer научился работать с RPATH (только для Linux) и PATH. Это означает, что если ваше приложение собрано с поддержкой RPATH (а RPATH в qt включен по умолчанию) или ваш qmake прописан в PATH, то вам не нужно указывать путь к qmake. CQtDeployer сам найдет qmake.
Проверим на практике.
Я создал простое консольное приложение с помощью Qt.
#include <QString> #include <QDebug> int main(int, char *[]) { QString str = "hello CQtDeployer 1.4"; qInfo() << str; return 0; }
Я буду использовать систему сборки cmake, так как она более актуальна, чем qmake.
andrei@HP:~/Hello$ tree . ├── CMakeLists.txt ├── CMakeLists.txt.user └── main.cpp 0 directories, 3 files
Создайте папку для сборки.
andrei@HP:~/Hello$ mkdir build
Запустите cmake в созданной папке.
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
создание проекта
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
Проверяем нашу программу.
andrei@HP:~/Hello/build$ ls CMakeCache.txt CMakeFiles cmake_install.cmake Hello Hello_autogen Makefile
И запускаем cqtdeployer минуя его программу без 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!
О чудо, теперь наше приложение полностью автономно.
Проверьте это.
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$
Корень программы:
Библиотеки необходимые для работы программы:
Как видно из примера, приложение полностью собрано.
Каркас установщика Qt
Второе новшество, о котором стоит знать, — это возможность формировать QIF-установщики из коробки. Все, что нужно для нашего примера, это добавить опцию qif в команду упаковки.
Пример использования.
andrei@HP:~/Hello/build$ cqtdeployer -bin Hello qif
Всего одна простая команда и программа приобретает презентабельный вид.
Этот установщик поддерживает минимальную интеграцию дистрибутивов Linux и Windows. А именно: создание ярлыков, и регистрация приложения в ОС.
Если вас по какой-то причине не устраивает внешний вид этого установщика, вы можете изменить его с помощью флага qifStyle. На момент версии 1.4 cqtdeployer поддерживает только 2 стиля (native и quasar).
Пример стиля квазара:
Вы также можете использовать свою собственную таблицу стилей qss. Для этого передайте путь к вашему qss или css файлу вместо имени стиля.
Например, рассмотрим следующую таблицу стилей qss.
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%)); }
Давайте проверим, что мы получаем в этом случае.
cqtdeployer -bin Hello qif -qifStyle ./../style.qss
Вот, собственно, и темная тема установщика.
Разбивка на пакеты
И, наверное, последнее важное обновление, о котором стоит знать, — это возможность разбивать большой мультибинарный проект на подпроекты.
Эта функция самая сложная из всех перечисленных, так как для ее использования требуется много текста. Поэтому я рекомендую использовать файл конфигурации.
Для начала усложним наш проект, добавив в него еще 2 исполняемых файла. Я не стал заморачиваться и просто сделал 2 копии своей утилиты Hello.
Для упрощения работы с пакетами необходимо инициализировать каталог.
cqtdeployer init
Это еще одна новая функция, которая создает файл CQtDeployer.json, в который мы будем писать наши конфигурации, вместо того, чтобы передавать параметры утилите.
{ "binDir": ".", "clear": true, "libDir": "./", "recursiveDepth": 5 }
Теперь сделаем 2 пакета из 3-х наших программ. Для этого укажите:
{ "binDir": ".", "clear": true, "libDir": "./", "recursiveDepth": 5, "targetPackage": [ ["Dstro1", "Hello1"], ["Dstro2", "Hello2"], ["Dstro2", "Hello3"] ] }
Обратите внимание, что мне пришлось явно указать привязку Dstro2 к Hello2 Hello3. К сожалению, во время версии 1.4 cqtdeployer не мог анализировать целевые перечисления. Обратите внимание, что если я напишу вместо Hello1 Hello, то отбор будет производиться по всем совпадениям и будут выбраны все 3 программы.
Итак, давайте посмотрим, что произошло.
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. Dstro2 - содержит оставшиеся 2.
Теперь проверим, что будет, если все это запаковать установщиком. Добавьте для параметра qif значение true в CQtDeployer.json: qif: true, .
{ "binDir": ".", "clear": true, "qif": true, "libDir": "./", "recursiveDepth": 5, "targetPackage": [ ["Dstro1", "Hello1"], ["Dstro2", "Hello2"], ["Dstro2", "Hello3"] ]
Как видно из скриншота, теперь у нас 2 пакета при установке.
Новые псевдонимы
И последнее небольшое, но приятное дополнение: теперь в cqtdeployer добавлены новые команды.
сqt — — это быстрый способ развернуть ваше приложение. Это упрощает вызов развертывания.
-
Пример:
cqt myApp — это то же самое, что cqtdeployer -bin myApp .
-
Пример:
cqtdeployer.cqt - то же, что и cqt, но для пакета snap.
В windows-версии теперь не нужно добавлять знак % для вызова утилиты.
В версии для windows теперь нет необходимости добавлять знак % для вызова утилиты.
Теперь вызов выглядит как в 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