☰
VS2015下QtXlsxWriter编译与集成实战:从踩坑到生成Excel
2026/10/13 20:48:56 网站建设 项目流程

1. 为什么一个"菜鸟"会卡在 QtXlsxWriter 的编译上

如果你正在用 VS2015 做 Qt 相关的桌面开发,突然接到一个需求:把界面上的数据导出成 Excel 文件。你第一反应可能是——Qt 自带的 QTableWidget 数据导出成 CSV 挺简单,但 CSV 打开后中文乱码、格式全丢、客户还嫌弃"这不是真正的 Excel"。于是你开始找能直接生成.xlsx文件的库,搜来搜去,QtXlsxWriter 几乎是绕不开的选择。

问题来了。QtXlsxWriter 这个库,官方文档写得比较"工程师向",默认你熟悉 qmake 的编译流程、知道怎么把第三方库塞进 Qt 工程、看得懂.pro文件里那些include()和link()的写法。但如果你是从 Visual Studio 那一套sln + vcxproj的思维过来的,或者平时写 Qt 主要靠 Qt Creator 点点点,那第一次编译 QtXlsxWriter 大概率会卡住。

我自己第一次搞这个库的时候,在 VS2015 环境下折腾了差不多一个下午。报的错五花八门:一会儿是nmake找不到,一会儿是qmake不是内部命令,一会儿编译过了但链接的时候一堆unresolved external symbol。最坑的是,网上搜到的教程大多是 Qt Creator 的,或者用的是 MinGW 版本的 Qt,跟 VS2015 + MSVC 这套组合拳对不上。

所以这篇东西,就是把我踩过的坑、绕过的弯,按一个"菜鸟也能跟着做"的顺序重新捋一遍。核心目标只有一个:在 VS2015 环境下,把 QtXlsxWriter 编译成可用的库,并且能在一个 Qt 工程里成功调用它生成 xlsx 文件。我会把每一步为什么这么做讲清楚,而不是甩一堆命令让你复制粘贴。适合的人群很明确:用 VS2015 写 Qt、对 qmake 和 nmake 不太熟、但需要导出 Excel 功能的开发者。

2. 动手之前,先把这几个概念和工具理清楚

2.1 QtXlsxWriter 到底是个什么东西

QtXlsxWriter 是一个基于 Qt 的第三方库,专门用来读写 Excel 的.xlsx格式文件。注意,它处理的是 Office 2007 之后的那种基于 XML 的 xlsx,不是老的.xls二进制格式。它的工作方式不依赖 Office 组件,也不需要装 Excel,纯靠 Qt 自己的QIODevice、QXmlStreamWriter这些类把数据按 OOXML 规范写进压缩包里。这一点很关键——意味着你打包发布的程序,客户机器上不装 Office 也能正常导出 Excel。

它提供的能力大致包括:创建工作表、写入单元格数据(字符串、数字、日期、公式)、设置单元格格式(字体、颜色、边框、对齐)、合并单元格、插入图片、设置列宽行高等等。对于绝大多数"把表格数据导出成 Excel"的需求,这个库完全够用。

2.2 为什么在 VS2015 下编译会跟网上教程不一样

这里要讲一个很多人一开始没搞明白的事:Qt 有两套编译器体系。一套是 MinGW(Windows 上的 GCC),一套是 MSVC(微软的编译器)。你用 Qt Creator 默认装的往往是 MinGW 版本,而 VS2015 用的是 MSVC 2015(也就是 MSVC 14.0)。这两套编译出来的库,二进制是不兼容的。

网上大量 QtXlsxWriter 的编译教程,默认你用的是 MinGW,命令是mingw32-make。但你在 VS2015 环境下,必须用nmake,而且你的 Qt 必须是MSVC 版本的 Qt,不能是 MinGW 版本的。如果你装的 Qt 是 MinGW 版,那在 VS2015 里根本没法用,得重新下载对应 MSVC 2015 的 Qt 版本。这是第一个大坑,很多人卡在这里半天找不到原因。

2.3 需要提前准备好的东西

在正式开始之前,确认下面这几样东西都到位了:

  • Visual Studio 2015:安装时记得勾选 C++ 相关的组件,确保nmake可用。
  • Qt for Windows (MSVC 2015 版本):注意版本号要匹配,比如 Qt 5.9.x 或 5.12.x 的 MSVC2015 32/64 位版本。装完之后,qmake.exe和nmake都要能在命令行里调用。
  • QtXlsxWriter 源码:从代码托管平台拉一份下来,解压到没有中文、没有空格的路径下,比如D:\libs\QtXlsxWriter。
  • 一个命令行环境:推荐用"VS2015 开发人员命令提示符",或者用 Qt 自带的命令行工具,关键是环境变量要配好。

