Введение
Скомпилированный Qt-исполняемый файл сам по себе обычно недостаточен для распространения конечным пользователям — он зависит от Qt-библиотек, плагинов, и иногда дополнительных runtime-компонентов, которые должны быть упакованы вместе с ним. В статье разберём специализированные инструменты упаковки для каждой платформы и их интеграцию в CI как часть автоматизированного процесса релиза.
Концепция
windeployqt (Windows) анализирует исполняемый файл, определяет реально используемые Qt-библиотеки и плагины (через анализ зависимостей и используемых Qt-модулей), и копирует их рядом с исполняемым файлом, формируя самодостаточный, переносимый набор файлов, готовый к распространению без необходимости установки Qt на машине конечного пользователя. linuxdeployqt выполняет аналогичную задачу для Linux, часто в сочетании с форматом AppImage, дающим единый, переносимый исполняемый файл, инкапсулирующий все зависимости. macdeployqt формирует полноценный .app-бандл macOS со всеми зависимостями внутри, готовый для распространения (опционально с последующей подписью кода и нотаризацией, специфичными требованиями Apple для распространения вне App Store).
Пример кода
# Windows — упаковка через windeployqt в рамках CI
- name: Упаковка релиза (Windows)
if: runner.os == 'Windows'
run: |
windeployqt build/Release/MyQtApp.exe --dir release_package
# ^ автоматически копирует Qt6Core.dll, Qt6Widgets.dll, плагины платформы и т.д.
# рядом с MyQtApp.exe в указанную директорию
- name: Архивация для распространения
if: runner.os == 'Windows'
run: Compress-Archive -Path release_package/* -DestinationPath MyQtApp-windows.zip
shell: pwsh
# Linux — упаковка через linuxdeployqt в формат AppImage
linuxdeployqt build/MyQtApp -appimage
# Результат: MyQtApp-x86_64.AppImage — единый, самодостаточный исполняемый файл,
# запускаемый на большинстве современных Linux-дистрибутивов без отдельной установки зависимостей
# macOS — упаковка через macdeployqt и опциональная подпись кода
macdeployqt build/MyQtApp.app -dmg
# Результат: MyQtApp.dmg — готовый для распространения образ диска с .app-бандлом внутри
# Подпись кода (требует действующего сертификата разработчика Apple)
codesign --deep --force --sign "Developer ID Application: Your Name" MyQtApp.app
Пояснения к коду
windeployqt build/Release/MyQtApp.exe --dir release_package показывает основной принцип всех трёх инструментов — анализ конкретного, уже скомпилированного исполняемого файла (а не исходного кода) для определения реально нужных зависимостей, что даёт более точный, минимальный набор копируемых файлов по сравнению с попыткой угадать или скопировать «все возможные» Qt-библиотеки без разбора. AppImage-результат linuxdeployqt показывает специфичный для Linux подход к распространению — единый файл, инкапсулирующий все зависимости, решает классическую проблему «зависимости от конкретной версии системных библиотек конкретного дистрибутива», делая распространение между разными Linux-дистрибутивами значительно проще, чем традиционные системные пакеты (deb/rpm), требующие совместимости именно с конкретной версией системных библиотек целевого дистрибутива. Подпись кода через codesign для macOS — необходимый шаг для распространения приложения, которое пользователи могут запустить без предупреждений системы безопасности Gatekeeper, блокирующих неподписанные приложения, загруженные из интернета.
Подводные камни
- Запуск
windeployqt/аналогичных инструментов на release-сборке без явной проверки результата на чистой, «девственной» виртуальной машине без установленного Qt SDK — успешная работа собранного, «задеплоенного» приложения на машине разработчика (где может быть установлен сам Qt SDK, скрывающий проблему отсутствия какой-либо реально нужной зависимости в итоговом пакете) не гарантирует, что то же самое сработает на машине конечного пользователя без Qt SDK вовсе; реальная проверка на чистом окружении (что естественно происходит в CI на свежей виртуальной машине) — критично важный шаг подтверждения корректности упаковки. - Отсутствие подписи кода для macOS-приложений, распространяемых за пределами App Store — без подписи (и для современных версий macOS — без нотаризации Apple) пользователи увидят предупреждение системы безопасности при попытке запустить приложение, что для многих обычных пользователей выглядит как явный признак потенциально вредоносного или «ненадёжного» ПО, существенно снижая доверие к легитимному приложению.
- Игнорирование специфичных требований к Qt-плагинам (платформенные плагины, плагины форматов изображений, плагины стилей) при ручной, неполной попытке скопировать зависимости вместо использования специализированных инструментов упаковки — Qt-приложения зависят не только от основных динамических библиотек (Qt6Core, Qt6Widgets), но и от набора плагинов, загружаемых динамически во время выполнения, и упущение нужных плагинов часто проявляется как неочевидная, на первый взгляд необъяснимая ошибка запуска («could not find or load the Qt platform plugin») именно на машине конечного пользователя, а не на машине разработчика.
- Хранение процесса упаковки только как ручной, недокументированной последовательности команд, выполняемых конкретным разработчиком перед каждым релизом, вместо интеграции в автоматизированный CI-пайплайн — без автоматизации процесс упаковки релиза становится подверженным человеческим ошибкам и забытым шагам, и интеграция упаковки в CI (статья 454, итоговый мини-проект) устраняет этот риск, гарантируя одинаковый, воспроизводимый процесс для каждого релиза независимо от того, кто конкретно его инициировал.