☰
Windows 10下编译Qt 5.15.12 32位动态库实战指南
2026/10/17 2:52:44 网站建设 项目流程

简介:Qt 5.15.12 这个版本是针对 Windows 10 操作系统专门编译的 32 位动态库,采用微软公司推出的可视化编译工具链构建而成;它主要面向那些需要在三十二位 Windows 环境下开发 Qt 图形用户界面程序的软件工程师,尤其适合需要兼容老旧系统或者希望严格控制外部依赖的工程项目。整个压缩包的大小约为三百六十兆字节,其中一共包含两千个头文件,覆盖了窗体控件、网络通信、核心数据结构等常用模块,为程序编写、编译连接以及最终部署提供了完整的接口声明。这一版本目前已有五百八十六人学习或下载使用;值得留意的是,这个版本没有集成网页浏览引擎,因此在体积上更加紧凑,同时也保留了对安全传输协议的支持,并且同时提供调试版本和发布版本两种模式,方便开发者开展测试与正式部署。利用这批头文件,开发者可以快速搭建或者迁移三十二位的 Qt 项目,在保证功能完整的前提下获得更高效的编译和构建体验。

1. 从 Windows 10 环境折腾 Qt 5.15.12 的 32 位动态库说起

接手一个老项目的维护时,我发现自己被卡在一个很基础但绕不过去的问题上:目标机器是 32 位的 Windows 10,依赖方只接受 DLL 形式的解耦模块。用 Qt 写界面和业务逻辑没问题,但编译输出默认跟着系统位数走,一不留神就生成 64 位的 .dll,对方一加载直接报"不是有效的 Win32 应用程序"。同样的坑,换台机器再踩一次就知道,编译 Qt 动态库这件事,本质上是在跟编译器位数、Qt 安装方式、环境变量和源码包较劲。这篇文章就从 Qt 5.15.12 这个版本入手,把在 Windows 10 上编 32 位动态库的完整流程、参数设置和翻车点拆开讲透,适合需要为老系统提供 32 位模块的 C++ 开发者,也适合刚接触 Qt 组件化开发的人快速摸清门道。

2. 为什么选 Qt 5.15.12 和 32 位动态库:编译前的三个关键决策

2.1 版本选择的现实考量:LTS 生命周期与离线安装包

Qt 5.15 是 Qt 5 系列的最后一个 LTS 分支,5.15.12 算是这个分支里比较后期的补丁版本,bug 修复比较完整。更重要的是,它还有离线安装包和源码包,对国内开发环境来说,不用依赖在线安装器来回拉取国外服务器,省去很多等待时间。

选 32 位还涉及一个系统兼容性事实:Windows 10 虽然主流是 64 位,但不少工控机、旧式收银设备、银行柜面终端依然是 32 位系统,或者 64 位系统但只装了 32 位的运行库。如果对方系统跑着 32 位进程,你的 DLL 必须是 32 位,否则 LoadLibrary 直接失败。这类问题往往出现在"程序已经写好、准备交付"的阶段,那时候再回头编 32 位版本,成本最高。所以我的习惯是:项目一开始就确认目标平台位数,并且在开发机里同时保留 32 位和 64 位两套 Qt 环境。

2.2 动态库与静态库的选择边界

同一份源码,可以选择编译成 DLL(动态库)或者 LIB(静态库)。动态库文件小,调用方可以独立升级,但你必须把对应的 DLL 一并分发;静态库编进 exe 里,部署简单,但文件体积变大,Qt 自身的 LGPL 授权条款也要求动态链接方式更方便合规。

在 Qt 5.15.12 的源码包里,默认编译方式就是动态库,你不需要额外修改配置。用 configure 脚本加上合适的参数,它会生成 Qt5Core.dll、Qt5Gui.dll、Qt5Widgets.dll 这些模块。如果业务方要求"只给你们模块的 DLL,不暴露源码",这种编译方式就是标准答案。

2.3 编译器选型:MSVC 还是 MinGW

在 Windows 平台上编 Qt,编译器主要两条路线:MSVC(微软的 Visual Studio 工具链)和 MinGW(GCC 的 Windows 移植版)。编译出来的 DLL 并不互通,MSVC 编的 DLL 让 MinGW 编的 exe 去 LoadLibrary 调用,经常会因运行时库不一致导致崩溃或莫名其妙的符号错误。

