Развертывание Qt и QML приложений в Linux и Windows

Переносимость приложений, переносимость qt, Qt, Run Linux Application, QML, windows, deployment, cqtdeployer, Развертывание, deploy, linux

Введение

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

Для начало немного теории

Зачем это нужно?

Существует несколько способов сборки приложений, основные из них это:

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

  • Динамическая сборка. Отличается от статической тем, что в бинарнике будут лежать только исходные тексты вашего приложения (размер бинарника будет минимальный), но при выполнении такого приложения ему понадобятся сторонние библиотеки, которые использовались при его написании.

Теперь немного описания

Console-QtDeployer — это простая утилита, аналогичная windeployqt и macdeployqt . Но в отличие от аналогов имеет куда более гибкий интерфейс (флаги запуска) и более высокую скорость работы, к тому же она поддерживает 2 платформы windows и linux а это значит что теперь мы сможете собирать зависимости под windows на Linux и наоборот.

Давайте рассмотрим пример

Для примера я написал простое qt приложение с использованием qml — MyApp.

MyApp (main.cpp)

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

MyApp (main.qml)

import QtQuick 2.9
import QtQuick.Controls 2.2

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Scroll")

    ScrollView {
        anchors.fill: parent

        ListView {
            width: parent.width
            model: 20
            delegate: ItemDelegate {
                text: "Item " + (index + 1)
                width: parent.width
            }
        }
    }
}

MyApp слинкована динамически, то есть для работы ему требуются библиотеки qt. Если попробовать запустить приложение, сразу после сборки мы получим ошибку:

~/MyApp$ ./MyApp 
./MyApp: /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5: version `Qt_5' not found (required by ./MyApp)
./MyApp: /usr/lib/x86_64-linux-gnu/libQt5Gui.so.5: version `Qt_5' not found (required by ./MyApp)
./MyApp: /usr/lib/x86_64-linux-gnu/libQt5Core.so.5: version `Qt_5.11' not found (required by ./MyApp)
./MyApp: /usr/lib/x86_64-linux-gnu/libQt5Core.so.5: version `Qt_5' not found (required by ./MyApp)

Из сходных текстов мы видим, что приложение зависит от GUI библиотек qt и библиотек qml. Поиск и сборка всех ресурсов (библиотек и плагинов) займет очень много времени. Чтобы сэкономить время и силы, мы воспользуемся утилитой CQtDeployer (скачать можно здесь ) или установить в Snap Store

Загрузите из Snap Store

cqtdeployer -bin myApp -qmake /media/D/Qt/5.12.3/gcc_64/bin/qmake -qmlDir ./

После выполнения данной команды, вы получите полностью готовое для работы приложение с готовым лаунчером, который настроит все необходимое окружение для работы вашего приложения на всех машинах под управлением Linux.

Давайте подробнее рассмотрим некоторые из параметров CQtDeployer:

Опция Описание
help / h Показывает справку
always-overwrite Копирует файлы с заменой уже существующих
-bin [list, params] Развертываемый файл или папка. пример -bin ~/my/project/bin/,~/my/project/bin.exe
-binDir [params] Папка с развертываемыми файлами (с рекурсивным поиском). ВНИМАНИЕ! Этот флаг поддерживает только файлы 'so', 'dll' и 'exe'. Если вы хотите развернуть бинарный файл Linux, используйте флаг '-bin'
-qmlDir [params] Папка qml. пример -qmlDir ~/my/project/qml
deploySystem Копирует все библиотеки
-qmake [params] Путь к qmake. пример
-qmake ~/Qt/5.11.1/gcc_64/bin/qmake
-ignore [list,params] Список библиотек для игнорирования
Пример -ignore libicudata.so.56,libicudata2.so.56
-ignoreEnv [list,params] Список путей для игнорирования.
Пример -ignoreEnv /bad/dir,/my/bad/Dir
clear Удаляет все старые файлы (с прошлого запуска)
пример -runScript myApp.sh
allQmlDependes Извлекает все библиотеки qml.
(не рекомендуется, так как занимает много памяти)
-libDir [list,params] Устанавливает дополнительные пути к библиотекам
Пример -libDir ~/myLib,~/newLibs
-extraPlugin [list,params] Устанавливает дополнительный путь для extraPlugin приложения
-recursiveDepth [params] Устанавливает глубину поиска библиотек (по умолчанию 0)
-targetDir [params] Устанавливает целевой каталог (по умолчанию это путь к первому развертываемому файлу)
noStrip Пропускает шаг strip
noTranslations Пропускает файлы переводов
qmlExtern Использует внешний сканер qml (qmlimportscaner)
не работает без qmake и в snap
-verbose [0-3] Показывает дебаг лога

Итог

