简介:针对Windows 10环境下将Cutelyst框架与Grantlee视图引擎整合的需求,这份资源提供了使用Qt 5.15.2编译完成的Cutelyst动态库及配套文件。Cutelyst是一个基于C++的高性能Web框架,Grantlee则提供了灵活的模板渲染能力,两者结合适合希望构建服务端渲染应用、又熟悉Qt生态的开发者使用。压缩包共一百七十二个文件,其中八十七个头文件用于声明对外接口,二十三个动态链接库与十四个静态库分别满足运行时加载和链接需要,十三个PC文件供集成环境识别依赖,另有CMake配置和工具支持项目快捷引入。整个压缩包仅一点三一兆字节,非常轻量。目前已有两百七十四人学习下载,并附有博客链接可供查阅编译细节与排错思路。借助这套文件,开发者可以直接获得编译好的动态库,省去从源码构建的繁琐流程,同时也能了解Qt5.15.2下Cutelyst与Grantlee视图的集成方式,从而快速开展Web功能开发或自研框架验证。
1. 为什么非要在 Win10 上手工编译带 Grantlee 视图的 Cutelyst:先看清三个依赖
Cutelyst 是一个基于 Qt 的 C++ Web 框架,核心只负责路由、插件和请求生命周期,模板渲染能力由视图插件提供。Grantlee 是 Qt 生态里的模板引擎,语法接近 Django 模板,用{{ }}和{% if %}这类标记把数据渲染成 HTML。标题里这串组合下来,目标是拿到能在 Windows 上运行、并加载 Grantlee 视图的 Cutelyst 动态库。官方对 Windows 的支持大多是“能编但没人给你发二进制”,所以整个过程本质是工具链协调问题,Qt 5.15.2 装好只是开始,真正耗时间的是把 MinGW、Grantlee、CMake 三者的路径和 ABI 对齐。我观察下来,让新手翻车的点不在 Cutelyst 源码,而在依赖搜索顺序。这篇需要解决三件事:选哪套工具链、Grantlee 怎么编出来、Cutelyst 的 CMake 参数怎么给。适合想在 Windows 上用 Qt 全家桶做 Web 渲染、又不想被迫换 Linux 的 C++ 团队参考。
2. 环境与依赖:Win10 上把 Qt 5.15.2、MinGW 和 Grantlee 先摆平
2.1 为什么选择 Qt 5.15.2 自带的 MinGW 8.1.0,而不是 MSVC
Grantlee 5.3 的 CMake 目标明确指向 Qt5,对 MinGW 支持最完整。用 MSVC 不是编不了,而是要给 Cutelyst 处理 GNU 风格导入库命名.dll.a,还得给 Grantlee 额外指定运行时库选项,这在 Windows 上属于给自己加戏。vcpkg 虽然能装 Grantlee,但它装出来的库通常和 Cutelyst 编译时用的 ABI 不一致,排查起来更累。所以常见做法是用 Qt 5.15.2 安装包自带的 MinGW 8.1.0 整套工具链,Qt 库和编译器版本完全配对,从源头减少一个变量。
| 工具链 | ABI 一致性 | 改动量 | 适合场景 |
|---|---|---|---|
| Qt 自带 MinGW 8.1.0 | 高,与 Qt 库同源 | 小,开箱即用 | 本主题首选 |
| MSVC 2019 | 中,需处理导入库与运行时库 | 大,CMake 选项要多调 | 团队已锁死 MSVC 环境 |
| vcpkg 预编译 Grantlee | 不确定,取决于 triplet | 中,依赖路径不可控 | 只在 Linux 上跑通过 |
我一般会把 CMake、MinGW 和 Qt 全放在同一套命令环境里执行,而不是在普通 cmd 里手动拼 PATH。原因在第 4 章的坑里会具体展开,这里先记住结论:Windows 上编译 Qt 系的第三方库,统一工具链比什么都重要。
2.2 Qt 5.15.2 下载安装:把 Qt 库、MinGW 和 CMake 一次性勾选齐
标题写的是 Qt 5.15.2,这个版本值得单独说一句:它是 Qt 官方最后一个提供开源离线安装包的版本,之后开源用户只能走在线安装器。在 Win10 上下载安装时,组件别只勾 Qt 本体,下面这几个都要选上,否则后面少工具又得回安装器补:
- Qt 5.15.2 > MinGW 8.1.0 64-bit:Qt 库本体,路径通常是
C:\Qt\5.15.2\mingw81_64; - Developer and Designer Tools > MinGW 8.1.0 64-bit:编译器本体,路径通常是
C:\Qt\Tools\mingw810_64; - Developer and Designer Tools > CMake:Qt 安装器自带的 CMake,省得再去配系统 PATH。
装完之后不要直接双击普通 cmd 编译,而是从开始菜单启动 “Qt 5.15.2 (MinGW 8.1.0 64-bit)” 命令提示符。这个入口已经把 qmake、g++、cmake 的 PATH 配好。进去后先确认环境:
qmake -v g++ --version cmake --version where qmake where g++qmake 的输出里会给出 Qt 库的确切位置,只要看到 “Using Qt version 5.15.2 in C:/Qt/5.15.2/mingw81_64/lib” 就说明 PATH 干净。重点解释 where 命令:它用来查 qmake 和 g++ 到底命中的是哪个目录。很多人编译到一半报版本冲突,根因就是 PATH 里先命中了其他软件自带的 Qt 或编译器。如果 where 返回的第一条不是预期路径,那就别继续了,先处理环境再往下走。
目录规划我会固定成四块,方便后面 CMake 引用:源码放D:\src,第三方安装放D:\3rd,编译中间产物放D:\src下的 build 目录,最后 Cutelyst 安装到D:\cutelyst-install。这样即使中途把 build 目录整个删掉重来,也不需要动源码和 Qt 安装。
2.3 Grantlee 为什么要单独编译,而不是让 CMake 自动拉
Cutelyst 对 Grantlee 视图的处理是把它作为视图插件,编译期依赖 Grantlee5 的 CMake 包,也就是Grantlee5Config.cmake。CMake 不会像 npm 那样自动去拉依赖,它只会按CMAKE_PREFIX_PATH在给定目录里找find_package需要的配置文件。所以 Grantlee 必须先被编译并安装到一个已知目录,Cutelyst 的配置阶段才能找到它。
为什么不直接用 vcpkg?vcpkg 装出来的 Grantlee 用的是它自己那套 triplet,和当前编译 Cutelyst 的 MinGW 不一定匹配。更隐蔽的问题是 vcpkg 默认把 DLL 和导入库放在同一层目录,而 Cutelyst 的视图插件链接 Grantlee 时按头文件和库文件的分类去查找,路径一旦对不上就会出现“头文件找到了、库找不到”这种奇怪状态。自己编 Grantlee 表面上多花十分钟,但后面 Cutelyst 的 CMake 配置是一路绿灯的。编译 Grantlee 只需要注意它依赖 Qt5Core 和 Qt5Gui,不需要额外装第三方库,这点在 Windows 上比较省心。
装完之后顺手检查安装目录结构:D:\3rd\grantlee下出现bin、include、lib三个目录,include里能看到 grantlee 头文件,lib\cmake\Grantlee5下有Grantlee5Config.cmake,看到这些就算装成功。后面 Cutelyst 找不到 Grantlee 时,回来检查这几项就够了。
3. 用 Qt 命令行编译 Grantlee 与 Cutelyst 动态库:CMake 配置与命令
3.1 先编译 Grantlee:最小命令与三个常见误用
拿到 Grantlee 源码(以 5.3.1 分支为准,这个版本对 Qt 5.15 兼容性最好)后,在 Qt 的 MinGW 命令提示符里执行:
cmake -S D:\src\grantlee -B D:\src\grantlee-build -G "MinGW Makefiles" ^ -DCMAKE_BUILD_TYPE=Release ^ -DCMAKE_PREFIX_PATH=C:\Qt\5.15.2\mingw81_64 ^ -DCMAKE_INSTALL_PREFIX=D:\3rd\grantlee ^ -DBUILD_TESTS=OFF cmake --build D:\src\grantlee-build -j8 cmake --install D:\src\grantlee-build这段命令的逻辑是:用-S和-B分离源码和构建目录,-G明确指定 MinGW Makefiles 生成器,避免 CMake 在 Windows 上默认生成 Visual Studio 工程;CMAKE_PREFIX_PATH指向 Qt 5.15.2 的 mingw81_64 目录,Grantlee 的 CMake 靠它找到 Qt5Core 和 Qt5Gui;CMAKE_INSTALL_PREFIX决定最终安装位置,安装产物里最关键的是lib\cmake\Grantlee5\Grantlee5Config.cmake,这是后面 Cutelyst find_package 的依据。
参数说明:
-DCMAKE_BUILD_TYPE=Release:Cutelyst 是发布用途,建议从头到尾保持 Release,避免 Debug 和 Release 混用后 Qt 运行时库不同导致崩溃;-DBUILD_TESTS=OFF:Grantlee 的测试套件会拉一批 Qt5Test 依赖,在 Windows 上编译时间明显变长,关掉不影响使用;-j8:按机器逻辑核心数调整,8 核用 8,16 核可以给 16,给太少会白白等编译。
三个常见误用值得提前说。第一,不加-G参数,CMake 会优先探测 Visual Studio,生成一堆.vcxproj,在 MinGW 命令提示符里根本没法用,这是个非常容易踩的坑;第二,CMAKE_PREFIX_PATH不要写成 Qt 的 lib 或 bin 子目录,要写到包含 lib 和 include 的上层目录,C:\Qt\5.15.2\mingw81_64才是正确层级;第三,千万别跳过 install 直接用 build 目录里的库,Cutelyst 需要的是带 CMake 配置文件的安装树,而不是散落在 build 下的中间产物。
3.2 编译 Cutelyst 动态库:用 -DBUILD_VIEWS_GRANTLEE=ON 打开 Grantlee 视图
Grantlee 装好后,进入 Cutelyst 编译。源码拉取时用git clone --recursive,因为 Cutelyst 带了一些第三方子模块,漏掉会导致 CMake 配置阶段直接报缺文件。命令如下:
cmake -S D:\src\cutelyst -B D:\src\cutelyst-build -G "MinGW Makefiles" ^ -DCMAKE_BUILD_TYPE=Release ^ -DCMAKE_PREFIX_PATH="C:\Qt\5.15.2\mingw81_64;D:\3rd\grantlee" ^ -DCMAKE_INSTALL_PREFIX=D:\cutelyst-install ^ -DBUILD_PLUGINS=ON ^ -DBUILD_VIEWS_GRANTLEE=ON ^ -DBUILD_TESTS=OFF ^ -DCUTELYST_USE_URIPARSER=OFF cmake --build D:\src\cutelyst-build -j8 cmake --install D:\src\cutelyst-build这里CMAKE_PREFIX_PATH同时给了两个路径,用分号分隔,这就是为什么必须用引号包起来:在 cmd 里分号本身不会被当作分隔符,但如果路径带空格或者被 shell 二次解析,很容易出现只命中 Qt、漏掉 Grantlee 的情况。CMake 解析-D参数时会把分号视为列表分隔,引号保证整段路径作为一个参数传进去。
各选项的职责如下。
| 参数 | 作用 | 踩坑提醒 |
|---|---|---|
-DBUILD_PLUGINS=ON | 编译 Cutelyst 基础插件 | 只想要 Grantlee 也必须开,部分版本视图插件依赖这个开关 |
-DBUILD_VIEWS_GRANTLEE=ON | 生成 CutelystQt5ViewGrantlee.dll 视图插件 | 选项名不同 tag 略有差异,配置后可查缓存确认 |
-DCUTELYST_USE_URIPARSER=OFF | 使用源码内置的 uriparser | 不要设成 SYSTEM,Windows 上很难装齐全 |
-DCMAKE_PREFIX_PATH | 指定 Qt 和 Grantlee 的搜索根 | 分号连接,必须加引号 |
configure 完成后,可以用一条命令确认视图插件开关确实打开了:
cmake -LA D:\src\cutelyst-build | findstr /i "GRANTLEE VIEW"如果输出里没有BUILD_VIEWS_GRANTLEE相关项,说明当前源码版本的选项名不一样。打开根目录的 CMakeLists.txt 搜索 grantlee 就能看到准确名字,不要对着老博客硬套。这个排查动作在换版本、换 tag 时尤其有用,Cutelyst 的 CMake 选项在不同发行版里确实调整过。
3.3 安装产物:Cutelyst 动态库和 Grantlee 视图插件分别在哪
编译加安装结束后,D:\cutelyst-install下的目录结构大致如下:
| 文件或目录 | 作用 |
|---|---|
bin\Cutelyst.dll | Cutelyst 核心动态库,Web 框架本体 |
bin\CutelystQt5ViewGrantlee.dll | Grantlee 视图动态库,部分版本装到lib\cutelyst\plugins\views下 |
include\Cutelyst\ | 编译期头文件 |
lib\cmake\Cutelyst\ | CMake 配置包,供其他 Qt 工程 find_package 使用 |
视图插件的准确目录以 install 命令的实际输出为准,方法是在安装日志里搜 Grantlee.dll,看它被复制到哪个目录就用哪个。这里想强调的是,Cutelyst 的动态库是分层的:核心库只负责路由和上下文,Grantlee 视图作为独立 DLL 被加载。所以后续发布应用时不能只复制 Cutelyst.dll,还要把视图插件、Grantlee 的 DLL 一并带上,缺一不可。
拿到 DLL 之后,我习惯用 objdump 直接看它的导入表,快速确认视图插件依赖了哪些库:
objdump -p CutelystQt5ViewGrantlee.dll | findstr "DLL Name"输出里应该能看到grantlee_core.dll(MinGW 下可能带 lib 前缀)和libQt5Core.dll等。如果导入表里缺了某个库,趁早回去查路径,等运行时再发现问题会更痛苦。
4. 编译避坑:ABI 混用、库找不到和运行时 DLL 加载失败
这一章是标题里那台 Win10 最容易绊倒人的地方,按出现频率从高到低写。每一条都是实际编译时见过的真实现象,直接给解决路径。
4.1 fatal: cannot mix incompatible Qt library (version 0x50601) with this library
现象:编译 Cutelyst 或 Grantlee 时,编译器报出fatal: cannot mix incompatible Qt library (version 0x50601) with this library这类错误,版本号后面串起来的值让人一头雾水。0x50601 对应的其实是 Qt 5.6.1,这个报错说明当前进程里混入了一个老版本 Qt 的某个库。
原因:PATH 里存在其他软件带进来的 Qt 5.6 或更早版本的 bin 目录,比如某些 IDE、Python 环境、桌面软件捆绑的 Qt。编译器使用 Qt 5.15.2 的头文件,但运行时优先加载了旧版本的 DLL,版本检查直接失败。
解决:先执行where qmake和where g++,如果返回路径里有 Qt 之外的内容,把真正需要的 Qt 和 MinGW 路径放到 PATH 最前面。最彻底的做法是关闭当前 cmd,重新通过开始菜单打开 “Qt 5.15.2 (MinGW 8.1.0 64-bit)” 命令提示符,这个入口配的 PATH 顺序是可控的。这个问题不玄学,本质就是优先级问题,谁在前谁生效。
4.2 CMake 提示 Could NOT find Grantlee,明明已经编译过了
现象:Cutelyst 的 configure 阶段报Could NOT find Grantlee (missing: Grantlee_DIR),但 3.1 节的 Grantlee 明明编译成功了。
原因分两种。一种是 Grantlee 的 install 步骤没执行,编译产物停留在 build 目录,没有生成Grantlee5Config.cmake,自然什么都找不到;另一种是CMAKE_PREFIX_PATH里的分号被 shell 处理掉,CMake 实际只搜索了 Qt 目录。还有一种隐蔽情况:Grantlee 安装目录里生成的是Grantlee5Config.cmake,但 Cutelyst 某个版本要求的是GrantleeConfig.cmake,两者名字不匹配。
解决:先去D:\3rd\grantlee\lib\cmake下看有没有 Grantlee5 或 Grantlee 开头的目录。没有就回到 grantlee-build 重新执行cmake --install D:\src\grantlee-build,确认输出里出现 Install 字样。有的话,在 Cutelyst 缓存里手动指定:打开D:\src\cutelyst-build\CMakeCache.txt,搜索Grantlee_DIR,把它改成指向包含 Config.cmake 的那个目录,然后重新 configure。改缓存是最后手段,但确实有效。
4.3 链接期报 undefined reference to uriparser_xxx
现象:Cutelyst 编译到链接阶段,报出一大片undefined reference to uriparser_parse_uri之类的符号缺失,不是一两个,是几十个连在一起。
原因:Cutelyst 核心库依赖 uriparser 做 URI 解析。Windows 上最常见的翻车点是 CMake 选择了系统 uriparser,而系统里没有对应 MinGW ABI 的导入库;或者源码里的内置 uriparser 没有参与构建。
解决:在 configure 里显式指定-DCUTELYST_USE_URIPARSER=OFF,让 Cutelyst 使用自带的 uriparser 源码,这是 Windows 上最省事的路径。如果源码里没有明确叫这个名字的选项,就搜 CMakeLists.txt 里的 uri 关键词,找到对应开关再传。不要试图自己下载编译 uriparser 再手动加库,路径和 ABI 对不齐时,这次省下的时间会在下次吐出来。
4.4 运行期报 qt.qpa.plugin: could not find the qt platform plugin,或者无法定位程序输入点
现象:Cutelyst 和视图插件都编译成功后,运行程序却立刻崩溃。轻则提示无法定位程序输入点 grantlee_something.dll,重则直接报 Qt 平台插件找不到,连程序都没起来。
原因:视图插件 DLL 运行时会在进程的 DLL 搜索路径里找 Grantlee 的 DLL。只要 exe 同级目录或 PATH 里没有C:\Qt\5.15.2\mingw81_64\bin和D:\3rd\grantlee\bin,加载就会失败。平台插件找不到则是 Qt 的 plugins 目录没有正确暴露给 qt.conf 或环境变量。
解决:临时验证阶段,在 cmd 里把路径拼齐再启动程序:
set PATH=C:\Qt\5.15.2\mingw81_64\bin;D:\3rd\grantlee\bin;D:\cutelyst-install\bin;%PATH% myapp.exe正式发布阶段不要依赖 PATH,用 windeployqt 处理 Qt 库,再把 Cutelyst.dll、CutelystQt5ViewGrantlee.dll、Grantlee 的 DLL 全部复制到 exe 同级目录。这一步是把 Qt 库和框架库分开整理,整理完再用依赖检查工具过一遍。
4.5 混用 MSVC 与 MinGW 产物,链接器一顿报错
现象:链接时报一堆undefined reference to std::__cxx11::basic_string或者找不到__imp_开头的符号,看起来像是不是同一个 C++ 编译器编出来的。
原因:Grantlee 用 MSVC 编、Cutelyst 用 MinGW 编,或者反过来。两个编译器对标准库和导出符号的修饰规则不同,MinGW 的导出符号在 MSVC 库里找不到对应实现,这是 Windows 上最磨人的 ABI 问题,比路径问题难查得多。
解决:整个过程只用一套工具链。从开始菜单启动的 “Qt 5.15.2 (MinGW 8.1.0 64-bit)” 环境里,qmake、g++、mingw32-make、cmake 全部来自 Qt 安装目录,是同一套组合。不要在 Qt 命令行里拿到一半路径后,又去手动调用 Visual Studio 的库。我现在每次编第三方库前都会先确认 qmake 路径,这个本能在 Windows 上省了大量无谓的返工。
5. 验证与进阶:让 Grantlee 视图真正被 Cutelyst 加载
编译成功不等于视图能渲染,最后一步是验证动态库真的被 Cutelyst 加载了。我会先用最小的 Cutelyst 应用跑一次:在应用入口注册 Grantlee 视图,然后在配置里指向模板目录。
[View-Grantlee] GRANTLEE_INCLUDE_PATHS=C:/app/templates GRANTLEE_PREFERRED_LOADER=FileSystemLoader GRANTLEE_CACHE=OffGRANTLEE_INCLUDE_PATHS指向模板文件所在目录,FileSystemLoader表示从文件系统读取模板而不是从资源文件读,GRANTLEE_CACHE=Off让改模板后重启即生效,调试期必须关缓存。启动后请求一个返回模板的路由,如果页面里出现{{ }}里的变量值,说明视图插件加载成功。如果页面是模板原始文本,问题基本出在视图没注册或者模板路径不对。
进阶一点的做法是写一条日志来确认视图注册:在 Cutelyst 的启动日志里搜索 Grantlee,看到类似 “Loaded view Grantlee” 的输出就放心了。我现在每次换版本重新编译,拿到 DLL 后的第一件事不是跑业务代码,而是用最小工程验证视图加载,再把整个 DLL 集合纳入构建脚本。这套流程跑顺之后,后续换 Grantlee 版本只需要重新编译两个库,其余路径和配置完全不动。
这条链路里我最深的体会是:Windows 上编译 C++ 框架,大量问题不是代码本身,而是搜索路径和 ABI 的优先级。先确认 PATH 再动手,是少走弯路的关键,希望帮到你。
本文还有配套的精品资源,点击获取