提示:路径里千万不要有中文和空格。我见过有人把源码放在"我的文档\新建文件夹"下面,结果 qmake 生成 Makefile 的时候路径解析直接崩了,报的错还特别隐晦,查半天查不出来。

3. 环境变量配置:这一步错了后面全白搭

3.1 把 qmake 和 nmake 都挂到 PATH 上

编译 QtXlsxWriter 的核心命令就两条:qmake生成 Makefile,nmake执行编译。但前提是这两个命令在命令行里能直接找到。

nmake来自 VS2015,最省事的办法是直接用开始菜单里的"VS2015 x64 本机工具命令提示符"(或者 x86 版本,取决于你的 Qt 是 32 位还是 64 位)。这个命令行窗口打开的时候,VS 相关的环境变量已经自动配好了,nmake直接可用。

qmake来自 Qt 安装目录,比如D:\Qt\Qt5.9.9\5.9.9\msvc2015_64\bin。你需要把这个bin目录加到系统 PATH 里,或者临时在当前命令行里set PATH=%PATH%;D:\Qt\Qt5.9.9\5.9.9\msvc2015_64\bin。

验证一下:在命令行里敲qmake -v,如果输出了 Qt 的版本信息,说明配好了。再敲nmake /?,如果出来一堆帮助信息,说明 nmake 也没问题。

3.2 32 位还是 64 位,必须跟 Qt 版本对齐

这是个特别容易翻车的点。你的 Qt 是msvc2015_64,那你就必须用x64 本机工具命令提示符,编译出来的库才是 64 位的。如果你用 x86 的命令行去编译 64 位的 Qt,qmake 阶段可能就报错了,或者编译出来的库跟你的工程位数对不上,链接的时候一堆符号找不到。

判断方法很简单:看你的 Qt 安装目录名,带_64的就是 64 位,不带的就是 32 位。然后选对应的命令行工具。我个人的习惯是,在开始菜单里把"VS2015 x64 本机工具命令提示符"固定到任务栏,省得每次找。

3.3 一个容易被忽略的细节:环境变量污染

有时候你机器上装了多个版本的 Qt,或者之前配过别的编译环境,PATH 里可能混着好几个qmake。这时候qmake -v输出的版本可能不是你想要的。解决办法是在命令行里用绝对路径调用 qmake,比如:

D:\Qt\Qt5.9.9\5.9.9\msvc2015_64\bin\qmake.exe -v

这样能确保用的是你指定的那个版本。编译的时候也用绝对路径,避免歧义。

4. 编译 QtXlsxWriter 的完整操作链路

4.1 进入源码目录,先看一眼结构

解压完 QtXlsxWriter 源码后,进去看一眼目录结构。通常根目录下会有一个QtXlsxWriter.pro文件,这是 qmake 的工程文件。还有一个src目录,里面是库的源代码。有的版本还会带examples目录,里面是示例工程。

我们要编译的是库本身,所以关注根目录的.pro文件就行。在命令行里cd到源码根目录:

cd /d D:\libs\QtXlsxWriter

注意用/d参数,因为要跨盘符切换。这一步没什么技术含量,但路径一定要对。

4.2 执行 qmake 生成 Makefile

在源码根目录下执行:

qmake QtXlsxWriter.pro

如果一切正常,你会看到目录下多出来一个Makefile(或者Makefile.Debug和Makefile.Release)。这一步 qmake 做的事情,是读取.pro文件里的配置,结合当前 Qt 环境,生成 nmake 能看懂的 Makefile。

这一步常见的报错有几种:

  • qmake: command not found:PATH 没配好,回去检查 3.1。
  • Project ERROR: Unknown module(s) in QT: ...:.pro文件里引用了某个 Qt 模块,但你的 Qt 安装里没有。QtXlsxWriter 一般只依赖core和gui,如果报这个错,可能是 Qt 装得不全。
  • 路径相关报错:源码路径里有中文或空格,换路径。

4.3 执行 nmake 开始编译

Makefile 生成之后,直接:

nmake

或者分开编译 debug 和 release:

nmake debug nmake release

编译过程会持续几分钟,取决于机器性能。你会看到一堆.cpp文件被编译成.obj,最后链接成.dll和.lib。

这里有个经验:第一次编译建议只编 release,因为 debug 版本体积大、编译慢,而且如果你只是要验证能不能用,release 足够了。等确认流程跑通,再补 debug 版本。

4.4 编译产物在哪里,怎么确认成功了

编译完成后,产物通常在源码目录下的lib文件夹里(具体位置看.pro文件的配置)。你会看到类似这样的文件:

文件类型文件名示例用途
动态库QtXlsxWriter.dll运行时需要,跟 exe 放一起或放系统路径
导入库QtXlsxWriter.lib链接时需要,告诉链接器 dll 里有哪些符号
静态库(如果配了)QtXlsxWriter.lib (较大)静态链接时用

如果lib目录下这几个文件都在,而且大小正常(dll 一般几百 KB 到 1MB 左右),那基本就成功了。如果只有.obj没有.lib,说明链接阶段出问题了,往上翻编译日志找error。

5. 把编译好的库塞进 VS2015 的 Qt 工程

5.1 头文件、lib、dll 三件套怎么放

编译出来只是第一步,真正要用起来,得让 VS2015 的工程能找到这三样东西:

  • 头文件:QtXlsxWriter 源码里的src目录下有一堆.h文件,比如xlsxdocument.h、xlsxworksheet.h。你需要把src目录的路径告诉编译器。
  • 导入库(.lib):链接阶段需要,告诉链接器去哪个 dll 里找符号。
  • 动态库(.dll):运行阶段需要,程序启动时加载。

我的习惯是在工程目录下建一个third_party文件夹,里面分include、lib、bin三个子目录,分别放头文件、lib、dll。这样工程自包含,换台机器也能编译。

5.2 在 VS2015 工程属性里配置包含目录和库目录

右键工程 -> 属性,注意配置和平台要选对(Debug/Release、x64/Win32):

  • C/C++ -> 常规 -> 附加包含目录:加上third_party\include的路径。
  • 链接器 -> 常规 -> 附加库目录:加上third_party\lib的路径。
  • 链接器 -> 输入 -> 附加依赖项:加上QtXlsxWriter.lib。

这三步做完,编译和链接阶段就能找到库了。但运行时还需要 dll,最简单的办法是把QtXlsxWriter.dll复制到你的 exe 输出目录下。

5.3 一个真实的链接报错案例

我第一次配的时候,编译通过了,但链接报了一堆unresolved external symbol,全是QtXlsx::Document::...之类的。当时第一反应是库没链上,检查了附加依赖项,QtXlsxWriter.lib确实加了。

后来发现问题出在位数不匹配。我的 Qt 是 64 位的,但编译 QtXlsxWriter 的时候用的是 x86 的命令行,编出来的是 32 位库。32 位的 lib 拿到 64 位工程里链接,符号当然对不上。重新用 x64 命令行编译一遍,问题解决。

这个坑的教训是:编译库的位数、Qt 的位数、VS 工程的位数,三者必须完全一致。任何一个不一致,都会在链接或运行阶段出问题。

6. 写一段最小代码验证库能不能用

6.1 一个最简单的导出示例

库配好之后,别急着往正式项目里塞,先写个最小 demo 验证一下。下面这段代码创建一个 xlsx 文件,往第一个单元格写点东西:

#include <QCoreApplication> #include "xlsxdocument.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QXlsx::Document xlsx; xlsx.write("A1", "Hello QtXlsxWriter"); xlsx.write("A2", 12345); xlsx.write("A3", QDateTime::currentDateTime()); xlsx.saveAs("test_output.xlsx"); return 0; }

编译运行,如果当前目录下生成了test_output.xlsx,用 Excel 或 WPS 打开能看到内容,说明整条链路通了。

6.2 运行时报错"找不到 QtXlsxWriter.dll"怎么办

这是最常见的问题。程序编译链接都过了,一运行就弹窗说找不到 dll。原因很简单:exe 运行时会在当前目录、系统目录、PATH 里找 dll,你的QtXlsxWriter.dll不在这些地方。

解决办法有三个,按推荐程度排序:

  1. 把 dll 复制到 exe 所在目录(最省事,推荐)。
  2. 把 dll 所在目录加到系统 PATH(不推荐,污染环境)。
  3. 用 Qt 的windeployqt工具自动收集依赖(适合发布时用)。

我一般用第一种,在 VS 工程里配一个生成后事件,自动把 dll 拷过去:

xcopy /y "$(SolutionDir)third_party\bin\QtXlsxWriter.dll" "$(OutDir)"

这样每次编译完 dll 自动就位,省得手动拷。

6.3 中文乱码问题的排查

如果你的导出内容里有中文,打开 Excel 发现是乱码,那多半是编码问题。QtXlsxWriter 内部用的是 UTF-8,但你的源码文件如果是 GBK 编码,字符串字面量传进去就可能出问题。

解决办法:确保源码文件保存为 UTF-8(带 BOM 或不带都行,VS2015 建议带 BOM),或者在写字符串的时候显式转换:

xlsx.write("A1", QString::fromUtf8("中文内容"));

实测下来,只要源码是 UTF-8,直接写中文字面量一般没问题。如果还是乱码,检查一下是不是用了const char*而不是QString。

7. 踩坑复盘:那些让我多花两小时的细节