После выполнения cqtdeployer у вас появится папка Distro c уже готовым приложением со всеми его зависимостями содержимое этой папки должно выглядеть примерно следующим образом:

drwxr-xr-x 7 andrei andrei 4096 May 24 12:22 ./
drwxrwxr-x 3 andrei andrei 4096 May 24 12:22 ../
drwxr-xr-x 2 andrei andrei 4096 May 24 12:22 bin/
drwxr-xr-x 2 andrei andrei 4096 May 24 12:22 lib/
-rwx---rwx 1 andrei andrei  433 May 24 12:22 myApp.sh*
drwxr-xr-x 6 andrei andrei 4096 May 24 12:22 plugins/
drwxr-xr-x 5 andrei andrei 4096 May 24 12:22 qml/
drwxr-xr-x 2 andrei andrei 4096 May 24 12:22 translations/


cqtdeployer result

  • myApp.sh — скрипт запуска вашего приложения
  • bin — папка с вашим бинарником
  • lib — папка со всеми необходимыми зависимости вашего приложения
  • plugins — qt плагины, необходимые для работы приложения
  • qml — зависимости qml.
  • translations — стандартные переводы qt.

Таким образом можно подготовить ваше приложения для упаковки в deb или snap пакет, после чего можно приступить к его распространению. Учитывайте, что после выполнения cqtdeployer, ваше приложение необходимо запускать с помощью sh скрипта, который настроит для вашего приложения необходимое окружение.

Для Windows все точно так же. только в консоли нужно будет писать не cqtdeployer а %cqtdeployer%

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
TT
13 июня 2019 г. 19:01
Taimoor Tanweer

C++ - Тест 001. Первая программа и типы данных

  • Результат:66баллов,
  • Очки рейтинга-1
TT
13 июня 2019 г. 18:51
Taimoor Tanweer

C++ - Тест 002. Константы

  • Результат:75баллов,
  • Очки рейтинга2
ВМ
13 июня 2019 г. 12:30
Ваня Мороз

C++ - Тест 001. Первая программа и типы данных

  • Результат:100баллов,
  • Очки рейтинга10
Последние комментарии
i
17 июня 2019 г. 6:10
ingenfly

Только по осям xAxis2, уAxis2 значения начинаются с 0. Почему-то xAxis2 и xAxis не синхронизированы по данным. Ну и QCustomPlot последний.
16 июня 2019 г. 20:21
Евгений Легоцкой

Добрый день. Ну точно также добавляете ту же самую информацию на ось xAxis2, только добавляете другое форматирование customPlot->xAxis2->setDateTimeFormat("hh:mm"); если я ...
EF
14 июня 2019 г. 13:56
Egor Fomin

Спасибо за ваш ответ, у меня получилось реализовать это. Тем не менее появилась другая проблема, поэтому опять надеюсь на вашу помощь. Скажем, я уже выставил точки и они соеденены. Когда я нач...
d
13 июня 2019 г. 14:47
damix

Можно классу, который описывает точку, добавить сигнал, который подавать (emit), когда точка перемещается (переопределить mouseMoveEvent или mouseReleaseEvent). Так вот эти сигналы у каждой из...
i
13 июня 2019 г. 14:09
ingenfly

Здравствайте! Подскажите, пожалуйста: customPlot->xAxis2->setTickLabels(true); //Здесь включается отображение данных на оси xAxis2. а можно как-то продублировать информацию cus...
Сейчас обсуждают на форуме
I
19 июня 2019 г. 13:41
Intruder

Всем добрый день. При разборе XML файла наткнулся на тег вот такого плана: <TagName attribute1="value1" attribute2="value2" /> При попытке проверить на наличие такого элеме...
19 июня 2019 г. 12:55
Михаиллл

Скажите пожалуйста, как его в таком случае перемещать и удалять?
18 июня 2019 г. 19:50
Дмитрий

Большое спасибо! SDK заработал.К сожалению удалось продвинутся только на один шаг. При сборке чистого проекта NDK выдаёт следующие ошибки C:\Android\ndk-bundle/toolchains/arm-linux-andr...
18 июня 2019 г. 16:59
Михаиллл

Добрый день.В этом учебнике представлен код INSTALLED_APPS = ( ... 'rest_framework', 'snippets.apps.SnippetsConfig',) На строчке 'snippets.apps.SnippetsConf...
18 июня 2019 г. 14:24
Михаиллл

Спасибо, работает.Послушаю вашего совета.
Ищу работу?
25,000.00 руб. - 30,000.00 руб.
Разработчик Qt/C++
Barnaul, Altai Krai, Russia

Для зарегистрированных пользователей на сайте присутствует минимальное количество рекламы

EVILEG
О нас
Услуги
Присоединяйтесь к нам
© EVILEG 2015-2019
Рекомендует хостинг TIMEWEB