Реклама

Qt WinAPI - Урок 004. QtIFW - Автоматизация WinDeployQt и сборки инсталляторов с Qt Installer Framework

TutorialQtQt, Qt Installer Framework, QtIFW, windeployqt219

Правильный программист - это ленивый программист. Если есть возможность что-то автоматизировать, то обязательно нужно это сделать. Например, можно сделать автоматическое выполнение windeployqt со сборкой онлайн и оффлайн инсталляторов, а также подготовкой репозитория приложения с помощью Qt Installer Framework и чёрной магии QMake .

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

Но автоматизацию windeployqt оставим в основном проекте.

Структура проекта

Итак, имеем проект, с двумя подпроектами:

  1. Hello.pro - проект приложения
  2. Installer.pro -  проект инсталлятора

Основной проект представляет собой самый обычный "Hello world", но самый большой интерес заключается в скрипте QMake, который отвечает за windeployqt приложения.

Второй проект имеет минимальную структуру для сборки оффлайн и онлайн инсталляторов, а также сборки репозитория. Скрипт QMake в профайле проекта также содержит необходимую информацию для автоматизации сборки инсталляторов.

Автоматизация WinDeployQt

HelloInstaller.pro

Данный файл имеет традиционное содержание для subdirs проекта.

TEMPLATE = subdirs

CONFIG += ordered

SUBDIRS += \
    Hello \
    Installer

Hello.pro

Помимо обычного указания директорий сборки исполняемого файла, а также других выходных файлов проекта, в данном QMake скрипте выполняется запуск утилиты windeployqt .

QT += core
QT -= gui

CONFIG += c++11

TARGET = Hello
CONFIG += console
CONFIG -= app_bundle

TEMPLATE = app

# Выбираем директорию сборки исполняемого файла
# в зависимости от режима сборки проекта
CONFIG(debug, debug|release) {
    DESTDIR = $$OUT_PWD/../../HelloDebug
} else {
    DESTDIR = $$OUT_PWD/../../HelloRelease
}
# разделяем по директориям все выходные файлы проекта
MOC_DIR = ../common/build/moc
RCC_DIR = ../common/build/rcc
UI_DIR = ../common/build/ui
unix:OBJECTS_DIR = ../common/build/o/unix
win32:OBJECTS_DIR = ../common/build/o/win32
macx:OBJECTS_DIR = ../common/build/o/mac

# в зависимости от режима сборки проекта
# запускаем win deploy приложения в целевой директории, то есть собираем все dll
CONFIG(debug, debug|release) {
    QMAKE_POST_LINK = $$(QTDIR)/bin/windeployqt $$OUT_PWD/../../HelloDebug
} else {
    QMAKE_POST_LINK = $$(QTDIR)/bin/windeployqt $$OUT_PWD/../../HelloRelease
}

SOURCES += main.cpp

Если с указанием сборки папки исполняемого файла всё ясно, то разберёмся с тем, что же происходит при выполнении windeployqt.

QMAKE_POST_LINK - это директива, указывающая действия после завершения сборки проекта. То есть то, что мы выполняем после того, как был собран исполняемый файл.

$$(QTDIR) - переменная, которая содержит путь к комплекту сборки Qt. В моём случае это D:\Qt\5.7\mingw53_32.

Для выполнения windeployqt не обязательно указывать исполняемый файл, достаточно указать в качестве аргумента папку, где этот файл находится. В результате, по завершении сборки проекта, будет выполнена автоматическая сборка необходимых для приложения dll , и они будут помещены рядом с исполняемым файлом.

Сборка инсталляторов и репозитория

Сборка инсталляторов и онлайн репозитория проекта производится с помощью Qt Installer Framework, который содержит в своём составе утилиты, как для сборки самих инсталляторов, так и для подготовки репозитория приложения.

Для сборки будут использоваться две утилиты из этого фреймворка:

  • binarycreator - утилита для сборки инсталлятора;
  • repogen - утилита для подготовки онлайн репозитория.

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

Структура директорий

Рассмотрим структуру проекта:

  • config - в которой находится конфигурационный файл инсталлятора:
    • config.xml - в данном файле будет содержаться информация об удалённом репозитории, версии, названии проекта и т.д.
  • packages - в котором будут находиться пакеты, из которых будут собираться инсталляторы, например:
    • ru.evileg.helloinstaller - директория первого пакета
      • meta - директория, которая содержит инсталляионные скрипты, которые будут описывать специфичный функционал, например, закрытие активного экземпляра приложения, если производится обновление приложения, или прописывание информации в реестр системы.
        • package.xml - в минимальном варианте требуется наличие данного файла, который будет  описываться версию и дату сборки проекта. Эта информация потребуется для формирования файла Updates.xml, который будет помещён в онлайн репозиторий.
      • data - в данную директорию необходимо будет поместить исполняемый файл и все необходимые dll, ресурсные файлы, файлы переводов и т.д. То есть всё, что необходимо для сборки рабочего приложения.
    • ru.evileg.ecolor -  а также, например, директория второго пакета с содержимым, которое сходно по структуре с предыдущим вариантов.