通常遵循的原则是:调用方用什么编译器,你编 DLL 就用什么编译器。如果调用方是用 Visual Studio 开发的 C++ 项目,必须用 MSVC 编译;如果调用方是 MinGW 或 Code::Blocks 类的环境,就需要准备 MinGW 版本的 Qt。我一般在 Windows 10 上用的组合是 MSVC 2019 的 x86 环境 + Qt 5.15.12 源码包,这样可以顺带支持 32 位 MSVC 应用。

另外要注意,这里有一个"位数一致性"的细节。32 位编译不是单纯在命令行加个 -m32 就行,它要求整套工具链都切换到 x86 模式。MSVC 的 x86 编译环境需要启动"x86 Native Tools Command Prompt",或者用 vcvarsall.bat 初始化环境变量。我在刚试这套操作的时候,直接在普通 CMD 里敲 nmake,结果报错"无法打开 include 文件 'winnt.h'",原因就是没有初始化 MSVC 的环境变量。后面会专门讲这个坑。

3. 搭建 Qt 5.15.12 动态库编译环境:源码获取与工具链准备

3.1 获取 Qt 5.15.12 源码并安排目录

Qt 5.15.12 的源码包可以从 Qt 官方仓库的历史版本区获取,通常是一个大约 500MB 到 1GB 的压缩包(不同分发渠道大小略有差异)。拿到源码后第一件事是把压缩包解压到一个路径简单、没有空格和中文的目录下,例如 D:\Qt\src\qt-5.15.12。

目录结构非常关键,因为 Qt 的构建系统对路径非常敏感。我曾经把源码放在 D:\Qt 源码\qt-5.15.12,结果 configure 阶段反复报找不到文件,最后发现是中文路径和空格惹的祸。此后我给自己定了一个规矩:所有编译相关的工作目录一律纯英文、纯小写,宁可多敲几个字符也不留隐患。

# 示例:在 Windows 终端中解压,注意目标路径 mkdir D:\Qt\src tar -xf qt-everywhere-src-5.15.12.tar.xz -C D:\Qt\src cd D:\Qt\src\qt-everywhere-src-5.15.12

Qt 5.15 之后,源码包是"everything"模式,也就是包含 qtbase、qtdeclarative、qtquickcontrols 等全模块。编译整个包非常耗时,我们只需要其中几个核心模块,所以后续 configure 阶段需要通过参数裁剪。不裁剪的话,一个完整构建可能要跑 2 小时以上,裁剪之后一般 20 分钟能完成。

3.2 安装并初始化 MSVC 2019 的 32 位工具链

如果还没有安装 Visual Studio 2019(或 2022,两个版本都能支持 Qt 5.15.12),需要先安装,并且安装时勾选"使用 C++ 的桌面开发"工作负载。这里不必装完整 VS,只装 Build Tools 也可以,但要确保包含 MSVC v142 工具集和 Windows 10 SDK。

编译 32 位 Qt 时,我一般用 x86 Native Tools 命令行窗口,而不是默认的"开发人员命令提示符"。因为后者默认是 64 位编译环境,哪怕你敲 cl 编译单个文件,默认输出的也是 64 位目标文件。很多人在这一步翻车,编译出来的 Qt5Core.dll 是 64 位,调用方加载才发现位数对不上。

# 打开 x86 Native Tools Command Prompt(或者手动执行 vcvarsall.bat) call "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars32.bat"

执行完之后,可以通过 cl 命令验证环境是否切到了 32 位:

cl # 输出第一行会显示 "for x86" / "x86" 相关内容

3.3 处理 Perl 和 Python 依赖

Qt 编译过程中有几个辅助工具是依赖 Perl 的,比如同步翻译文件和部分代码生成逻辑。如果机器上没有 Perl,configure 阶段会给出警告或者直接失败。常见做法是安装 Strawberry Perl,并把安装目录加入系统 PATH。此外,Qt 5.15 部分模块会用到 Python,但如果我们只编译 qtbase 和基础模块,可以跳过大多数 Python 相关依赖。为了保险,我一般在环境里装一个 Python 3.8 以上版本并加入 PATH,避免某些模块自动扫描时找不到解释器。

# 确认依赖是否就绪 perl --version python --version

这两个命令如果在 x86 Native Tools 环境里能正常输出版本号,说明基本依赖到位。需要提醒的是,PATH 里如果存在多个 Perl 或 Python 版本,configure 可能会选错,遇到"找不到模块"的报错时可以优先检查一下当前用的是哪个版本的解释器。

4. configure 与 nmake 实战:把 Qt 5.15.12 编成 32 位 DLL

4.1 configure 参数拆解:平台、模块、后缀与位数

