ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

QT6.3.0_x86从环境配置到部署:CMake构建与插件排错全流程

QT6.3.0_x86从环境配置到部署:CMake构建与插件排错全流程 简介QT6.3.0_x86 是一份基于 Windows 环境、由 Visual Studio 2019 企业版编译生成的 Qt 6.3.0 32 位预编译 SDK 包面向需要在 x86 架构下进行 Qt 桌面应用、嵌入式界面或插件开发的开发者可直接集成到 VS2019 使用免去从源码自行编译的繁琐流程。压缩包共含 13606 个文件其中以 h 头文件5363 个、cmake 构建脚本2431 个、qml 界面描述文件660 个、dll 动态库472 个及 qm 翻译文件266 个为主覆盖 Qt Core、Gui、Widgets、Quick、Network、多媒体等常用模块整体体积约 695 MB。已有 718 人学习/下载口碑良好。借助这份预编译 SDK开发者能快速搭建 32 位 Qt 开发环境直接引用头文件与库文件进行项目配置同时可查看随包提供的 cmake 配置示例与模块依赖关系适合需要稳定 32 位构建链的 Qt 开发者及需要离线部署 SDK 的团队。1. 为什么一个“QT6.3.0_x86”包名能让老司机也翻车“QT6.3.0_x86”这个命名最常见于三类东西同事直接从安装目录压出来的 Qt 6.3.0 运行库、一个写好了 CMakeLists 的示例工程、或者某个依赖 Qt 6.3.0 的软件 SDK。它强调了版本和架构却偏偏不告诉你包里的东西对应哪套编译器、该配哪个 Kit、是不是动过 plugins 目录。于是新手照着教程装完 Qt Creator一构建就报 dependent 5.15.2 路径错误一运行就弹 qt.qpa.plugin 找不到 windows 平台插件老手则会先查 PE 头确认这包到底是 32 位还是 64 位再决定要不要往下看。这篇笔记就按“装环境→跑通最小工程→调性能→部署验证”的顺序把 x86 平台下 Qt 6.3.0 从压缩包到可用 exe 的链路一次理清适合刚拿到这类包却跑不起来的 Windows 开发者也适合准备从 Qt 5.15 迁到 6.3 的老工程维护者。2. 装对 QT6.3.0_x86版本、位数和编译器三件套2.1 先搞清楚 x86 指哪个 x32 位和 x64 是两套世界标题里的 x86 有歧义。狭义上 x86 指 32 位 Intel 指令集PE 格式里 Machine 字段是 0x14c广义上大家把 x64 也归入 x86 体系就是常说的“X86 电脑”。这两者决定你装哪个 Qt 包、配哪套第三方依赖。拿到 QT6.3.0_x86 包第一件事就是看里面有没有 msvc2019_32、mingw_32 这类目录名或者直接对 bin 下的 dll 读 PE 头——这比看文件名可靠得多。接下来是 Qt 版本、编译器 Kit、构建工具三件套。Qt 6.3.0 在 Windows 下的官方套件一般分 MSVC 系列和 MinGW 系列MSVC 和 Visual Studio 生态同源能直接调 Win32 API跟 C/CLI 或 COM 组件混编方便调试器用 CDBMinGW 自带 GCC 和 gdb装完就是一套能命令行编译的独立工具链不依赖 VS。做工业软件、要对接 Halcon 一类视觉库的我一般建议直接选 MSVC x64因为第三方闭源库几乎不给 MinGW 版就算给了 .a运行时依赖也容易出问题。如果你是从 Qt 5.15 迁过来的会觉得 6.3 的构建方式变化很大。Qt 6 整个框架用 CMake 重建新工程也默认 CMakeqmake 虽然在 6.3 里还能找到但新工程再写 .pro 属于给自己挖坑。这不只是习惯问题Qt 6 的模块依赖由 find_package 统一管理旧工程里手动用 INCLUDEPATH 指定 Qt 头文件的写法在 6.3 下很容易带出路径残留——就是后面要讲的 dependent 5.15.2 报错。目标场景推荐 Kit说明只做 Windows 桌面、和 VS 项目混编MSVC 2019 或 2022x64调试用 CDB兼容 COM/驱动层调用想要绿色解压、纯命令行编译MinGW 系列不需要装 VSgdb 调试必须用 32 位第三方库MSVC 2019 x86注意 Qt 6.x 的 32 位支持面比 5.15 窄Linux x86_64 桌面GCC 9别依赖 apt 里的老旧 Qt用安装器或 aqtinstallARM 类桌面平台交叉编译工具链x86 压缩包里的预编译库全部作废2.2 下载与组件选择勾错组件等于白装下载 Qt 6.3.0 的常见做法是走官方在线安装器或者用离线镜像。镜像站提供的是安装源目录不是单个 exe下载体积有几十 GB 量级所以组件不要贪多够用就行。组件勾选逻辑一般是这样进入 Qt 6.3.0 分类后Qt Base 是必选的做 QML 界面再加 Qt Quick 相关模块用到图表勾 Qt Charts只用 Widgets 加网络勾完 Base 就能跑。Tools 分类下Qt Creator 必选走 MSVC 要选对应调试器走 MinGW 要勾 MinGW 工具链。CMake 和 Ninja 如果系统里已经有 3.21 以上的版本可以不在这里重复勾。安装完先看目录结构。Qt 6.3.0 套件根目录下会展开 include、lib、bin、plugins、qml 五个关键目录。bin 里除了 qmake.exe还有 moc.exe、rcc.exe、uic.exe、windeployqt.exe 这些命令行工具——日常的版本校验、资源编译、部署检查其实都可以不开 Qt Creator直接在终端里做。lib 下是导入库和 CMake 配置目录plugins 是运行时插件比如 platforms/qwindows.dll 就在里面。这个结构记清楚后面所有报错排查都围绕它展开。提示老工程从 5.15 迁过来时旧的 5.15.2 套件先留着等新 Kit 跑通再卸载。留着不占多少空间但能让你在迁移失败时有一条回头路。2.3 装完先用命令行验三件事装完别急着开 IDE先打开终端验证三件事qmake 版本、CMake 是否可用、PATH 里有没有历史残留。# 1. 确认 qmake 版本和套件路径 C:\Qt\6.3.0\msvc2019_64\bin\qmake.exe -v # 2. 确认 CMake 能被找到Qt6 模块靠 CMAKE_PREFIX_PATH 定位 C:\Qt\Tools\CMake_64\bin\cmake.exe --version # 3. 查 PATH 里有没有历史 Qt 残留这条最容易被忽略 where qmakeqmake -v 会打印出 Qt 版本和构建套件如果显示的是 5.15.2说明你的 PATH 被旧版本占了。where qmake 会把 PATH 里所有 qmake 列出来出现多个结果就要小心后面构建时 find_package 可能串版本。如果你拿到的是别人给的压缩包还要再确认一下位数用 PowerShell 读 PE 头最直接# 读 PE 头 Machine 字段0x8664 是 x640x14c 是 x8632位 $p C:\Qt\6.3.0\msvc2019_64\bin\qmake.exe $fs [System.IO.File]::OpenRead($p) $br New-Object System.IO.BinaryReader($fs) $fs.Seek(0x3C, Begin) | Out-Null $pe $br.ReadInt32() $fs.Seek($pe 4, Begin) | Out-Null (0x{0:X} -f $br.ReadUInt16()) $br.Close()输出 0x8664 就是 x640x14c 是 32 位。这一步花不了一分钟但能帮你避开后面整条依赖链崩掉的尴尬。PATH 里混着多套 Qt 的问题我现在都是先查再动手很少再被“玄学报错”拖一下午。3. 跑通第一个 Qt 6.3.0 程序从清理残留到 CMake 构建3.1 先救场dependent 5.15.2 路径报错拿到压缩包工程最常见的第一个报错长这样:-1: error: dependent ..\..\..\..\..\..\qt\5.15.2\msvc2019_64\include\qtwidgets/qwidget.h does not exist.现象很直接编译器找不到一个带 5.15.2 字样、用一串 .. 拼出来的头文件路径。原因也简单工程是别人那里拷来的CMakeCache.txt 或 .pro 里残留了旧 Qt 的绝对路径或者 Qt Creator 的 Kit 还指向 5.15.2 的 qmake。这个报错和“找不到头文件”性质不同它不是缺文件而是构建系统在旧路径上找不存在的东西。处理分三步。第一步删掉 build 目录或者用 Qt Creator 清空影子构建第二步打开工具→选项→Kits把默认 Qt Version 切到 6.3.0 的 qmake第三步CMake 工程直接删掉 CMakeCache.txt 再重新配置。命令行下就是这么干rm -rf build cmake -S . -B build -G Ninja -DCMAKE_PREFIX_PATHC:/Qt/6.3.0/msvc2019_64-DCMAKE_PREFIX_PATH 是给 find_package(Qt6) 指路的唯一关键参数写错或漏写CMake 就会去系统 PATH 里碰运气找到的很可能又是 5.15.2。Ninja 比 Visual Studio 生成器快不少前提是装了 Ninja 并且 Qt Creator 的 Tools 里勾过。别去手动改 .pro 里的 INCLUDEPATH 来绕过这个报错那是拿胶布补漏你本地能过下一个人拿到照样编译失败。注意判断这个报错是“旧路径残留”还是“真缺头文件”看报错路径里的版本号就行。路径带 5.15.2、6.2.0 等你不用的版本九成是残留路径带当前 6.3.0 才考虑组件没装全。3.2 最小 CMake 工程一个窗口跑通新建一个目录放两个文件。CMakeLists.txt 这样写cmake_minimum_required(VERSION 3.21) project(Qt630Demo VERSION 1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 REQUIRED COMPONENTS Widgets) qt_standard_project_setup() qt_add_executable(Qt630Demo main.cpp ) target_link_libraries(Qt630Demo PRIVATE Qt6::Widgets)main.cpp 写一个最简窗口#include QApplication #include QLabel int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel label(QT6.3.0_x86 跑通了); label.setAlignment(Qt::AlignCenter); label.setMinimumSize(320, 120); label.show(); return app.exec(); }qt_standard_project_setup 是 Qt 6.3 开始提供的辅助函数会自动处理翻译文件、资源编译器、moc 等常规配置省掉一堆重复 CMake 代码。qt_add_executable 代替了老工程的 add_executable它会自动把 Qt 的元对象编译步骤挂上去。target_link_libraries 里的 Qt6::Widgets 由 find_package 生成链接它会连带把 Qt6Core、Qt6Gui 拉进来。构建和运行cmake -S . -B build -G Ninja -DCMAKE_PREFIX_PATHC:/Qt/6.3.0/msvc2019_64 cmake --build build ./build/Qt630Demo.exe窗口弹出来说明这套 QT6.3.0_x86 环境和编译链路是通的。如果双击 exe 没反应回到 2.3 节查 PATH大概率是串了旧版本。3.3 MSVC 下的 UTF-8中文别等乱码了再调Qt 6 的 QString 默认按 UTF-8 解释源码里的窄字符串字面量所以很多 Qt 5 时代的中文乱码问题在 6.3 里已经缓解。但如果你用 MSVC 编译且源文件保存成了 GBK 编码编译器会按当前代码页去读窗口里就会出现“跑通了”变成“跑通了”这类乱码。Qt 5 时代大家靠 QTextCodec 和 #pragma execution_character_set(utf-8) 绕过Qt 6 里 QTextCodec 不再是推荐方案。正确做法是直接在 CMake 里给 MSVC 加一个编译选项让编译器把源码当 UTF-8 处理if(MSVC) target_compile_options(Qt630Demo PRIVATE /utf-8) endif()这个选项同时影响源文件解释和执行字符集加上之后从 Qt 5.15 老工程搬过来的中文源码字面量基本不用改。如果团队里有人的编辑器默认不是 UTF-8 保存建议顺手在 .gitattributes 里把 *.cpp 和 *.h 定义为 utf-8省得每次换人接手都出一轮乱码。4. 界面与数据传输表格卡顿和大文件传输的落地做法4.1 QTableWidget 换 QTableView 自定义 QAbstractTableModel十万行不卡“qt 表格大数据卡顿”这个问题几乎每个做桌面工具的都会遇到。QTableWidget 在几百行时还凑合上了几千行就开始拖一万行基本卡到没法看。原因是 QTableWidget 为每个单元格都 new 一个 QTableWidgetItem一万行乘十列就是十万个对象光创建和布局就要占掉大量时间滚动时这些对象还要反复参与计算。解决办法是把数据和视图分离自己实现一个 QAbstractTableModel然后交给 QTableView 去显示。这也是 Qt 里 MVVM 思路的基础形态模型层只提供数据访问接口视图层按需取数据。先定义数据结构和模型头文件#pragma once #include QAbstractTableModel #include QVector struct Record { int id; QString name; double score; }; class RecordModel : public QAbstractTableModel { Q_OBJECT public: using QAbstractTableModel::QAbstractTableModel; void setRecords(const QVectorRecord rows); int rowCount(const QModelIndex parent {}) const override; int columnCount(const QModelIndex parent {}) const override; QVariant data(const QModelIndex index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; private: QVectorRecord rows_; };模型实现文件#include RecordModel.h void RecordModel::setRecords(const QVectorRecord rows) { beginResetModel(); // 通知视图数据要整体刷新 rows_ rows; endResetModel(); } int RecordModel::rowCount(const QModelIndex parent) const { return parent.isValid() ? 0 : rows_.size(); } int RecordModel::columnCount(const QModelIndex parent) const { return parent.isValid() ? 0 : 3; } QVariant RecordModel::data(const QModelIndex index, int role) const { if (!index.isValid() || index.row() rows_.size()) return {}; const Record r rows_.at(index.row()); switch (role) { case Qt::DisplayRole: switch (index.column()) { case 0: return r.id; case 1: return r.name; case 2: return QString::number(r.score, f, 2); // double 转字符串 } break; case Qt::TextAlignmentRole: return index.column() 2 ? Qt::AlignRight : Qt::AlignLeft; default: break; } return {}; } QVariant RecordModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role ! Qt::DisplayRole) return {}; if (orientation Qt::Horizontal) { switch (section) { case 0: return tr(ID); case 1: return tr(名称); case 2: return tr(得分); } } return section 1; }在窗口里挂上模型RecordModel model; model.setRecords(makeRecords(100000)); // 10 万行数据 ui-tableView-setModel(model); ui-tableView-verticalHeader()-setDefaultSectionSize(24); ui-tableView-setUniformRowHeights(true);几个关键点。第一setRecords 里 beginResetModel/endResetModel 必须成对出现漏掉的话视图不知道数据变了表格显示不出来第二data() 里只做按行取数据这种轻量操作千万别在这里查数据库或做复杂计算QTableView 是懒加载只对可见区域的行调用 data()这正是它快的根本原因第三setUniformRowHeights(true) 加上垂直表头的默认行高能让视图跳过逐行测高的步骤滚动时省一大截布局时间。有读者反馈“换成 QTableView 自定义 model 后视图只显示几十行”这基本是三种情况rowCount 返回了 0data() 对 Qt::DisplayRole 返回了无效 QVariant或者 setRecords 里忘了 beginResetModel。挨个排查就行。排序和筛选可以再套一个 QSortFilterProxyModel但不要在代理的 lessThan 里做重量级操作否则排序一触发又会卡回去。如果界面复杂度继续往上走Qt 6.3.0 里也有人用更完整的 MVVM 框架来组织模型层或者干脆把复杂页面交给前端 Vue3通过 QWebEngineView 加载本地静态资源再用 QWebChannel 做桥接。那是另一个大话题但模型和视图分离这条思路是它的地基先把 QAbstractTableModel 吃透后面都好说。4.2 大文件网络传输别一次读进内存用结构体包头加分块发送大文件传输这个话题常见翻车是把几个 GB 的文件一次性 read 进 QByteArray然后整个 write 给 QTcpSocket。后果是内存峰值直接等于文件大小写 socket 时还会因为内核缓冲区分批发送导致长时间占用线程。在 32 位 x86 程序里这个内存峰值更容易触发崩溃因为 32 位进程的用户态地址空间天然受限。分块发送是常规解法。发送端用一个固定大小的缓冲区循环读文件void sendFile(QTcpSocket *socket, const QString path) { QFile f(path); if (!f.open(QIODevice::ReadOnly)) return; const qint64 total f.size(); // QFileInfo 也可以拿大小QFile 直接拿更省事 qint64 sent 0; QByteArray block(64 * 1024, Qt::Uninitialized); while (sent total) { qint64 n f.read(block.data(), block.size()); if (n 0) break; if (socket-write(block.constData(), n) -1) break; sent n; } }块大小一般取 64KB 到 1MB。太小的话 TCP 小包多吞吐上不去太大会让内存峰值变高也容易把 socket 发送缓冲填满。这个同步循环只是演示真放在 GUI 线程里几十 MB 的文件就能让界面卡住。可靠做法是把收发逻辑放进 QThread用 moveToThread 迁过去或者用 Qt 6 提供的异步上传接口让事件循环驱动发送不要在一帧里把整个文件塞进发送缓冲。还有两个细节。一是循环里不要频繁调用 flush()每块 flush 会让发送队列反复排空速度可能掉一个数量级二是接收端要按文件长度累计写入写之前用 QFile::resize 预分配空间避免磁盘频繁扩展。协议包头建议用紧凑结构体但要注意 C 结构体默认对齐会插入填充字节#pragma pack(push, 1) struct FileHead { char magic[4]; // Q,F,I,L quint64 fileSize; // 文件总字节数 quint32 nameLen; // 文件名长度 }; #pragma pack(pop)不加 pack(push,1) 的话char[4] 后面会填充 4 字节quint32 后面再填 4 字节两边编译器对齐规则不一致时收端解析包头就会错位文件名和大小全乱。这个坑我在跨平台联调时踩过后来凡是走网络的协议结构体一律显式 pack。5. 避坑清单拿到 QT6.3.0_x86 包之后的五个高频报错5.1 qt.qpa.plugin could not find the qt platform plugin “windows”现象是双击 exe 弹窗提示 could not find the qt platform plugin “windows” in “”引号里是空的。很多人这时候会去拷 Qt6Core.dll其实方向错了Qt 的窗口系统插件是 platforms 目录下的 qwindows.dll程序启动时要加载它找不到就会报这个错。常见原因有两个分发时把 plugins 目录整个漏了或者把 64 位 exe 配上了 32 位平台的插件位数不匹配同样报这个错。临时验证可以这样set QT_QPA_PLATFORM_PLUGIN_PATHC:\Qt\6.3.0\msvc2019_64\plugins MyApp.exe但正式交付不要靠环境变量应该用 windeployqt 生成完整的部署目录见第 6 章。排查时先把 Qt 运行时当黑匣子对付先看 exe 同目录下有没有 platforms/qwindows.dll再看它和 exe 的位数是否一致最后再看环境变量有没有指向错误版本。5.2 dependent “......\qt\5.15.2\msvc2019_64\include\qtwidgets…” 残留这个报错在 3.1 节已经救过一次场这里再补一条血泪经验它最容易出现在“压缩包工程”里因为压缩包会把 build 目录一起打包而 build 目录里的 CMakeCache.txt 记录着对方机器的绝对路径。你解压后直接打开CMake 读缓存里的旧路径自然报 dependent 5.15.2。解决就一句删掉 build 目录和 CMakeCache.txt让 CMake 重新配置。不要尝试在 CMakeLists.txt 里加 include_directories 硬凑那只会把问题盖住。重配时把 -DCMAKE_PREFIX_PATH 指到 6.3.0 的套件一次就干净。5.3 启动崩溃或提示无法定位程序输入点程序一启动就崩或者弹“无法定位程序输入点于 Qt6Core.dll”多半是 PATH 里混进了多套 Qt。Windows 加载 dll 是沿着 PATH 顺序找的如果 C:\Qt\5.15.2\msvc2019_64\bin 在 PATH 前面6.3.0 的 exe 运行时就会加载旧版 Qt6Core.dll函数符号对不上直接崩。查一下机器上有几套 Qtwhere /r C:\Qt Qt6Core.dll启动时用批处理把目标版本放在最前set PATHC:\Qt\6.3.0\msvc2019_64\bin;%PATH% start MyApp.exe想验证到底加载了哪个路径用 Process Explorer 看进程模块列表里的 Qt6Core.dll 位置。我的习惯是一台机器只在 PATH 里保留一个 Qt 版本的 bin其余版本交给 CMake 的 CMAKE_PREFIX_PATH 按工程隔离互不干扰。5.4 32 位程序调用 Halcon 等第三方库直接崩现象是程序一调 Halcon 的接口就崩或者提示“不是有效的 Win32 应用程序”。原因通常是对接的 Qt 是 32 位第三方库装的是 x64 版。Windows 一个进程里所有 dll 的位数必须一致x86 进程加载不了 x64 dll反之亦然。解决方向是让整条依赖链统一。现在新版的 Halcon 等视觉库基本只给 x64所以 Qt 也要用 msvc2019_64 套件第三方库装 x64 版。如果业务铁了心要 32 位那 Qt 必须用 msvc2019_32所有依赖库也都要找 32 位版MSVC 编译选项再配 /arch:IA32。这个决定最好在选型阶段做别等代码写了一半再换——换架构不是只换个安装包所有第三方头文件、库路径、部署脚本都要跟着动。顺带说一句 aarch64 之类 ARM 平台如果目标是这类桌面系统x86 压缩包里的预编译库一个都用不上要从交叉编译工具链重新开始这是另一套玩法了。5.5 缺少 VC 运行库和卸载残留到客户机器上跑提示缺少 VCRUNTIME140.dll 或 MSVCP140.dll这就是 MSVC Kit 编译的程序在裸奔。Qt 的 MSVC 套件依赖 Visual C 运行库新装的精简系统不一定带。常见做法是给目标机器装 VC_redist.x64.exe 和 VC_redist.x86.exe如果不想让客户装东西部署时用 windeployqt 加 --compiler-runtime 参数运行库会直接拷进 exe 目录。卸载残留是另一个容易被忽视的坑。重装 Qt 时如果旧版没卸干净装完发现 Kit 列表里出现两个 6.3.0版本还互相打架。正确顺序是先跑在线安装器的维护模式卸载再手动删 C:\Qt 目录和用户缓存里的 Qt 配置目录。直接删文件夹会留下注册表和 Qt Creator 的 Kit 残留下次装新版这些残留继续污染环境。6. 把 exe 带到干净机器上windeployqt 与部署自检6.1 windeployqt 参数速查windeployqt 是 Qt 自带的分析工具扫描 exe 的导入表把依赖的 Qt dll、插件、QML 模块拷到目标目录。参数不多常用的就下面几个参数作用什么时候用--release部署 release 版本默认就是可省--no-translations不拷贝翻译文件程序不需要国际化时--compiler-runtime顺带拷贝 VC 运行库目标机器是精简系统时--qmldir指定 QML 源码目录用了 QML 时必须给--dir指定输出目录默认当前目录对 Widgets 程序命令一般是cd build C:\Qt\6.3.0\msvc2019_64\bin\windeployqt.exe --release --no-translations --compiler-runtime MyApp.exe跑完后 exe 旁边会出现 platforms 目录里面有 qwindows.dll这才是一个能搬走的完整目录。6.2 三种验证手段我第一次部署 Qt 程序就吃过亏在自己机器上双击正常拷去客户机器报平台插件错误。后来养成一个习惯交付前做三件事。第一把 PATH 里的 Qt bin 临时去掉再双击 exe如果还能起来说明没有偷偷依赖环境变量第二用 Process Explorer 看进程加载的 Qt6Core.dll 路径确认是用部署目录里的那个不是系统里捡来的第三检查 platforms/qwindows.dll 和 exe 的位数一致这一步用 2.3 节的 PowerShell 脚本读一遍就行。6.3 收尾习惯第三方库按需手动拷。windeployqt 只认 Qt 自己的依赖Halcon、OpenCV 这类 dll 不会自动带出来要和 exe 放同一个目录或者放到子目录后加 PATH。用 Inno Setup 做安装包时也建议把 VC 运行库和插件的目录结构原样保留别做扁平化处理否则插件路径一旦变qt.qpa.plugin 的报错会原样回来。这些事没有技巧含量纯粹靠每次打包后多花两分钟自检。毕竟部署目录里的每一份 dll都应该有它存在的理由而不是靠运气。希望帮到你。本文还有配套的精品资源点击获取
返回列表