7.1 源码版本和 Qt 版本的兼容性

QtXlsxWriter 的不同版本对 Qt 版本有要求。老版本的库可能用了 Qt 5.0 时代的 API,在新版 Qt 上编译会报废弃警告甚至错误。反过来,新版本的库可能用了 Qt 5.15 才有的特性,在 Qt 5.9 上编译不过。

我遇到过一次,拉的最新源码在 Qt 5.9 上编译报错,提示某个QStringView相关的 API 不存在。后来换了一个稍早的 tag 才编过。所以拉源码的时候,留意一下 release 说明或者 commit 记录,选一个跟你 Qt 版本匹配的。

7.2 nmake 的并行编译参数

nmake默认是单线程编译,源码文件多的时候会比较慢。可以加/J参数开多核:

nmake /J

不过要注意,某些老版本的 nmake 对/J支持不好,可能出现编译顺序问题。如果开了/J之后报奇怪的错,去掉这个参数再试。

7.3 清理重编的正确姿势

编译过程中如果中断了,或者改了配置想重来,别直接删 Makefile 就完事。正确的清理命令是:

nmake clean nmake distclean

clean删掉编译产物,distclean连 Makefile 一起删。然后再重新qmake+nmake。直接手动删文件有时候会漏掉一些中间产物,导致下次编译出现莫名其妙的错误。

7.4 关于 debug 和 release 混用

VS2015 工程默认有 Debug 和 Release 两种配置。如果你编译 QtXlsxWriter 只编了 release 版本,那你的工程在 Debug 配置下链接就会失败,因为找不到 debug 版的 lib。

解决办法要么是补编 debug 版本,要么是在工程里把 Debug 配置也指向 release 的 lib(不推荐,调试时可能出问题)。最稳妥的是两个版本都编,分别放到lib\debug和lib\release目录,工程属性里按配置分别指向。

8. 几个提升效率的实操建议

8.1 把编译过程脚本化

如果你经常需要在不同机器上配这个库,建议把编译命令写成一个.bat脚本:

@echo off call "D:\Qt\Qt5.9.9\5.9.9\msvc2015_64\bin\qmake.exe" QtXlsxWriter.pro nmake nmake clean

注意第一行的call,因为 qmake 本身也是个批处理,不加call的话执行完 qmake 脚本就退出了,后面的 nmake 不会执行。这个细节坑过我一次。

8.2 用 .pri 文件简化工程配置

QtXlsxWriter 源码里通常带一个.pri文件,里面封装了头文件路径、库路径这些配置。如果你用的是 qmake 工程(.pro),可以直接include()这个 pri 文件,省得手动配一堆路径。但 VS2015 的工程是.vcxproj,用不了 pri,还是得手动配属性。这也是为什么 VS 环境下配第三方库比 Qt Creator 麻烦的原因之一。

8.3 关于静态链接的取舍

QtXlsxWriter 也支持静态编译,就是把库直接编进你的 exe,不需要额外的 dll。好处是发布简单,坏处是 exe 体积变大,而且如果多个模块都用这个库,可能产生符号冲突。

我的建议是:小项目、发布要求简单,用静态;大项目、模块多,用动态。动态链接虽然多一个 dll,但更新库的时候不用重新编译整个工程,维护上更灵活。

8.4 版本管理的一点心得

第三方库的源码和编译产物,建议纳入版本管理(比如 Git)。但注意,编译产物(.obj、.dll、.lib)体积大且跟环境相关,一般用.gitignore排除掉,只保留源码和编译脚本。这样换机器的时候,拉源码、跑脚本、重新编译,流程清晰可控。

9. 最后聊几句实际使用中的体会

QtXlsxWriter 这个库,功能上不算特别强大,复杂的 Excel 操作(比如图表、数据透视表)它做不了。但对于"把数据导出成带格式的 Excel"这个最常见的需求,它足够稳定,而且不依赖 Office,部署省心。

我在实际项目里用它做过报表导出,几千行数据、带单元格格式和合并,生成速度很快,打开也没问题。唯一需要注意的是,写入大量数据时,尽量用批量写入的方式,比如先把数据组织成二维数组,再循环写入,比一个个单元格单独写要快不少。另外,saveAs的时候如果目标文件被 Excel 占用,会保存失败,记得在代码里处理这个异常情况,给用户一个友好的提示。

编译这个库本身,说难不难,说简单也不简单。核心就是三件事:环境变量配对、位数对齐、路径干净。这三样搞定了,剩下的就是按部就班执行命令。第一次配可能会花点时间,但配通一次之后,后面再遇到就是十分钟的事。希望这篇东西能帮你少走点弯路,把时间花在真正的业务逻辑上,而不是跟编译环境较劲。

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

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

立即咨询