进入源码目录后,运行 configure 是决定整个编译方向的关键一步。我通常用下面的参数组合,这里逐项说明每个参数的作用:

configure.bat -platform win32-msvc -debug-and-release -opensource -confirm-license -shared -mp -nomake examples -nomake tests -skip qtwebengine -skip qt3d -skip qtquick3d -prefix D:\Qt\5.15.12\msvc2019 -opengl desktop -angle -suffix 32
  • -platform win32-msvc:告诉 Qt 构建系统使用 MSVC 编译器和 Windows 平台定义,注意这里的 win32 指的就是 Windows API,跟 32 位、64 位没有直接关系,真正决定位数的是当前命令行环境的 cl 是 x86 还是 x64。
  • -debug-and-release:同时生成 debug 和 release 两个版本的库。如果不加这个参数只编译 release,后面调试阶段你会发现没有对应的 .pdb 文件和 debug 版 DLL,断点进不去。
  • -opensource -confirm-license:接受开源协议,避免出现交互式确认弹窗阻塞构建。
  • -shared:指定生成动态库(DLL),这也是 Qt 默认值,但显式写出来更保险。
  • -mp:启用多进程编译。现代 CPU 都至少 4 核,不加这个参数据说编译时间会翻倍。
  • -nomake examples -nomake tests:跳过示例和测试代码的编译。这两个模块跟最终 DLL 没有关系,裁剪掉能省大量时间。
  • -skip qtwebengine:跳过 WebEngine 模块。这个模块体积巨大,而且要额外下载 Chromium 源码,很多环境编译会卡死在网络请求上。如果项目用不到浏览器内核,务必加上这个跳过项。
  • -prefix:指定安装目录。编译完成后执行 nmake install 会把 DLL、LIB、头文件拷贝到这里,方便后续其他 CMake 工程引用。
  • -opengl desktop -angle:桌面 OpenGL 优先,同时保留 ANGLE 作为备选,兼容没有独立显卡的远程桌面环境。
  • -suffix 32:这个参数很实用,它会给生成的 DLL 文件名加一个 32 后缀,比如 Qt5Core32.dll。这样在同一台机器上同时安装 32 位和 64 位 Qt 时,两个版本的 DLL 不会互相覆盖。如果你不分发给别人,只是自己本地开发,不加这个也行;但一旦要交付 32 位版本给老系统,带后缀更能防止"拷错文件"。

configure 执行完以后,终端会打印一行编译配置摘要,包含 Qt 版本、位数、模块启用情况。我一般会看两处:一是Building for后面的架构是否显示x86,二是Qt modules and options里是否包含Qt Core、Qt GUI、Qt Widgets这些必要模块。

4.2 nmake 编译与 install 安装

configure 通过之后,直接在当前目录执行 nmake。这里没什么技巧,就是等。第一次编译 qtbase 模块时,我大概花了 15 到 20 分钟(8 核 CPU 情况下)。期间如果屏幕滚动飞快,说明编译正常;如果长时间没有任何输出,注意检查资源管理器里 CPU 占用率,很多杀毒软件后台扫描会拖慢编译进程,极端情况下会卡死。

nmake nmake install

nmake install会把编译产出的 DLL、LIB、头文件、mkspec 配置统一拷贝到D:\Qt\5.15.12\msvc2019目录。安装完成后,进入该目录的 bin 子目录,确认一下 Qt5Core32.dll 等文件确实生成了。我习惯用dir /b D:\Qt\5.15.12\msvc2019\bin\*.dll快速列一下 DLL 文件,确认数量是否正常。如果 bin 目录是空的,说明 install 目标有问题,检查 configure 的 -prefix 参数是否写对了。

4.3 验证 DLL 位数:dumpbin 检查导出函数与架构

编译完成后,验证输出的 DLL 是 32 位还是 64 位,这一步不能跳过。Windows 下最直接的方式是用 VS 自带的 dumpbin 工具。

dumpbin /headers D:\Qt\5.15.12\msvc2019\bin\Qt5Core32.dll | findstr /i "machine" # 输出 "machine (x86)" 即为 32 位 DLL,输出 "machine (x64)" 则是 64 位

如果是 x64,说明前面某个环节出了问题,最常见的原因是当前命令提示符不是 x86 模式,configure 时 cl 是 64 位版本,编译出来当然是 64 位。不要慌,重新打开 x86 Native Tools 命令行,删掉源码目录下的config.cache和Makefile文件,重新执行 configure 即可。不清理缓存直接重跑 configure,可能会沿用上一次的配置,导致位数依然不对。

4.4 编写一个最小 tests 程序链接 32 位 Qt DLL

