Введение
Сборка приложения — только часть пути; для передачи его конечным пользователям нужно собрать дистрибутив: исполняемый файл, нужные библиотеки Qt и плагины (платформенные, форматов изображений, стилей), ресурсы. CMake предоставляет команды install() для описания того, что и куда копировать при установке, а Qt дополняет это инструментами для автоматического разрешения зависимостей (windeployqt на Windows, macdeployqt на macOS, linuxdeployqt или ручная сборка AppImage на Linux). В статье разберём базовую настройку install() и интеграцию с инструментами деплоя.
Концепция
install(TARGETS ... RUNTIME DESTINATION ...) указывает, куда устанавливать собранный исполняемый файл, а install(FILES ...)/install(DIRECTORY ...) — куда копировать дополнительные ресурсы (иконки, конфиги, переводы). Эти команды формируют основу для cmake --install и для генерации пакетов через CPack.
Для Qt-приложений ключевая сложность — собрать рядом с исполняемым файлом все нужные Qt-библиотеки (Core, Gui, Widgets и так далее) и платформенные плагины (без qwindows.dll/libqxcb.so приложение вообще не запустится, так как Qt не найдёт платформенный плагин). Решение — запускать windeployqt/macdeployqt как часть процесса сборки или установки, либо вручную прописывать копирование нужных библиотек через install().
Пример кода: CMake install() и
cmake_minimum_required(VERSION 3.21)
project(MyApp LANGUAGES CXX)
find_package(Qt6 REQUIRED COMPONENTS Core Widgets)
add_executable(MyApp main.cpp)
target_link_libraries(MyApp PRIVATE Qt6::Core Qt6::Widgets)
install(TARGETS MyApp
RUNTIME DESTINATION bin
)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/resources/
DESTINATION share/myapp/resources
)
# Автоматический запуск windeployqt после сборки на Windows
if (WIN32)
find_program(WINDEPLOYQT_EXECUTABLE windeployqt
HINTS "${Qt6_DIR}/../../../bin"
)
if (WINDEPLOYQT_EXECUTABLE)
add_custom_command(TARGET MyApp POST_BUILD
COMMAND ${WINDEPLOYQT_EXECUTABLE}
--no-translations
"$<TARGET_FILE:MyApp>"
COMMENT "Развёртывание зависимостей Qt через windeployqt"
)
endif()
endif()
# Базовая настройка CPack для генерации установочного пакета
include(CPack)
set(CPACK_PACKAGE_NAME "MyApp")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_GENERATOR "ZIP") # или NSIS, DEB, RPM, DragNDrop и т.д.
Пояснения к коду
Основные install() команды описывают, что входит в дистрибутив: сам исполняемый файл (RUNTIME DESTINATION bin) и директория с ресурсами приложения. Блок if (WIN32) показывает типичный паттерн автоматизации деплоя: после успешной сборки (POST_BUILD) автоматически запускается windeployqt, который анализирует бинарник, находит все нужные Qt-библиотеки и плагины и копирует их рядом с исполняемым файлом — без этого шага собранный .exe не запустится на машине без установленного Qt SDK.
Подключение CPack и указание генератора (ZIP, NSIS для Windows-инсталляторов, DEB/RPM для Linux-пакетов) позволяет получить готовый к распространению пакет одной командой cpack после сборки.
Подводные камни
- Забытые плагины Qt (стили, форматы изображений, платформенные плагины).
windeployqtобычно справляется с этим автоматически, но при использовании менее распространённых модулей Qt (например, QtSvg для иконок в формате SVG) нужно убедиться, что соответствующие плагины попали в дистрибутив — их отсутствие может проявляться не как явная ошибка, а как «пустые» иконки или отсутствующий визуальный стиль. - На Linux нет единого инструмента, аналогичного
windeployqt/macdeployqt—linuxdeployqtсуществует, но менее интегрирован с CMake «из коробки», и для серьёзного распространения часто используют AppImage, Flatpak или системные пакеты с явным указанием зависимости от пакета Qt в дистрибутиве. - Версионная несовместимость системных библиотек Qt с собранным приложением. Если приложение собрано под одну минорную версию Qt, а на целевой машине системный Qt другой версии, могут возникать ABI-несовместимости — поэтому для десктопных приложений предпочтительнее разворачивать Qt-библиотеки вместе с приложением (как делает
windeployqt), а не рассчитывать на системный Qt. - Несоответствие путей
RPATH/RUNPATHна Linux. Если бинарник ищет shared-библиотеки Qt по абсолютному пути сборочной машины, на целевой машине (где этих путей не существует) запуск завершится с ошибкойcannot open shared object file— нужно настраиватьINSTALL_RPATHи относительные пути ($ORIGIN) для переносимости.