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

Posted

技术标签:

【中文标题】Qt5 CMake 将所有库包含到可执行文件中【英文标题】:Qt5 CMake include all libraries into executable 【发布时间】:2020-03-25 17:48:42 【问题描述】:

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


操作系统: Windows 10

Qt: 5.14

Cmake: 3.5



我的尝试:

    set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static") set(CMAKE_CXX_FLAGS "$CMAKE_CXX_FLAGS -std=c++0x -fPIC") $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
        )

【问题讨论】:

其他人已经在本站问过类似的问题,例如this。你试过这些建议吗?通过更新您的Path 或将丢失的 DLL 复制到您的可执行位置,您的问题可能会得到解决。 当然...除了我在 CMake 中的静态链接库和缺少的 DLL 之间没有任何联系,因为我不能只是将该 DLL 复制粘贴到我的构建文件夹中。这表明我没有正确链接库。 您是否重新安装了 Qt5core? ;) 我做了一些测试,在 qt 创建者的 qmake 构建的构建文件夹中成功执行“make all”。然后我更改了所有源文件的路径并将 em 放在 buid 文件夹中 - 工作得非常好,因为所有链接都已由 qmake 完成,并且源代码中的更改通过发出 make all 生效。你可以在 build 文件夹中执行 make all - 它编译吗? 【参考方案1】:

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

如果您真的想拥有静态可链接的 Qt 库,则需要先静态编译 Qt,然后才能链接它们。有一些关于静态编译 Qt 的描述。但工作量很大。

B为什么找不到Qt5Core.dll:

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

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


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

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

    使用以下内容创建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()

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

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

    然后添加到您的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)

最后在CMakeLists.txt末尾添加:

windeployqt(Scrollable)

现在,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"
)

【讨论】:

我确实试过了,它几乎可以工作了,只是现在当我构建项目时它失败了,我收到了这个错误消息。 Unable to find the platform plugin. mingw32-make.exe[2]: *** [CMakeFiles\Scrollable.dir\build.make:172: Scrollable.exe] Error 1 mingw32-make.exe[2]: *** Deleting file 'Scrollable.exe' mingw32-make.exe[1]: *** [CMakeFiles\Makefile2:76: CMakeFiles/Scrollable.dir/all] Error 2 mingw32-make.exe: *** [Makefile:83: all] Error 2 22:26:33: The process "C:\Qt\Tools\CMake_64\bin\cmake.exe" exited with code 2. Error while building/deploying project Scrollable (kit: Desktop Qt 5.14.1 MinGW 64-bit) When executing step "CMake Build" 好的,好像平台插件没有被复制。它应该在platforms\qwindows.dll。我也不确定,如果您的应用程序在 exe 文件夹中需要额外的编译器特定(mingw)运行时库。 -- 您可以使用dependencywalker.com 找出您的exe 依赖于什么。然后将这些库复制到文件夹中。 我在 CMakeList.txt 中添加了 target_link_librarieswindeployqt(Scrollable) 之间的更新,但无法正常工作,我收到此错误消息:CMake Error at CMakeLists.txt:53 (add_custom_command): Error evaluating generator expression: $&lt;TARGET_FILE_DIR:&gt; Expression syntax not recognized 对不起,我的错:$&lt;TARGET_FILE_DIR:$TARGET 的所有出现都应该是 $&lt;TARGET_FILE_DIR:Scrollable&gt;【参考方案2】:

跟进您的 mingw 依赖项: ...

如果 Qt 也与 MinGW 一起安装,则只需使用 windeployqt.exe--compiler-runtime 命令行选项,即可避免对 add_custom_command 内的运行时库进行额外的复制操作。

【讨论】:

以上是关于Qt5 CMake 将所有库包含到可执行文件中的主要内容,如果未能解决你的问题,请参考以下文章

将所有库依赖项包含到可执行文件中 Linux

20190110-CMake-Makefile

20190110-CMake-Makefile

使用 CMake 将 Qt DLL 复制到 Windows 上的可执行目录

使用 CMake 将资源(例如,着色器代码;图像)嵌入到可执行文件/库中

将相关源文件放入库时,带有 CMake 的 Qt5 不编译 .ui 文件