Qt5 CMake 将所有库包含到可执行文件中

Mir*_*cea 4 c++ qt build cmake static-linking

我正在尝试使用 Qt 5.14 构建一个发布模式下的应用程序,并且 Qt Creator 内部一切正常,但是当我尝试单独运行可执行文件时,我收到如下错误:


操作系统: Windows 10

Qt: 5.14

编译: 3.5


在此输入图像描述


我尝试过的:

  1. 设置(CMAKE_EXE_LINKER_FLAGS“-static-libgcc -static-libstdc++ -static”)
  2. 设置(CMAKE_CXX_FLAGS“${CMAKE_CXX_FLAGS} -std=c++0x -fPIC”)
  3. ${ADDITIONAL_LIBRARIES} - target_link_libraries 内部的静态

上述方法都不适合我,每当我尝试在不使用 Qt Creator 的情况下自行运行可执行文件时,我都会遇到相同的错误。


我的 CMake 文件:

cmake_minimum_required(VERSION 3.5)

project(Scrollable LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")
set(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} -std=c++0x -fPIC")
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt5 REQUIRED Core Widgets Gui Qml Quick Qml)

qt5_add_resources(resource.qrc)

include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories("MoviesInterface")

set(SOURCES
        main.cpp
        MovieInterface/movieinterfaceomdb.cpp
        MovieInterface/moviesinterface.cpp
        )

set(HEADERS
        MovieInterface/movieinterfaceomdb.h
        MovieInterface/moviesinterface.h
        )


add_executable(Scrollable ${SOURCES} ${HEADERS} qml.qrc)
qt5_use_modules(Scrollable Core Network)
target_link_libraries(Scrollable
        Qt5::Core
        Qt5::Gui
        Qt5::Widgets
        Qt5::Qml
        ${ADDITIONAL_LIBRARIES} -static
        )
Run Code Online (Sandbox Code Playgroud)

Jen*_*och 12

A您想要静态编译。这不适用于 Qt 库和 Mingw 库本身,因为它们也需要静态编译。但它们仅作为动态链接库分发。

如果您确实想要拥有可静态链接的 Qt 库,则需要先静态编译 Qt,然后才能链接它们。有一些关于静态编译 Qt 的描述。但这是一项繁重的工作。

B为什么找不到Qt5Core.dll:

在 Qt Creator 中,由于编译器/工具链自动检测,应用程序的 Qt 库的路径会自动设置。

但是,当您独立运行应用程序可执行文件时,不会设置 Qt 库的路径,并且它们不会驻留在可执行文件旁边的应用程序文件夹中。


为了解决这个问题,我建议使用windeployqt. Windeployqt 分析您构建的库或可执行文件,并将所需的 Qt 依赖项复制到构建文件夹中。

我倾向于为此使用 cmake 辅助函数。

  1. windeployqt.cmake使用以下内容创建并将其放入/cmake项目的模块文件夹中:
find_package(Qt5Core REQUIRED)

# get absolute path to qmake, then use it to find windeployqt executable

get_target_property(_qmake_executable Qt5::qmake IMPORTED_LOCATION)
get_filename_component(_qt_bin_dir "${_qmake_executable}" DIRECTORY)

function(windeployqt target)

    # POST_BUILD step
    # - after build, we have a bin/lib for analyzing qt dependencies
    # - we run windeployqt on target and deploy Qt libs

    add_custom_command(TARGET ${target} POST_BUILD
        COMMAND "${_qt_bin_dir}/windeployqt.exe"         
                --verbose 1
                --release
                --no-svg
                --no-angle
                --no-opengl
                --no-opengl-sw
                --no-compiler-runtime
                --no-system-d3d-compiler
                \"$<TARGET_FILE:${target}>\"
        COMMENT "Deploying Qt libraries using windeployqt for compilation target '${target}' ..."
    )

endfunction()
Run Code Online (Sandbox Code Playgroud)

注1:--verbose 1已设置,以便您了解发生了什么情况。您稍后可以禁用它。

注2:排除项请自行处理。我不知道您的应用程序的具体要求,例如您是否需要 OpenGL 或 SVG 支持。

  1. 然后添加到您的CMakeLists.txt:
# Set path to our custom CMAKE scripts
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")

# Include Qt deployment helper function
include(windeployqt)
Run Code Online (Sandbox Code Playgroud)

最后,在 的末尾添加CMakeLists.txt:

windeployqt(Scrollable)
Run Code Online (Sandbox Code Playgroud)

现在,windeployqt 作为可执行文件上的 POST_BUILD 步骤运行,将 qt 库复制到构建文件夹。可执行文件现在将从该文件夹中获取 Qt 依赖项,并且应该能够独立运行(无需设置 Qt 库的路径)。

请记住还要复制其他依赖项,例如第三方库或运行时依赖项。


mingw 依赖项的后续操作:

set(QT_MINGW "/path/to/your/qt/mingw/compiler")

add_custom_command(TARGET Scrollable POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different ${QT_MINGW}/bin/libgcc_s_dw2-1.dll $<TARGET_FILE_DIR:${TARGET}>
    COMMAND ${CMAKE_COMMAND} -E copy_if_different ${QT_MINGW}/bin/libstdc++-6.dll $<TARGET_FILE_DIR:${TARGET}>
    COMMAND ${CMAKE_COMMAND} -E copy_if_different ${QT_MINGW}/bin/libwinpthread-1.dll $<TARGET_FILE_DIR:${TARGET}>
    COMMENT "Deploy mingw runtime libraries from ${QT_MINGW}/bin"
)
Run Code Online (Sandbox Code Playgroud)