config.xml

Файл, в котором описана служебная информация об издателе, пути установки приложения, его версии и названии. А также приводится информация об адресе удалённого репозитория. Данная информация будет одинакова, как для онлайн инсталлятора, так и для оффлайн инсталлятора. Ведь нам нужно будет помимо прочего ещё и обновлять приложение, поэтому для обоих версий инсталляторов нужна информация об удалённом репозитории.

<?xml version="1.0" encoding="UTF-8"?>
<Installer>
    <Name>Hello Installer</Name>
    <Version>1.0.0</Version>
    <Title>1.0.0 Installer</Title>
    <Publisher>EVILEG</Publisher>
    <StartMenuDir>HelloInstaller</StartMenuDir>
    <TargetDir>@RootDir@Program Files (x86)\EVILEG\HelloInstaller</TargetDir>
        <AllowSpaceInPath>true</AllowSpaceInPath>
    <RemoteRepositories>
        <Repository>
            <Url>http://www.evileg.ru/software/helloinstaller/</Url>
        </Repository>
    </RemoteRepositories>
</Installer>
  • Installer - формируемый инсталлятор
    • Name - Наименование приложения
    • Version - Версия приложения
    • Title - Заглавие окна инсталлятора
    • Publisher - Издатель
    • StartMenuDir - указывает группу продуктов, к которой принадлежит приложение в стартовом меню Windows.
    • TargetDir - папка установки приложения; @RootDir@ - корневая папка. В данном случае C:\
      • AllowSpaceInPath - разрешить пробелы в пути к директории
    • RemoteRepositories - список репозиториев
      • Repository - один из онлайн репозиториев, их может быть несколько, либо они могут даже заменяться
      • Url - адрес репозитория

package.xml

Здесь уже указывается дополнительная информация о порядке установки приложения в систему, то есть наличие определённых форм, окон, установочных скриптов, например, для занесения информации в реестр. Также добавлена информация о дате выпуска приложения, что также будет помещено в файл Updates.xml.

Данный файл должен содержаться в каждом пакете. Инсталлятор может предоставлять возможность установке ряда компонентов, вспомните инсталлятор Qt, там много пунктов. Соответственно каждый такой пакет представляет свой пункт.

<?xml version="1.0" encoding="UTF-8"?>
<Package>
    <DisplayName>Hello Installer</DisplayName>
    <Description>The main component</Description>
    <Version>1.0.0</Version>
    <ReleaseDate>2016-07-30</ReleaseDate>
        <Default>true</Default>
    <Name>ru.evileg.helloinstaller</Name>
    <ForcedInstallation>true</ForcedInstallation>
    <RequiresAdminRights>true</RequiresAdminRights>
</Package>
  • DisplayName - наименование компонента. Обязательный тег.
  • Description - описание компонента. Обязательный тег.
  • Version - версия компонентаю. Обязательный тег.
  • ReleaseDate - дата выпуска. Обязательный тег.
  • Default - выбор компонента по умолчанию, то есть выбран компонент для установки, или нет.
  • Name - идентификатор пакета в виде доменного имени. Обязательный тег.
  • ForcedInstallation - указывает, что компонент обязателен к установке и пользователь не может его исключить из установки
  • RequiresAdminRights - указывает, что пакет должен устанавливаться с правами администратора. Поле необязательное. И самое интересное то, что в процессе работы инсталлятор может потерять данные права администратора. То есть для некоторых действий понадобится заново запрашивать у пользователя права администратора.

Installer.pro

Здесь представлен вариант со сборкой инсталляторов в отдельных папках для Release и Debug версий. А также подготовкой репозитория для Release версии.

Для сборки оффлайн инсталлятора воспользуемся утилитой binarycreator со следующими параметрами:

  • --offline-only - как видно из наименования, указывает, что собираем оффлайн инсталлятор
  • -c - указывает путь к конфигурационному файлу
  • -p -указывает путь к папке с пакетами, в процессе работы QtIFW сам разберётся с тем, как сформировать пакеты в инсталляторе с учётом их конфигурационных файлов и скриптов из папки meta

Примечание. Для онлайн версии инсталлятора всё тоже самое, только аргумент --offline-only заменяется на --online-only.

