Подготавливаем проект Qt6 к публикации
В процессе разработки, уже на этапе тестирования появляется необходимость упаковки программы для отправки её пользователям. Программа написанная на Qt6 зависит от большого количества библиотек, как самого фреймворка, так и, например, от GCC.
Чтобы решить проблему подготовки к публикации проекта в Qt6 используется утилита winqtdeploy, но она копирует не все необходимые разделяемые библиотеки.
Сегодня мы рассмотрим подготовку проекта на Qt6 к публикации, скопировав в отдельную папку, все необходимые для запуска программы файлы и разделяемые библиотеки.
Настройка проекта
Начнем мы с шаблона проекта Qt6 размещенного в git-репозитории.
Если папка:
c:\projects\qt6_pre_packageуже существует, переместите или удалите её:
cd c:\projects
rmdir /q/s qt6_pre_packageМы будем использовать проект из git-репозитория:
cd c:\projects
rmdir /q/s qt6-project-templategit
git clone --branch V1 https://gitflic.ru/project/vasiliyaltunin/qt6-project-templategit.git --depth 1Скопируем папку с проектом:
xcopy /y/e .\qt6-project-templategit\ .\qt6_pre_package\Проверим:
cd c:\projects\qt6_pre_package
cmake -S . -B build
cmake --build build.\build\qt6tpl.exeHello world!
Debug: Clicked (qrc:/qt/qml/altuninvv/qmlmain/qml/Main.qml:24, expression for onClicked)Всё работает.
В статье ссылка мы уже рассматривали копирование всех необходимых для запуска разделяемых библиотек (DLL).
В случае с проектом Qt6 всё намного сложнее.
Для запуска программы написанной с использованием этого фреймворка необходимо несколько компонентов:
- Разделяемые библиотеки GCC;
- Разделяемые библиотеки Qt6;
- Разделяемые библиотеки с плагинами платформы, библиотек и Qt6;
- Разделяемые библиотеки с плагинами QML;
- Файлы локализации QML.
Чтобы получить готовый к публикации проект с помощью CMake мы разобьем процесс на несколько шагов.
Получение информации о главном QML-модуле приложения
Мы можем получить немного информации о собираемом главном модуле программы.
Для этого в файл cmake\qt6.cmake.in добавим
qt_query_qml_module(${PROJECT_NAME}
URI module_uri
VERSION module_version
PLUGIN_TARGET module_plugin_target
TARGET_PATH module_target_path
MODULE_RESOURCE_PATH module_resource_path
QMLDIR module_qmldir
TYPEINFO module_typeinfo
QML_FILES module_qml_files
QML_FILES_DEPLOY_PATHS qml_files_deploy_paths
QML_FILES_PREFIX_OVERRIDES qml_files_prefix_overrides
RESOURCES module_resources
RESOURCES_DEPLOY_PATHS resources_deploy_paths
RESOURCES_PREFIX_OVERRIDES resources_prefix_overrides
)
message("=== My QML module_uri is: ${module_uri}")
message("=== My QML module_version is: ${module_version}")
message("=== My QML module module_plugin_target is: ${module_plugin_target}")
message("=== My QML module_target_path is: ${module_target_path}")
message("=== My QML module_resource_path is: ${module_resource_path}")
message("=== My QML module_qmldir is: ${module_qmldir}")
message("=== My QML module_typeinfo is: ${module_typeinfo}")
message("=== My QML module_qml_files is: ${module_qml_files}")
message("=== My QML qml_files_deploy_paths is: ${qml_files_deploy_paths}")
message("=== My QML qml_files_prefix_overrides is: ${qml_files_prefix_overrides}")
message("=== My QML module_resources is: ${module_resources}")
message("=== My QML resources_deploy_paths is: ${resources_deploy_paths}")
message("=== My QML resources_prefix_overrides is: ${resources_prefix_overrides}")Запустим:
=== My QML module_uri is: qmlmain
=== My QML module_version is: 1.0
=== My QML module module_plugin_target is:
=== My QML module_target_path is: qmlmain
=== My QML module_resource_path is: /qt/qml/altuninvv/qmlmain
=== My QML module_qmldir is: C:/Projects/qt6_pre_package/build/qmlmain/qmldir
=== My QML module_typeinfo is: C:/Projects/qt6_pre_package/build/qmlmain/qtprojecttemplate.qmltypes
=== My QML module_qml_files is: C:/Projects/qt6_pre_package/qml/Main.qml
=== My QML qml_files_deploy_paths is: qml/Main.qml
=== My QML qml_files_prefix_overrides is:
=== My QML module_resources is:
=== My QML resources_deploy_paths is:
=== My QML resources_prefix_overrides is:Эта информация может помощь вам при поиске ошибок возникающих при настройке и сборке проекта Qt6
Конфигурирование поиска Qt6
Модернизируем механизм поиска библиотек Qt6.Все дело в том, что в случае, если CMake не сможет найти установленный Qt6, то дальнейшее конфигурирование проекта не имеет смысла!
Откроем файл cmake\conf.cmake.in и заменим содержимое на:
include(GNUInstallDirs)
# Добавляем Qt6 к нашему проекту
find_package(Qt6 COMPONENTS Qml REQUIRED)
find_package(Qt6 COMPONENTS Quick REQUIRED)
find_package(Qt6 COMPONENTS QuickControls2 REQUIRED)
if(Qt6_FOUND) # если Qt6 найден
# Настраиваем Qt6
qt_standard_project_setup(REQUIRES 6.8)
# Вычисляем путь к корневой папке MinGW64
get_filename_component(QT_LIB_DIR "${Qt6_DIR}" DIRECTORY)
get_filename_component(QT_ROOT_PATH "${QT_LIB_DIR}" DIRECTORY)
get_filename_component(MINGW_ROOT "${QT_ROOT_PATH}" DIRECTORY)
message("== MinGW64 root path is: ${MINGW_ROOT}")
else() # если НЕ Qt6 найден
# Если Qt6 не найден то и продолжать смысла нет, выдаем критическую ошибку
message(FATAL_ERROR "Qt6 did not found!")
endif()Теперь при конфигурировании будет выдаваться путь к корневой папки MinGW
== MinGW64 root path is: C:/msys64/mingw64Откроем файл cmake\qt6.cmake.in и добавим в начале файла:
# Путь к папке с плагинами QML
set(QT_PLUGINS_DIR "${MINGW_ROOT}/share/qt6/qml")
message("QT_PLUGINS_DIR = ${QT_PLUGINS_DIR}")Ищем зависимости фреймворка Qt6 с помощью CMake
Для работы программы написанной на Qt6 нам потребуется множество библиотек, размещенных в определенных папках, по определенному пути.
Для поиска всех файлов, которые необходимых для запуска программы и копирования их в папку установки мы можем использовать команды Cmake:
qt_generate_deploy_script
qt_deploy_runtime_dependenciesСоздадим файл cmake\qt6-deploy.cmake.in
type nul > cmake\qt6-deploy.cmake.inДобавим содержимое
# Задаем настройки развертывания приложения
# Запускается при установке, создает необходимую структуру папок
# Копирует все необходимые библиотеки и плагины в созданные папки
qt_generate_deploy_script(
TARGET ${PROJECT_NAME}
# имя скрипта, используемое для добавления к установке
OUTPUT_SCRIPT deploy_script
# Содержимое скрипта установки
CONTENT "
# Определяет все плагины и компоненты, которые используются нашим приложением
qt_deploy_qml_imports(
TARGET ${PROJECT_NAME}
# Результат работы помещается в переменную plugins_found
PLUGINS_FOUND plugins_found
# Все найденные QML-модули будут скопированы в указанную папку
QML_DIR \"share/qt6/qml\"
)
# Копирует исполняемых файл, все необходимые библиотеки и модули
# в папку установки
qt_deploy_runtime_dependencies(
# Исполняемый файл
EXECUTABLE \"${CMAKE_INSTALL_BINDIR}/${MY_EXE_NAME}.exe\"
# QML-модули
ADDITIONAL_MODULES \"${plugins_found}\"
# Создает файл конфигурации qt.conf
GENERATE_QT_CONF
# Выводит подробную информацию о процессе сборки
#VERBOSE
# Все найденные QML-модули будут скопированы в указанную папку
QML_DIR \"share/qt6/qml\"
)
"
)
message("== QT6 deploy settings complete")Для инициализации процесса установки создадим файл cmake\install.cmake.in
type nul > cmake\install.cmake.inдобавим содержимое:
# Задаем настройки развертывания приложения
include(${PROJECT_SOURCE_DIR}/cmake/qt6-deploy.cmake.in)
# Задаем базовую установку
install(TARGETS ${PROJECT_NAME}
BUNDLE DESTINATION .
)
# Добавляем скрипт развертывания к установке
install(SCRIPT ${deploy_script})
install(
DIRECTORY "${PROJECT_BINARY_DIR}/dlls/"
DESTINATION "${CMAKE_INSTALL_BINDIR}"
FILES_MATCHING REGEX "[^\\\\/.]\\.[dD][lL][lL]$"
)В конец файла CMakeLists.txt добавим:
# Задаем настройки для установки приложения
include(${PROJECT_SOURCE_DIR}/cmake/install.cmake.in)Запустим конфигурирование и сборку
cmake -S . -B build
cmake --build buildЗапустим установку, на этот раз укажем временную папку для установки:
cmake --install build --prefix=c:\projects\qt6_rel-- Install configuration: "Debug"
-- Installing: c:\projects\qt6_rel/bin/qt6tpl.exe
-- Installing: c:\projects\qt6_rel/share/qt6/qml/QtQuick/qmldir
-- Installing: c:\projects\qt6_rel/share/qt6/qml/QtQuick/qtquick2plugin.dll
-- Installing: c:\projects\qt6_rel/share/qt6/qml/QtQml/qmldir
...
-- Installing: c:\projects\qt6_rel/share/qt6/qml/Qt/labs/qmlmodels/labsmodelsplugin.dll
-- Writing c:\projects\qt6_rel/bin/qt.conf
-- Running Qt deploy tool for bin/qt6tpl.exe in working directory 'c:\projects\qt6_rel'
'C:/msys64/mingw64/bin/windeployqt-qt6.exe' 'bin/qt6tpl.exe' '--dir' '.' '--libdir' 'bin' '--plugindir' 'share/qt6/plugins' '--qml-deploy-dir' 'share/qt6/qml' '--translationdir' 'share/qt6/translations' '--force' '--qtpaths' 'C:/msys64/mingw64/bin/qtpaths6.exe'
C:\projects\qt6_rel\bin\qt6tpl.exe 64 bit, release executable [QML]
Adding in plugin type generic for module: Qt6Gui
Adding in plugin type iconengines for module: Qt6Gui
Adding Qt6Svg for qsvgicon.dll from plugin type: iconengines
Adding in plugin type imageformats for module: Qt6Gui
Adding in plugin type networkinformation for module: Qt6Network
Adding in plugin type platforms for module: Qt6Gui
Adding in plugin type qmltooling for module: Qt6Qml
Adding Qt6OpenGL Qt6QmlMeta Qt6QmlModels Qt6QmlWorkerScript Qt6Quick for qmldbg_inspector.dll from plugin type: qmltooling
Adding Qt6Quick3DUtils for qmldbg_quick3dprofiler.dll from plugin type: qmltooling
Adding in plugin type tls for module: Qt6Network
Skipping plugin qopensslbackend.dll. Use -force-openssl or specify -openssl-root if you want to use it.
Direct dependencies: Qt6Core Qt6Gui Qt6Network Qt6Qml
All dependencies : Qt6Core Qt6Gui Qt6Network Qt6Qml
To be deployed : Qt6Core Qt6Gui Qt6Network Qt6OpenGL Qt6Qml Qt6QmlMeta Qt6QmlModels Qt6QmlWorkerScript Qt6Quick Qt6Quick3DUtils Qt6Svg
Warning: Cannot find any version of the dxcompiler.dll and dxil.dll.
Updating Qt6Core.dll.
Updating Qt6Gui.dll.
...
Updating D3Dcompiler_47.dll.
Creating directory C:/projects/qt6_rel/share/qt6/plugins/generic.
Updating qtuiotouchplugin.dll.
Creating directory C:/projects/qt6_rel/share/qt6/plugins/iconengines.
Updating qsvgicon.dll.
Creating directory C:/projects/qt6_rel/share/qt6/plugins/imageformats.
Updating qgif.dll.
...
Updating qsvg.dll.
Creating directory C:/projects/qt6_rel/share/qt6/plugins/networkinformation.
Updating qglib.dll.
Updating qnetworklistmanager.dll.
Creating directory C:/projects/qt6_rel/share/qt6/plugins/platforms.
Updating qwindows.dll.
Creating directory C:/projects/qt6_rel/share/qt6/plugins/qmltooling.
Updating qmldbg_debugger.dll.
...
Updating qmldbg_tcp.dll.
Creating directory C:/projects/qt6_rel/share/qt6/plugins/tls.
Updating qcertonlybackend.dll.
Updating qschannelbackend.dll.
Creating share\qt6\translations...
Creating qt_ar.qm...
...
Creating qt_zh_TW.qm...Обратите внимание! Мы указываем полный путь до папки установки:
--prefix=c:\projects\qt6_relЕсли этого не сделать, мы получим ошибку:
CMake Error at C:/msys64/mingw64/lib/cmake/Qt6Core/Qt6CoreDeploySupport.cmake:38 (message):
Given qt.conf path is not an absolute path: '..\qt6_rel/bin/qt.conf'Будет создана папка C:\Projects\qt6_rel с такой структурой:
Структура папок
C:\PROJECTS\QT6_REL
├───bin
└───share
└───qt6
├───plugins
│ ├───generic
│ ├───iconengines
│ ├───imageformats
│ ├───networkinformation
│ ├───platforms
│ ├───qmltooling
│ └───tls
├───qml
│ ├───Qt
│ │ └───labs
│ │ └───qmlmodels
│ ├───QtQml
│ │ ├───Models
│ │ └───WorkerScript
│ └───QtQuick
│ ├───Controls
│ │ ├───Basic
│ │ │ └───impl
│ │ ├───FluentWinUI3
│ │ │ └───impl
│ │ ├───Fusion
│ │ │ └───impl
│ │ ├───Imagine
│ │ │ └───impl
│ │ ├───impl
│ │ ├───Material
│ │ │ └───impl
│ │ ├───Universal
│ │ │ └───impl
│ │ └───Windows
│ │ └───impl
│ ├───Effects
│ ├───Layouts
│ ├───NativeStyle
│ ├───Shapes
│ ├───Templates
│ └───Window
└───translationsПопробуем запустить программу на своем ПК:
C:\Projects\qt6_rel\bin\qt6tpl.exeПрограмма отработала без проблем.
Скопируем папку с программой на виртуальную машину с только что установленной Windows, запустим:
qt6_rel\bin\qt6tpl.exeПолучим несколько ошибок такого вида:
Программе требуются разделяемые библиотеки GCC
Создаем функцию для поиска и копирования разделяемых библиотек в CMake
В статье (ссылка) мы уже рассматривали копирование разделяемых библиотек для программы, сегодня мы модернизируем этот механизм создав функцию.
Создадим папку для функций
cd c:\projects\qt6_pre_package
mkdir cmake\functionsСоздадим файл
type nul > cmake\functions\get_shared_deps.cmake.inДобавим к нему содержимое:
# Функция getshareddeps
# Предназначена для вычисления зависимостей от сторонних разделяемых библиотек.
#
# Использование:
#
# getshareddeps(
# [FULL_PATH]
# [DLL_PATH]
# [DLL_DIRS]
# )
#
# [FULL_PATH] - полный путь к исполняемому файлу или разделяемой библиотеке
# [DLL_PATH] - путь к папке или папкам в которых размещены требующиеся разделяемые библиотеки
# [DLL_DIRS] - папка в папке сборки проекта в которую будут скопированы найденные разделяемые библиотеки
function(getshareddeps FULL_PATH DLL_PATH DLL_DIRS)
message("== Searching for shared DLL for ${${FULL_PATH}}")
file(GET_RUNTIME_DEPENDENCIES
EXECUTABLES ${${FULL_PATH}}
RESOLVED_DEPENDENCIES_VAR DLLS # Список с найденными библиотеками помещаем в переменную DLLS
PRE_EXCLUDE_REGEXES "^api-ms-" "^ext-ms-"
POST_EXCLUDE_REGEXES ".*system32/.*\\.dll"
DIRECTORIES ${${DLL_PATH}}
)
message("== Search completed")
message("== DLL Copying started for ${${FULL_PATH}} ")
foreach(DLL ${DLLS})
message("Dependency copied: ${DLL}")
file(COPY ${DLL} DESTINATION ${${DLL_DIRS}}/dlls)
endforeach()
message("== DLL Copying finished")
endfunction()Создадим файл:
type nul > cmake\shared_deps.cmake.inДобавим содержимое:
message("== Shared dependency setup")
# Задаем папку, в которой нужно искать разделяемые библиотеки
set(MY_DEPENDENCY_PATHS C:/msys64/mingw64/bin)
# Делаем установленные переменные доступными во время запуска из блока install(CODE
install(CODE "set(MY_DEPENDENCY_PATHS \"${MY_DEPENDENCY_PATHS}\")")
install(CODE "set(DLLS_DIR \"${CMAKE_CURRENT_BINARY_DIR}\")")
install(CODE "set(SOURCE_DIR \"${PROJECT_SOURCE_DIR}\")")
install(CODE "set(TARGET_EXE \"$<TARGET_FILE:${PROJECT_NAME}>\")")
# Создаем отдельную папку для разделяемых библиотек
make_directory(${DLLS_DIR}/dlls)
# Запускаем на этапе установки программы поиск всех зависимостей
install(CODE [[
# Для блока CODE все include нужно указывать внутри
include(${SOURCE_DIR}/cmake/functions/get_shared_deps.cmake.in)
# Вычисляем и копируем зависимости для программы
getshareddeps(TARGET_EXE MY_DEPENDENCY_PATHS DLLS_DIR)
# Возможно прочие модули Qt6 Quick зависят от других библиотек, в случае проблем просто
# просто добавьте строки с файлами плагинов нужного модуля
]])В файл CMakeLists.txt перед строкой
# Задаем настройки для установки приложениядобавим:
# Настраиваем установку разделяемых (shared) библиотек
include(${PROJECT_SOURCE_DIR}/cmake/shared_deps.cmake.in)Запустим конфигурирование и сборку
cmake -S . -B build
cmake --build buildЗапустим установку:
cmake --install build --prefix=c:\projects\qt6_relПоиск зависимостей для исполняемого файлов может занять несколько секунд. В результате мы получим те же сообщения, что и при предыдущей установке, но в начале добавиться блок:
== Searching for shared DLL for C:/Projects/qt6_pre_package/buьюфєыild/qt6tpl.exe
== Search completed
== DLL Copying started for C:/Projects/qt6_pre_package/build/qt6tpl.exe
Dependency copied: C:/msys64/mingw64/bin/Qt6Core.dll
Dependency copied: C:/msys64/mingw64/bin/Qt6Gui.dll
Dependency copied: C:/msys64/mingw64/bin/Qt6Network.dll
...
Dependency copied: C:/msys64/mingw64/bin/zlib1.dll
== DLL Copying finished
В самом конце добавится блок:
-- Up-to-date: c:\projects\qt6_rel/bin
-- Installing: c:\projects\qt6_rel/bin/libb2-1.dll
-- Installing: c:\projects\qt6_rel/bin/libbrotlicommon.dll
-- Installing: c:\projects\qt6_rel/bin/libbrotlidec.dll
-- Installing: c:\projects\qt6_rel/bin/libbz2-1.dll
-- Installing: c:\projects\qt6_rel/bin/libdouble-conversion.dll
...
-- Up-to-date: c:\projects\qt6_rel/bin/Qt6Qml.dll
-- Installing: c:\projects\qt6_rel/bin/zlib1.dllСкопируем папку c:\projects\qt6_rel в виртуальную машину и попробуем снова запустить:
Warning: QQmlApplicationEngine failed to load component ((null):0, (null))
Warning: qrc:/qt/qml/altuninvv/qmlmain/qml/Main.qml:2:1: Cannot load library C:\test\qt6_rel\share\qt6\qml\QtQuick\Controls\qtquickcontrols2plugin.dll: ═х эрщфхэ єърчрээ√щ ьюфєы№. (qrc:/qt/qml/altuninvv/qmlmain/qml/Main.qml:2, (null))
Hello world!Мы получили ошибку.
Запустим режим отладки плагинов Qt6. В консоли перейдем в папку с исполняемым файлом.
Запустим:
set QT_DEBUG_PLUGINS=1Запустим программу:
.\qt6tpl.exeРезультат:
Debug: "C:/test/qt6_rel/share/qt6/qml/QtQuick/Controls/qtquickcontrols2plugin.dll" cannot load: Cannot load library C:\test\qt6_rel\share\qt6\qml\QtQuick\Controls\qtquickcontrols2plьюфєы№. ((null):0, (null))
Debug: QLibraryPrivate::loadPlugin failed on "C:/test/qt6_rel/share/qt6/qml/QtQuick/Controls/qtquickcontrols2plugin.dll" : "Cannot load library C:\\test\\qt6_rel\\share\\qt6\\qml\\Qols2plugin.dll: ═х эрщфхэ єърчрээ√щ ьюфєы№." ((null):0, (null))
Warning: QQmlApplicationEngine failed to load component ((null):0, (null))
Warning: qrc:/qt/qml/altuninvv/qmlmain/qml/Main.qml:2:1: Cannot load library C:\test\qt6_rel\share\qt6\qml\QtQuick\Controls\qtquickcontrols2plugin.dll: ═х эрщфхэ єърчрээ√щ ьюфєы№. (qml/Main.qml:2, (null))
Hello world!Debug: checking directory path "C:/test/qt6_rel/share/qt6/plugins/accessiblebridge" ... ((null):0, (null)) Debug: checking directory path "C:/test/qt6_rel/bin/accessiblebridge" ... ((null):0, (null))
Debug: "C:/test/qt6_rel/share/qt6/plugins/platforms/qwindows.dll" unloaded library ((null):0, (null)) Debug: "C:/test/qt6_rel/share/qt6/qml/QtQuick/qtquick2plugin.dll" unloaded library ((null):0, (null)) Сообщение:
═х эрщфхэ єърчрээ√щ ьюфєы№.При перекодировке означает:
Не найден указанный модульПо какой-то причине не удается загрузить библиотеку:
C:\test\qt6_rel\share\qt6\qml\QtQuick\Controls\qtquickcontrols2plugin.dllПерейдем на наш ПК и запустим:
ldd C:\Projects\qt6_rel\share\qt6\qml\QtQuick\Controls\qtquickcontrols2plugin.dll | grep Qt6Результат:
Qt6QuickControls2.dll => /mingw64/bin/Qt6QuickControls2.dll (0x7ffacbce0000)
Qt6Core.dll => /mingw64/bin/Qt6Core.dll (0x7ffa54c50000)
Qt6Qml.dll => /mingw64/bin/Qt6Qml.dll (0x7ffa552e0000)
Qt6Gui.dll => /mingw64/bin/Qt6Gui.dll (0x7ffa54290000)
Qt6Quick.dll => /mingw64/bin/Qt6Quick.dll (0x7ffa53b80000)
Qt6QuickTemplates2.dll => /mingw64/bin/Qt6QuickTemplates2.dll (0x7ffa94340000)
Qt6Network.dll => /mingw64/bin/Qt6Network.dll (0x7ffa6ebd0000)
Qt6OpenGL.dll => /mingw64/bin/Qt6OpenGL.dll (0x7ffaa81d0000)
Qt6QmlMeta.dll => /mingw64/bin/Qt6QmlMeta.dll (0x7ffab21e0000)
Qt6QmlModels.dll => /mingw64/bin/Qt6QmlModels.dll (0x7ffa53220000)
Qt6QmlWorkerScript.dll => /mingw64/bin/Qt6QmlWorkerScript.dll (0x7ffaa6690000)Файл Qt6QuickControls2.dll отсутствует в папке на виртуальном машине.
Команда qt_deploy_runtime_dependencies не вычисляет зависимости QML плагинов, которые используются в нашей программе. Поэтому нам придется делать это самим с помощью Cmake.
Вычисление зависимостей QML-плагинов с помощью CMake
Откроем файл cmake\shared_deps.cmake.in и заменим содержимое на:
message("== Shared dependency setup")
# Задаем папку, в которой нужно искать разделяемые библиотеки
set(MY_DEPENDENCY_PATHS "${MINGW_ROOT}/bin")
# Делаем установленные переменные доступными во время запуска из блока install(CODE
install(CODE "set(MY_DEPENDENCY_PATHS \"${MY_DEPENDENCY_PATHS}\")")
install(CODE "set(DLLS_DIR \"${CMAKE_CURRENT_BINARY_DIR}\")")
install(CODE "set(SOURCE_DIR \"${PROJECT_SOURCE_DIR}\")")
install(CODE "set(TARGET_EXE \"$<TARGET_FILE:${PROJECT_NAME}>\")")
# Задаем пути до dll-файлов библиотек с плагинами
install(CODE "set(QT_QUICK_CONTROLS_PLUGIN \"${QT_PLUGINS_DIR}/QtQuick/Controls/qtquickcontrols2plugin.dll\")")
# Создаем отдельную папку для разделяемых библиотек
make_directory(${DLLS_DIR}/dlls)
# Запускаем на этапе установки программы поиск всех зависимостей
install(CODE [[
# Для блока CODE все include нужно указывать внутри
include(${SOURCE_DIR}/cmake/functions/get_shared_deps.cmake.in)
# Вычисляем и копируем зависимости для программы
getshareddeps(TARGET_EXE MY_DEPENDENCY_PATHS DLLS_DIR)
# Вычисляем и копируем зависимости для плагина qtquickcontrols2plugin.dll
getshareddeps(QT_QUICK_CONTROLS_PLUGIN MY_DEPENDENCY_PATHS DLLS_DIR)
# Возможно прочие модули Qt6 Quick зависят от других библиотек, в случае проблем просто
# просто добавьте строки с файлами плагинов нужного модуля
]])Запустим конфигурирование и сборку
cmake -S . -B build
cmake --build buildЗапустим установку, на этот раз укажем временную папку для установки:
cmake --install build --prefix=c:\projects\qt6_relСкопируем на виртуальную машину и запустим:
Cannot load library C:\test\qt6_rel\share\qt6\qml\QtQuick\Controls\Basic\qtquickcontrols2basicstyleplugin.dll: ═х эрщфхэ єърчрээ√щ ьюфєы№. (qrc:/qt/qml/altuninvv/qmlmain/qml/Main.qml:2, (null))На этот раз ошибка возникла в другой библиотеке.
Я произвел всё вышеописанное итеративно и в результате получил библиотеки, у которых не хватает зависимостей:
qtquickcontrols2basicstyleplugin.dll
qtquickcontrols2fusionstyleplugin.dll
qtquickcontrols2implplugin.dll
qtquickcontrols2basicstyleimplplugin.dllОткроем файл cmake\shared_deps.cmake.in и заменим содержимое на:
message("== Shared dependency setup")
# Задаем папку, в которой нужно искать разделяемые библиотеки
set(MY_DEPENDENCY_PATHS C:/msys64/mingw64/bin)
# Делаем установленные переменные доступными во время запуска из блока install(CODE
install(CODE "set(MY_DEPENDENCY_PATHS \"${MY_DEPENDENCY_PATHS}\")")
install(CODE "set(DLLS_DIR \"${CMAKE_CURRENT_BINARY_DIR}\")")
install(CODE "set(SOURCE_DIR \"${PROJECT_SOURCE_DIR}\")")
install(CODE "set(TARGET_EXE \"$<TARGET_FILE:${PROJECT_NAME}>\")")
# Задаем пути до dll-файлов библиотек с плагинами
install(CODE "set(QT_QUICK_CONTROLS_PLUGIN \"${QT_PLUGINS_DIR}/QtQuick/Controls/qtquickcontrols2plugin.dll\")")
install(CODE "set(QT_QUICK_CONTROLS_BASIC_PLUGIN \"${QT_PLUGINS_DIR}/QtQuick/Controls/Basic/qtquickcontrols2basicstyleplugin.dll\")")
install(CODE "set(QT_QUICK_CONTROLS_FUSION_PLUGIN \"${QT_PLUGINS_DIR}/QtQuick/Controls/Fusion/qtquickcontrols2fusionstyleplugin.dll\")")
install(CODE "set(QT_QUICK_CONTROLS_IMPL_PLUGIN \"${QT_PLUGINS_DIR}/QtQuick/Controls/impl/qtquickcontrols2implplugin.dll\")")
install(CODE "set(QT_QUICK_CONTROLS_BASIC_IMPL_PLUGIN \"${QT_PLUGINS_DIR}/QtQuick/Controls/Basic/impl/qtquickcontrols2basicstyleimplplugin.dll\")")
#install(CODE "set(QT_QUICK_PLUGIN \"${QT_PLUGINS_DIR}/QtQuick/qtquick2plugin.dll\")")
# Создаем отдельную папку для разделяемых библиотек
make_directory(${DLLS_DIR}/dlls)
# Запускаем на этапе установки программы поиск всех зависимостей
install(CODE [[
# Для блока CODE все include нужно указывать внутри
include(${SOURCE_DIR}/cmake/functions/get_shared_deps.cmake.in)
# Вычисляем и копируем зависимости для программы
getshareddeps(TARGET_EXE MY_DEPENDENCY_PATHS DLLS_DIR)
# Вычисляем и копируем зависимости для плагина qtquickcontrols2plugin.dll
getshareddeps(QT_QUICK_CONTROLS_PLUGIN MY_DEPENDENCY_PATHS DLLS_DIR)
# Вычисляем и копируем зависимости для плагина qtquickcontrols2basicstyleplugin.dll
getshareddeps(QT_QUICK_CONTROLS_BASIC_PLUGIN MY_DEPENDENCY_PATHS DLLS_DIR)
# Вычисляем и копируем зависимости для плагина qtquickcontrols2fusionstyleplugin.dll
getshareddeps(QT_QUICK_CONTROLS_FUSION_PLUGIN MY_DEPENDENCY_PATHS DLLS_DIR)
# Вычисляем и копируем зависимости для плагина qtquickcontrols2implplugin.dl
getshareddeps(QT_QUICK_CONTROLS_IMPL_PLUGIN MY_DEPENDENCY_PATHS DLLS_DIR)
# Вычисляем и копируем зависимости для плагина qtquickcontrols2basicstyleimplplugin.dl
getshareddeps(QT_QUICK_CONTROLS_BASIC_IMPL_PLUGIN MY_DEPENDENCY_PATHS DLLS_DIR)
# Возможно прочие модули Qt6 Quick зависят от других библиотек, в случае проблем просто
# просто добавьте строки с файлами плагинов нужного модуля
]])На этот раз после сборки и установки программа запустится!
Обратите внимание! Если вы начинаете использовать новый модуль Qt6 вам придется как описано выше добавить все плагины для проверки зависимостей!
Заключение
Сегодня мы рассмотрели подготовку проекта на Qt6 к публикации:
Настроили вывод информации о главном QML-модуле;
Доработали код поиска фреймворка Qt6;
Настроили qt_generate_deploy_script для поиска зависимостей Qt6;
Создали функцию CMake для поиска разделяемых библиотек, от которых зависит программа или разделяемый модуль;
С помощью созданной функции настроили определение зависимостей у QML-плагинов.
Добавить комментарий