Qt 程序的 Windows 打包与部署

35 阅读5分钟

Qt 程序在开发电脑上运行正常,复制到另一台电脑后却打不开,是上位机交付时很常见的问题。

原因通常不是业务代码变化,而是目标电脑缺少 Qt 动态库、平台插件、编译器运行库,或者设备厂商提供的依赖文件。

对于使用 Qt 动态库构建的 Widgets 程序,可以先通过 windeployqt 收集 Qt 依赖,再补齐项目自己的文件。

一、先生成正确的 Release 程序

交付前先确认:

  • 使用 Release 构建。
  • 程序与 Qt 库的架构一致,例如都为 x64。
  • 使用的 Qt 套件与编译器一致,例如 MSVC 或 MinGW。
  • 厂商 SDK 与程序的架构、工具链要求匹配。

对于 Visual Studio 等多配置 CMake 构建目录,可以执行:

cmake --build .\build --config Release

如果使用 Ninja 这类单配置生成器,需要在配置阶段指定:

cmake -S . -B .\build-release -DCMAKE_BUILD_TYPE=Release
cmake --build .\build-release

第二组命令应在已经配置好对应编译器和 Qt 路径的环境中运行。使用 Qt Creator 时,也可以直接选择对应 Kit 的 Release 配置进行构建。

找到最终生成的 EXE 后,先确认它确实来自 Release 目录,而不是之前留下的旧文件。

二、使用 windeployqt 收集依赖

假设程序名称为 DeviceMonitor.exe,先创建一个独立发布目录:

New-Item -ItemType Directory -Path .\dist
Copy-Item .\build\Release\DeviceMonitor.exe .\dist\

示例路径需要根据实际构建目录调整,dist 建议从空目录开始,避免混入旧版本 DLL。

然后运行与构建套件对应的 windeployqt:

& "C:\Qt\6.8.3\msvc2022_64\bin\windeployqt.exe" `
    --release `
    --compiler-runtime `
    --dir .\dist `
    .\dist\DeviceMonitor.exe

这里的 Qt 安装路径只是示例,应替换为实际构建程序使用的版本。

不要随意使用另一套 Qt 目录中的工具。即使版本号相同,MSVC 和 MinGW 的库也不能混用。

执行后,目录中通常会出现:

dist/
├── DeviceMonitor.exe
├── Qt6Core.dll
├── Qt6Gui.dll
├── Qt6Widgets.dll
├── platforms/
│   └── qwindows.dll
└── ...

如果程序使用 Qt Quick/QML,还需要通过 --qmldir 指定 QML 源码目录,帮助工具分析相关模块依赖。普通 Widgets 项目通常不需要这一步。

三、补齐设备 SDK 和程序资源

windeployqt 主要处理 Qt 依赖,不能替代对整个项目运行条件的检查。

上位机项目还可能需要:

  • 设备厂商 SDK 的 DLL。
  • SDK 依赖的其他动态库。
  • 图标、翻译文件和默认配置。
  • 设备驱动或厂商服务。
  • 编译器运行库。

例如,程序使用 SQLite 时,部署目录中需要对应的驱动插件:

sqldrivers/
└── qsqlite.dll

这些插件目录结构有实际意义,不能为了“整理文件”把所有 DLL 都移动到 EXE 旁边。

厂商 SDK 的文件也应按照厂商说明部署。SDK DLL 本身齐全,不代表它依赖的运行库、驱动或后台服务已经安装。

对于 MSVC 构建的程序,目标电脑还需要匹配架构且版本兼容的 Visual C++ 运行库。即使使用了 --compiler-runtime,也应检查工具的输出,并按部署结果安装或携带官方运行库组件。

如果图标、样式和模板通过 Qt 资源系统编译进程序,就不需要再单独复制;通过文件路径读取的内容则需要一起部署。

四、排查常见启动问题

1. 提示找不到某个 Qt DLL

例如:

找不到 Qt6Widgets.dll

先检查文件是否存在、版本是否一致,以及程序是否从正确的发布目录启动。

不要从网上随意下载一个同名 DLL 放进去。文件名相同,并不代表版本和编译器兼容。

2. 提示无法加载 Windows 平台插件

这类问题常与 platforms/qwindows.dll 有关,但即使文件存在,也可能因为它依赖的库缺失而加载失败。

可以在 PowerShell 中临时打开插件诊断:

$env:QT_DEBUG_PLUGINS = "1"
.\dist\DeviceMonitor.exe

诊断信息可通过控制台、调试器输出等方式查看,取决于程序的构建方式和日志配置。

完成后删除当前终端中的临时变量:

Remove-Item Env:QT_DEBUG_PLUGINS

重点查看插件搜索路径、实际加载的文件,以及缺失依赖信息。开发电脑上残留的 QT_PLUGIN_PATH 等环境变量,也可能让程序误用另一套 Qt 插件。

3. 提示应用程序无法正常启动

例如 0xc000007b,常见原因之一是混用了 32 位和 64 位依赖,但它不是唯一原因。

可以使用 Visual Studio 的 dumpbin 或 Dependencies 等工具检查 EXE 和 DLL 的架构、依赖关系。厂商 SDK 往往是这类问题的重点检查对象。

4. 界面能打开,设备或数据库却不能用

这说明基础界面依赖已经满足,但业务依赖可能仍有缺失。

可以继续检查:

  • 数据库驱动插件是否部署。
  • 串口或 USB 设备驱动是否安装。
  • SDK 配置文件和许可证文件是否齐全。
  • 程序是否仍然读取开发电脑上的绝对路径。
  • 数据目录是否有写权限。

程序放到 Program Files 后,普通用户通常不能随意修改安装目录中的文件。日志、数据库和用户配置应保存到适当的可写目录。

五、在干净环境中完成验证

不要只在安装了 Qt Creator 的开发电脑上验证发布包。开发环境中的 PATH、运行库和 SDK 安装目录,可能恰好补齐了发布包缺少的文件。

更可靠的做法是在没有开发环境的电脑或虚拟机中检查:

  1. 程序能否直接启动。
  2. 主要界面、图标和翻译是否正常。
  3. 设备能否连接、断开并重新连接。
  4. 数据能否保存、查询和导出。
  5. 普通用户权限下能否正常运行。
  6. 关闭和重新启动后,配置是否仍然有效。

对于需要真实硬件的上位机,虚拟机启动测试还不能代替设备联调。最终仍应在目标操作系统、驱动和设备环境下验证。

交付时可以把完整的 dist 目录打包,也可以进一步制作安装程序。无论采用哪种方式,真正需要交付的都是一套可独立运行的文件和运行条件,而不只是一个 EXE。