А для подготовки репозитория воспользуемся утилитой repogen , со следующими параметрами:

  • -p - указывает папку с пакетами
  • -i - указывает пакеты, которые необходимо включить в инсталлятор
  • -update - указывает, что необходимо обновить репозиторий по следующему пути. Если по этому пути нет репозитория, то будет создан новый.
# Before run make project, need to put executable file and dlls into
# $$PWD/installer/packages/ru.evileg.helloinstaller/data

TEMPLATE = aux

# В зависимости от режима сборки, определяем, куда именно будут собираться инсталляторы
CONFIG(debug, debug|release) {
    INSTALLER_OFFLINE = $$OUT_PWD/../../InstallerDebug/Hello.offline
    INSTALLER_ONLINE = $$OUT_PWD/../../InstallerDebug/Hello.online
    DESTDIR_WIN = $$PWD/packages/ru.evileg.helloinstaller/data
    DESTDIR_WIN ~= s,/,\\,g
    PWD_WIN = $$OUT_PWD/../../HelloDebug
    PWD_WIN ~= s,/,\\,g

    copydata.commands = $(COPY_DIR) $$PWD_WIN $$DESTDIR_WIN
    first.depends = $(first) copydata
    export(first.depends)
    export(copydata.commands)
    QMAKE_EXTRA_TARGETS += first copydata
} else {
    # Задаём переменные, которые будут содержать пути с названиями инсталляторов
    INSTALLER_OFFLINE = $$OUT_PWD/../../InstallerRelease/Hello.offline
    INSTALLER_ONLINE = $$OUT_PWD/../../InstallerRelease/Hello.online

    # Задаём переменную, которая должна содержать путь к папке с данными
    DESTDIR_WIN = $$PWD/packages/ru.evileg.helloinstaller/data
    DESTDIR_WIN ~= s,/,\\,g
    # Задаём путь откуда всё приложение с DLL-ками нужно будет скопировать
    PWD_WIN = $$OUT_PWD/../../HelloRelease
    PWD_WIN ~= s,/,\\,g

    # Прежде, чем выполнять сборку инсталляторов, необходимо скопировать файлы
    # из выходной папки проекта вместе со всеми DLL в папку data, которая относится
    # к собираемому пакету
    copydata.commands = $(COPY_DIR) $$PWD_WIN $$DESTDIR_WIN
    first.depends = $(first) copydata
    export(first.depends)
    export(copydata.commands)
    # задаём кастомную цель сборки, при которой сначала выполним компирование файлов
    # а потом уже и остальное, что следует по скрипту QMake
    QMAKE_EXTRA_TARGETS += first copydata
}

# Создаём цель по сборке Оффлайн Инсталлятора
INPUT = $$PWD/config/config.xml $$PWD/packages
offlineInstaller.depends = copydata
offlineInstaller.input = INPUT
offlineInstaller.output = $$INSTALLER_OFFLINE
offlineInstaller.commands = $$(QTDIR)/../../QtIFW2.0.3/bin/binarycreator --offline-only -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT}
offlineInstaller.CONFIG += target_predeps no_link combine

QMAKE_EXTRA_COMPILERS += offlineInstaller

# Создаём цель по сборке Онлайн Инсталлятора
INPUT = $$PWD/config/config.xml $$PWD/packages
onlineInstaller.depends = copydata
onlineInstaller.input = INPUT
onlineInstaller.output = $$INSTALLER_ONLINE
onlineInstaller.commands = $$(QTDIR)/../../QtIFW2.0.3/bin/binarycreator --online-only -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT}
onlineInstaller.CONFIG += target_predeps no_link combine

QMAKE_EXTRA_COMPILERS += onlineInstaller

# репозиторий будем собирать только в случае режима release
CONFIG(release, debug|release) {
    # Сборку репозитория производим после того, как были собраны Инсталляторы
    # Для этого воспользуемся QMAKE_POST_LINK вместо QMAKE_EXTRA_COMPILERS
    # Поскольку он хорошо для этого подходит
    QMAKE_POST_LINK += $$(QTDIR)/../../QtIFW2.0.3/bin/repogen -p $$PWD/packages -i ru.evileg.helloinstaller --update $$OUT_PWD/../../repository
}

DISTFILES += \
    packages/ru.evileg.helloinstaller/meta/package.xml \
    config/config.xml


Скачать архив с проектом Qt Installer Framework example

Видеоурок

@EVILEG 30 июля 2016 г. 22:03

Реклама

Реклама

Комментарии

Комментарии

Только авторизованные пользователи могут оставлять комментарии.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь

Реклама

Реклама