Развернуть все зависимости Qt при сборке

Я создал CMakeLists.txt для создания простого приложения Qt (на самом деле оно имеет только один файл main.cpp показывая пустое главное окно):

cmake_minimum_required (VERSION 3.7.0)

project(guitest)

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)

find_package(Qt5Widgets REQUIRED)
include_directories (${CMAKE_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR})
file (GLOB_RECURSE WSIMGUI_SRC *.cpp)

add_executable(${PROJECT_NAME} ${WSIMGUI_SRC})
target_link_libraries(${PROJECT_NAME} Qt5::Widgets)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Widgets> $<TARGET_FILE_DIR:${PROJECT_NAME}>)

Проект строит и add_custom_command копирует Qt5Widgets.dll файл в выходной каталог. Но когда я пытаюсь запустить программу, я получаю следующую ошибку:

Не удалось запустить это приложение, так как не удалось найти или загрузить плагин платформы Qt "windows" в "".

Я искал эту проблему, и я заметил, что я должен также скопировать platform папка из моей установки Qt.

Как я могу сделать это внутри моего CMakeLists.txt файл?

1 ответ

Решение

Qt предоставляет утилиту для развертывания зависимостей в Windows: windeployqt,

Учитывая, что ваша установка Qt находится в <qt_install_prefix>, вы должны использовать следующие команды:

set PATH=%PATH%;<qt_install_prefix>/bin
windeployqt --dir /path/to/deployment/dir /path/to/qt/application.exe

Гибкий способ использования windeployqt с CMake сначала объявить импортированную цель:

find_package(Qt5 ...)

if(Qt5_FOUND AND WIN32 AND TARGET Qt5::qmake AND NOT TARGET Qt5::windeployqt)
    get_target_property(_qt5_qmake_location Qt5::qmake IMPORTED_LOCATION)

    execute_process(
        COMMAND "${_qt5_qmake_location}" -query QT_INSTALL_PREFIX
        RESULT_VARIABLE return_code
        OUTPUT_VARIABLE qt5_install_prefix
        OUTPUT_STRIP_TRAILING_WHITESPACE
    )

    set(imported_location "${qt5_install_prefix}/bin/windeployqt.exe")

    if(EXISTS ${imported_location})
        add_executable(Qt5::windeployqt IMPORTED)

        set_target_properties(Qt5::windeployqt PROPERTIES
            IMPORTED_LOCATION ${imported_location}
        )
    endif()
endif()

Затем вы можете использовать его следующим образом:

add_executable(foo ...)

if(TARGET Qt5::windeployqt)
    # execute windeployqt in a tmp directory after build
    add_custom_command(TARGET foo
        POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/windeployqt"
        COMMAND set PATH=%PATH%$<SEMICOLON>${qt5_install_prefix}/bin
        COMMAND Qt5::windeployqt --dir "${CMAKE_CURRENT_BINARY_DIR}/windeployqt" "$<TARGET_FILE_DIR:foo>/$<TARGET_FILE_NAME:foo>"
    )

    # copy deployment directory during installation
    install(
        DIRECTORY
        "${CMAKE_CURRENT_BINARY_DIR}/windeployqt/"
        DESTINATION ${FOO_INSTALL_RUNTIME_DESTINATION}
    )
endif()

Это может (должно?) Быть встроено в функцию cmake.


Обратите внимание, что с помощью GLOB собирать исходные файлы не рекомендуется в документации CMake:

Мы не рекомендуем использовать GLOB для сбора списка исходных файлов из вашего исходного дерева. Если файл CMakeLists.txt не изменяется при добавлении или удалении источника, то сгенерированная система сборки не может знать, когда попросить CMake сгенерировать заново.


Если вы используете Visual C++, вы также можете установить Visual распространяемый, добавив следующий код в конце вашего CMakeLists.txt файл:

set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)

include(InstallRequiredSystemLibraries)

install(
    PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS}
    DESTINATION ${FOO_INSTALL_RUNTIME_DESTINATION}
)

Вы можете взглянуть на один из моих проектов под названием Softbloks, для полной и работающей интеграции windeployqt а также InstallRequiredSystemLibraries,

Другие вопросы по тегам