仅仅有 DLL 还不够,得写一个小程序验证整个调用链是通的。在独立目录创建一个min_test文件夹,里面放一个简单的 QWidget 应用:

// main.cpp #include <QApplication> #include <QLabel> int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel label("32-bit Qt DLL works"); label.resize(240, 80); label.show(); return app.exec(); }

对应的 CMakeLists.txt 内容如下:

cmake_minimum_required(VERSION 3.16) project(min_test) set(CMAKE_PREFIX_PATH "D:/Qt/5.15.12/msvc2019") set(CMAKE_INCLUDE_CURRENT_DIR ON) find_package(Qt5 COMPONENTS Core Widgets REQUIRED) add_executable(min_test main.cpp) target_link_libraries(min_test Qt5::Widgets Qt5::Core)

用 32 位的 MSVC 环境执行cmake -G "Visual Studio 16 2019" -A Win32生成项目,或者直接用 nmake 方式构建。注意这里的-A Win32是显式指定生成 32 位工程的关键。有人会漏掉这一步,结果 CMake 默认生成 x64 工程,链接阶段报"无法解析的外部符号",原因就是库是 32 位而目标程序是 64 位。

运行生成的 exe,弹出窗口显示 "32-bit Qt DLL works" 说明整个链路没问题。如果 exe 运行时提示缺少 Qt5Core32.dll 或 Qt5Widgets32.dll,把D:\Qt\5.15.12\msvc2019\bin加入系统 PATH 或者把 DLL 文件复制到 exe 同目录即可。

5. 编译期与运行期的九条避坑记录:现象、原因、解决

5.1 configure 报 "NMAKE is not recognized as an internal or external command"

现象:在普通 CMD 窗口执行 nmake,提示命令不存在。
原因:没有进入 MSVC 的编译环境,PATH 里没有 nmake 的路径。
解决:必须通过 x86 Native Tools Command Prompt,或者先执行 vcvarsall.bat,确保环境变量初始化。千万不要在未初始化环境的 shell 里尝试编译 Qt。

5.2 configure 检测到 64 位编译器而不是 32 位

现象:configure 过程中打印Building for: x86_64,但明明需要 32 位。
原因:vcvarsall 启动了 x64 环境,或者打开的是默认的 Developer Command Prompt。
解决:关闭当前窗口,重新打开 x86 Native Tools 命令行;如果手动执行 vcvarsall,确认参数是vcvars32.bat,不是vcvars64.bat。

5.3 编译过程中报 "fatal error C1083: Cannot open include file: 'winnt.h'"

现象:编译到一半,许多源文件报找不到 Windows SDK 头文件。
原因:MSVC 环境变量没有初始化,或者安装 VS 时没有勾选 Windows 10 SDK。
解决:重装或修改 VS 安装选项,勾选 Windows 10 SDK;执行 vcvars32.bat 之后检查include环境变量是否包含 SDK 头文件路径。

5.4 生成了 DLL 但调用方提示 "bad image" 或 "不是有效的 Win32 应用程序"

现象:调用方加载 DLL 直接失败,事件查看器里记录为错误模块。
原因:绝大多数情况是 DLL 本身是 64 位,调用的 exe 是 32 位,位数不匹配。
解决:用 dumpbin 检查 DLL 的 machine 类型;如果确认是 x64,重新按 32 位流程编译。

5.5 Qt5Core.dll 被其他版本覆盖,程序运行时版本错乱

现象:程序偶尔崩溃,或者在 Debug 窗口看到 Qt 版本不匹配的警告。
原因:bin 目录里同时存在不带后缀的 Qt5Core.dll 和带 32 后缀的版本,另一个安装的 Qt 版本覆盖了无后缀 DLL。
解决:configure 时加-suffix 32,让 32 位 DLL 带独立文件名;程序链接时也统一引用带后缀的 DLL,避免冲突。

5.6 编译 Qt WebEngine 卡死在下载 Chromium 源码

现象:nmake 执行十几分钟后,终端显示一直在从download.qt.io拉取压缩包,进度条极慢甚至失败。
原因:WebEngine 模块依赖 Chromium 源码,体积超过 2GB,网络不稳定时基本无法完成。
解决:configure 时加-skip qtwebengine,同时按照项目需求加-skip qt3d -skip qtquick3d -skip qtcharts等用不到的模块。一般工业 HMI 或工具类软件根本不需要这些。

5.7 编译完成后 bin 目录下找不到 install 的 DLL

现象:nmake 之后执行 nmake install,install 目录 bin 下只有几个 exe 不是预期的 DLL。
原因:一部分原因是 configure 的-prefix路径写错,还有一部分原因是 nmake 编译的实际输出目录在某个lib或bin子目录,没有被打包进安装目录。
解决:检查D:\Qt\src\qt-everywhere-src-5.15.12\qtbase\lib下是否存在 DLL;如果确实生成了但没 install,手动把 DLL 和 LIB 复制到目标目录。

5.8 调用程序编译时报链接错误 LNK1112:模块计算机类型与目标计算机类型冲突

现象:CMake 编译通过了,链接时报LNK1112。
原因:目标 exe 是 32 位,但编译过程中 CMake 实际使用的是 x64 工具链,导致 obj 文件是 x64,DLL 是 x86,链接器无法合并不同位的对象文件。
解决:CMake 配置时显式指定-A Win32,确保整个编译工具链都是 32 位。

5.9 运行时中文显示乱码或字体异常

现象:32 位 DLL 集成到老系统后,界面中文文字变成方块或乱码。
原因:老系统缺少中文字体,或者 Qt 的字体匹配策略与当前 Windows 10 字体库有差异。
解决:程序启动时用QFontDatabase检查可用字体,优先设置Microsoft YaHei或SimSun;如果 DLL 是嵌入到另一个进程里,需要确认该进程是否初始化了 OleInitialize 或字体相关资源,常见做法是在 DLL 加载后调用一次QApplication或QFont初始化。

6. 进阶验证:用 dumpbin 检查 DLL 依赖并梳理部署清单

编译完成只是第一步,真正交付之前还需要做依赖审查。动态库不像静态库那样把所有依赖打包进来,Qt5Core32.dll 自身还依赖VCRUNTIME140.dll、MSVCP140.dll以及若干系统 DLL。用 dumpbin 可以快速查看这些依赖:

dumpbin /dependents D:\Qt\5.15.12\msvc2019\bin\Qt5Core32.dll

输出列表里如果出现MSVCP140.dll和VCRUNTIME140.dll,说明目标机器需要安装 VC++ Redistributable。我一般建议在交付说明里写清楚"需要安装 Visual C++ 2019 x86 运行库",或者直接把运行库安装包一起打包。调用方如果没装,现象是程序启动时弹窗报"缺少 MSVCP140.dll"。

接下来梳理一份完整的部署清单,通常包含以下内容:

文件/目录说明
Qt5Core32.dllQt 核心模块,几乎所有 Qt 应用必需
Qt5Gui32.dllGUI 基础模块,涉及窗口绘制和输入处理
Qt5Widgets32.dll窗口部件模块,使用 QWidget 时需要
Qt5Platforms/qwindows.dllWindows 平台插件,无此文件程序无法启动
styles/qmodernwindowsstyle.dll可选,部分样式渲染需要
vc_redist.x86.exe运行库安装包,目标机器缺运行库时用

这里有一个很容易被忽略的细节:如果 DLL 是被其他程序动态加载(LoadLibrary),那么 Qt5Gui32.dll 的目录必须在QT_QPA_PLATFORM_PLUGIN_PATH环境变量指定的路径中找到qwindows.dll,否则被集成方调用 Qt 窗口时,界面初始化直接失败,而且不一定报错,只会在日志里留下一句could not find the Qt platform plugin "windows"。这个坑我踩过一次,后来习惯在 DLL 导出函数入口处写一段路径设置逻辑。

// dllmain.cpp 片段:加载前设置平台插件路径 #include <QtCore/qglobal.h> #include <QtCore/qcoreapplication.h> #include <QtCore/qdir.h> void setup_environment() { QString appDir = QCoreApplication::applicationDirPath(); qputenv("QT_QPA_PLATFORM_PLUGIN_PATH", appDir.toLocal8Bit() + "/platforms"); }

需要说明的是,这个设置要在任何 QGuiApplication 实例创建之前完成,否则qwindows.dll的加载顺序会抢在路径设置之前,依然找不到插件。通常的写法是在 DLL 的DllMain里不调用 Qt 函数,而在导出的初始化函数里先调用setup_environment()再创建 QApplication 对象。

最后是一个实际工作中总结出来的检查习惯:每次编译完,我会按顺序执行三步——先 dumpbin 看机器类型,再确认 DLL 依赖列表,最后用一个 32 位测试 exe 实际加载一次。三步都通过,才敢把 DLL 发给下游。从那以后我每次换环境或者改 Qt 版本,都强制走一遍这套流程,省掉的排查时间远比操作多。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询