ARTICLE DETAIL

资讯详情

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

Windows下编译带Grantlee的Cutelyst动态库:Qt 5.15.2与CMake实战

Windows下编译带Grantlee的Cutelyst动态库:Qt 5.15.2与CMake实战 简介面向在Windows 10下使用Qt 5.15.2编译Cutelyst框架并集成Grantlee视图的开发者这套编译产物直接解决了Cutelyst动态库在Windows环境下的构建与配置难题省去从源码编译的踩坑过程。压缩包共172个文件大小仅1.31MB核心包含87个h头文件、23个dll动态库、14个lib导入库、13个pc配置文件及5个cmake配置模块其中头文件覆盖请求、会话、分发器、控制器、上下文等核心APIdll和lib可供链接使用pc和cmake文件则方便与Qt工程集成。已有274人学习下载。资源目录结构清晰保留了Application、ActionChain、Grantlee引擎等框架组件并附带Plugin、View等扩展点便于中高级Qt开发者按需查阅或二次开发。如需基于Cutelyst快速搭建Web应用并采用Grantlee模板视图这套编译产物可视为较为完整的依赖基础与参考实现。1. 为什么非要自己编译带 Grantlee 的 Cutelystwin10 Qt 5.15.2 动态库只能自己搓在 Qt 生态里想做 Web 后端Cutelyst 几乎是唯一把 Qt 信号槽、元对象系统带进 HTTP 层的 C 框架这一点是别的框架替代不了的。但现实是Cutelyst 官方在 Windows 上的预编译动态库基本可遇不可求尤其是带 Grantlee 模板视图的版本——Grantlee 之于 Cutelyst就像 JSP 之于 Java没有它视图层只能靠QString手动拼 HTML维护成本直接起飞。我当时在 win10 Qt 5.15.2 下把带 Grantlee 视图的 Cutelyst 动态库从源码完整编译了一遍这篇文章就是那次的完整记录从依赖安装到 CMake 参数再到最后跑通模板渲染适合想在 Windows 上用 Qt 写 Web 应用、又不想在视图层被卡住的开发者。2. 编译前置Qt 5.15.2 组件、Grantlee 源码与 CMake 工具链2.1 Qt 5.15.2 安装在线安装工具里勾对三个东西先说 Qt 本身。在线安装工具里选 Qt 5.15.2 后会看到一大堆组件MSVC 2019 64-bit、MinGW 64-bit、Android、Sources、WebAssembly 铺满整个列表。这里我的原则是只用与 MSVC 2019 配套的msvc2019_64其他的一概不勾。sources 组件会有用但能用在线安装工具装的依赖尽量装省得后面补find_package时缺模块。Cutelyst 在 Windows 的测试基本都是在 MSVC 工具链下跑的你用 MinGW 去编 Cutelyst 不是不行但 Grantlee 的官方分支对 MinGW 的适配明显没有 MSVC 上心DLL 导出符号和异常处理都可能出幺蛾子。所以编译器这条线我建议直接锁死 MSVC 2019。Qt 库安装路径默认落在C:/Qt/5.15.2/msvc2019_64这个路径记下来后面所有 CMake 配置都要引用它。还有个细节容易被忽略Qt 5.15.2 在线安装工具本身不会帮你配环境变量qmake和 CMake 的Qt5Config.cmake都是靠路径查找的。你不需要把 Qt 的bin目录加进 PATH 也能编译但运行时程序找 Qt DLL 会依赖这个 PATH。我的习惯是安装完先不加全局 PATH后面具体项目里通过 CMake 的CMAKE_PREFIX_PATH指过去等确认编译没问题了再决定要不要加系统 PATH。2.2 编译 Grantlee模板引擎是 Cutelyst 的硬依赖必须先装Grantlee 是 Cutelyst 的模板引擎依赖Cutelyst 在 CMake 配置阶段会调用find_package(Grantlee5)去探测它找不到就静默禁用 Grantlee 视图支持。这个静默非常坑因为 Cutelyst 主库照样编译成功你到运行期才发现视图接口全没了再回头查 CMake 日志才看到 Grantlee 相关变量是空的。所以我强烈建议先把 Grantlee 单独装到一个独立前缀比如C:/grantlee/install和 Qt 分开管理。git clone https://github.com/steveire/grantlee.git cd grantlee git checkout 5.2.0 mkdir build cd build cmake -G Visual Studio 16 2019 -A x64 ^ -DCMAKE_PREFIX_PATHC:/Qt/5.15.2/msvc2019_64 ^ -DCMAKE_INSTALL_PREFIXC:/grantlee/install ^ -DBUILD_TESTINGOFF .. cmake --build . --config Release --parallel 8 cmake --install . --config Release这段命令里有几个关键点。第一git checkout 5.2.0必须执行Grantlee 的默认分支早就切到 Qt6 了直接编译默认分支会在 CMake 检测版本时报Qt6相关的错或者编译出一堆与 Qt 5.15.2 不兼容的符号。第二CMAKE_PREFIX_PATH指向 Qt 的msvc2019_64路径Grantlee 的 CMake 脚本依赖这个变量去找 Qt5 的 Config 文件。第三BUILD_TESTINGOFF关闭测试套件Grantlee 的测试编译极其耗时又和我们要做的事没关系。编译完成后检查C:/grantlee/install/bin会看到Grantlee_Templates.dll、Grantlee_TextDocument.dll这些动态库其中Grantlee_Templates.dll是 Cutelyst 视图层真正依赖的那个。另外Grantlee_Templates.lib、Grantlee_TextDocument.lib这些导入库在lib目录下后续 Cutelyst 链接时会用到。2.3 工具链核对CMake 3.16 起步VS2019 与 Qt 5.15.2 配套编译器我用的是 Visual Studio 2019版本不低于 16.11对应 MSVC 工具集 19.29。Qt 5.15.2 官方支持的编译器列表里写得很清楚VS2019 是主选。你非要用 VS2022 也不是完全不行但要意识到 Qt 5.15.2 的官方预编译库是用 19.29 编的混用工具集偶尔会遇到标准库实现细节不一致的链接问题这种问题查起来非常费时间我建议直接复制我这套组合。CMake 版本我推荐 3.16 到 3.22 之间我用的是 3.22。Cutelyst 的CMakeLists.txt对最低版本有硬性要求老版本会直接报错退出版本太新的话一些老式写法会有 deprecation 警告虽然不至于编译失败但日志看多了也烦。cmake --version这条命令确认 CMake 版本。cl这个命令只有在 Visual Studio 的x64 Native Tools Command Prompt里才存在普通 cmd 或 PowerShell 里找不到是正常的不用慌。我一般直接用 CMake 的-G参数指定生成器让 CMake 自己去定位 VS2019 的 MSVC 工具链不依赖 PATH 环境变量。工具链核对完成后环境就是三件套Qt 5.15.2 的 MSVC 2019 64 位库、Grantlee 5.2.0 的独立安装目录、VS2019 CMake 3.22 的编译组合。这三样齐了Cutelyst 的 CMake 配置阶段才有可能一次通过。3. 用 CMake 配置并编译 Cutelyst 动态库命令与全流程3.1 拉取源码Cutelyst 的目录结构与编译选项Cutelyst 源码从 GitHub 直接拉版本我用的 v3.0.0这个版本和 Qt 5.15.2 的配合最成熟。拉下来之后建议先看一眼顶层CMakeLists.txt里面有一堆CUTELYST_开头的选项变量比如CUTELYST_BUILD_TESTS、CUTELYST_BUILD_EXAMPLES、CUTELYST_BUILD_DOCS还有各个插件的开关。这些选项默认值大多是 ON意思是如果你不显式关掉CMake 会默认把测试、示例、文档全编译一遍时间翻倍不说还可能因为缺少依赖而在配置阶段报错。源码目录里src/Cutelyst是核心库的源码src/View/Grantlee是 Grantlee 视图的源码src/Plugins下面按插件分了目录比如 Session 插件就在src/Plugins/Session。Cutelyst 把主库、视图、插件分得比较清楚编译后你会看到多个 DLL不只是Cutelyst3Qt5.dll一个文件。git clone https://github.com/cutelyst/cutelyst.git cd cutelyst git checkout v3.0.0 mkdir build cd build这里切到 v3.0.0 之后build目录是独立的编译目录不污染源码目录这是 CMake 的标准做法。后面所有生成的文件包括CMakeCache.txt、.sln解决方案文件、编译产物全在这个build里想清理随时删掉重建。3.2 CMake 配置命令逐段拆解每个参数Cutelyst 的 CMake 配置命令看着长其实参数就三组生成器与平台、依赖路径、功能开关。我在 cmd 里执行的是下面这一整段长命令在 cmd 里用^换行如果你在 PowerShell 里跑^不生效删掉换行写成一行就行。cmake -G Visual Studio 16 2019 -A x64 ^ -DCMAKE_PREFIX_PATHC:/Qt/5.15.2/msvc2019_64;C:/grantlee/install ^ -DCMAKE_INSTALL_PREFIXC:/cutelyst ^ -DCUTELYST_BUILD_TESTSOFF ^ -DCUTELYST_BUILD_EXAMPLESOFF ^ -DCUTELYST_BUILD_DOCSOFF ^ ..逐项说-G Visual Studio 16 2019 -A x64指定生成器和目标平台CMake 会自动定位 VS2019 的 MSVC 工具链这一步不需要你手动设置任何环境变量。CMAKE_PREFIX_PATH是核心分号分隔两个路径一个是 Qt 5.15.2 的库目录一个是 Grantlee 的安装目录Cutelyst 的 CMake 脚本用find_package找 Qt5 和 Grantlee5 时就是遍历这个列表。CMAKE_INSTALL_PREFIX决定install阶段把东西装到哪我习惯单独放C:/cutelyst不混进 Qt 目录这样后续别的项目引用时路径清晰。三个CUTELYST_BUILD_*开关全部置 OFF只编译库本身和插件跳过测试和示例能省下大量编译时间。配置过程中 CMake 会在控制台打印很多-- Found信息重点看两行Found Grantlee5和Found Qt5。如果 Grantlee 没找到会打印Could NOT find Grantlee5之类的话这时候直接 CtrlC 中断回到上一段检查CMAKE_PREFIX_PATH是否包含C:/grantlee/install。注意CMAKE_PREFIX_PATH指向的是 Grantlee 的安装前缀不是源码目录。很多人配置失败是因为把路径指到了grantlee/build那个目录里根本没有Grantlee5Config.cmake。配置完成后build 目录里会出现Cutelyst3Qt5.sln或类似名称的 Visual Studio 解决方案文件同时会有CMakeCache.txt。此时可以顺手确认一下 Grantlee 视图选项是否真的被激活了cmake -LA . | findstr GRANTLEE如果输出里能看到类似CUTELYST_VIEW_GRANTLEE:BOOLON的行说明 Grantlee 视图已启用。如果显示 OFF 或者根本没有这个变量回到CMAKE_PREFIX_PATH检查 Grantlee 安装路径。这一步的坑我在第 5 章还会细说。3.3 编译与安装验证动态库确实被生成配置通过之后就是编译。Visual Studio 生成器默认是多配置的所以编译时用--config Release指定别在 CMake 配置阶段传CMAKE_BUILD_TYPE那个变量对 VS 生成器不生效传了也白传cmake --build . --config Release --parallel 8--parallel 8开 8 个并行编译任务我机器是 8 核 16 线程跑满没有压力。首次编译 Cutelyst 大概需要五到十分钟取决于机器性能。编译过程中如果报错绝大多数情况是缺少某个系统库或者 Qt 组件可以先跳去第 5 章对号入座。编译结束后检查输出目录cmake --install . --config Release安装完成后C:/cutelyst下的目录结构大概是这样的C:/cutelyst/ ├── bin/ │ ├── Cutelyst3Qt5.dll │ ├── Cutelyst3Qt5d.dll │ ├── Cutelyst3Qt5Session.dll │ └── ... ├── include/ │ └── Cutelyst/ └── lib/ ├── Cutelyst3Qt5.lib └── cmake/ └── Cutelyst3Qt5/bin下带d后缀的是 Debug 版动态库不带的是 Release 版两个都有就说明 debug 和 release 配置都编译过了。如果你只执行了--config Release那Cutelyst3Qt5d.dll不会出现这是正常的。lib/cmake/Cutelyst3Qt5目录里就是 CMake 包配置文件那是第 4 章要拆解的重点。4. 输出物解读Config 文件、Targets 文件与 debug/release 库的分工4.1 Cutelyst3Qt5Config.cmake外界引用这个库的入口Cutelyst 编译安装后你会在lib/cmake/Cutelyst3Qt5目录下看到一组文件Cutelyst3Qt5Config.cmake、Cutelyst3Qt5ConfigVersion.cmake、Cutelyst3Qt5Targets.cmake、Cutelyst3Qt5Targets-release.cmake、Cutelyst3Qt5Targets-debug.cmake。这一组文件构成了 CMake 的包配置文件作用就是让其他 CMake 工程通过find_package(Cutelyst3Qt5)找到 Cutelyst 库。Cutelyst3Qt5Config.cmake是入口它做的事情是检查依赖项比如 Qt5、Grantlee5、加载Cutelyst3Qt5Targets.cmake、设置缓存变量。Cutelyst3Qt5ConfigVersion.cmake存版本号find_package加REQUIRED时会用它做版本校验保证你引入的库版本和工程要求匹配。4.2 Targets 文件与 imported target 的定位逻辑Cutelyst3Qt5Targets.cmake是最核心的文件里面定义了 imported target也就是 CMake 里可以直接被target_link_libraries引用的逻辑目标。这个文件本身不包含具体的路径信息而是按配置分别 includeCutelyst3Qt5Targets-release.cmake和Cutelyst3Qt5Targets-debug.cmake这两个文件分别存了 Release 和 Debug 库的绝对路径、链接库名字、编译选项。这样设计的好处是你的工程在 Release 配置下编译时CMake 自动链接 Release 版的Cutelyst3Qt5.lib和Cutelyst3Qt5.dll切到 Debug 配置时自动切到Cutelyst3Qt5d.lib。你不需要自己在 CMakeLists 里做任何判断。我自己的工程里经常出现 Release 编译通过、Debug 编译却报链接错误的场景最后查下来都是混用了 Cutelyst 的 Release 导入库和 Debug 运行库这就是 Targets 文件双轨机制想避免的问题。4.3 Session、ActionChain、Component 都编到哪里去了Cutelyst 的架构是主库加插件。Cutelyst3Qt5.dll是核心库包含Application、Controller、Context、Request、Response这些基础类以及Action、ActionChain、Component这些框架组件。你项目正文里看到的那些名字比如Cutelyst3Qt5Session.5就是 Session 插件的动态库文件.5是 Cutelyst 主版本号后缀属于 Windows 动态库的版本标识惯例。Action 和 ActionChain 不是独立的动态库它们是核心库里的类。Action 是路由到 Controller 方法的抽象ActionChain 是把多个 Action 串成链这两个类会直接编进Cutelyst3Qt5.dll你通过核心库头文件就能使用。Component 也是核心库的一部分所有 Controller、View、Plugin 的基类都是它同样不需要单独链额外的库。Session 比较特殊它被编译成独立的插件动态库。这样的好处是插件可以按需加载不需要的会话功能不会拖累主库体积。运行时 Cutelyst 通过 Qt 的插件机制加载这些 DLL所以如果你要用 Session除了链接导入库还要保证Cutelyst3Qt5Session.dll在运行目录或 PATH 里否则插件静默加载失败你不会看到任何编译期报错。Grantlee 视图的情况类似View::Grantlee相关代码要么编进主库要么作为插件具体取决于你编译时打开的选项验证方法在第 3 章已经说过看 CMake 缓存里的CUTELYST_VIEW_GRANTLEE。5. 编译避坑五个翻车现场与对应的修复方法5.1 配置阶段报Could NOT find Grantlee5现象Cutelyst 执行cmake配置时提示找不到Grantlee5包配置日志里出现Could NOT find Grantlee5 (missing: GRANTLEE_TEMPLATES_LIBRARY)。原因CMAKE_PREFIX_PATH没指到 Grantlee 的安装前缀或者 Grantlee 安装目录本身不完整。常见情况是把路径指到了grantlee/build这种编译目录但Grantlee5Config.cmake只在install后的lib/cmake/Grantlee5里才有。解决确认CMAKE_PREFIX_PATH中包含的是C:/grantlee/install而不是别的路径然后检查C:/grantlee/install/lib/cmake/Grantlee5/Grantlee5Config.cmake是否存在。不存在就回到第 2 章重新执行 Grantlee 的cmake --install。5.2 链接错误LNK2038 mismatch detected for RuntimeLibrary现象自己的工程链接 Cutelyst 时MSVC 报LNK2038提示RuntimeLibrary不匹配一个值是/MDd一个是/MD。原因Cutelyst 编译时用的是 Release 配置但你工程在 Debug 配置下链接了 Release 版的导入库。也就是你手动指定了cutelyst3Qt5.lib而不是让 CMake 通过Cutelyst3Qt5Targets-debug.cmake自动选 Debug 库。解决不要在target_link_libraries里手写.lib路径统一用find_package(Cutelyst3Qt5)拿 imported target。工程切 Debug 配置编译时CMake 会自动通过Cutelyst3Qt5Targets-debug.cmake指向Cutelyst3Qt5d.lib这是最可靠的方案。5.3 运行时提示Cutelyst3Qt5.dll not found现象编译通过但运行 exe 时弹窗或控制台报错找不到Cutelyst3Qt5.dll或Cutelyst3Qt5Session.dll。原因Cutelyst 的动态库在C:/cutelyst/bin你程序的运行目录里没有这些 DLL系统 PATH 里也没有C:/cutelyst/binWindows 加载 DLL 失败。解决三种方式任选把C:/cutelyst/bin加入系统 PATH把需要的 DLL 拷贝到 exe 同目录或者在应用的 Qt 工程里加一个 post-build 步骤自动拷贝。我自己的习惯是把C:/cutelyst/bin和 Qt 的bin都加进 PATH本地开发省心部署时再用 windeployqt 统一处理。5.4 Grantlee 视图头文件找不到grantleeview.h现象编译工程时#include Cutelyst/View/Grantlee/grantleeview.h报找不到文件但 Cutelyst 主库头文件都能正常引入。原因Cutelyst 编译时没有激活 Grantlee 视图支持导致视图头文件根本没有被安装到include/Cutelyst/View/Grantlee。这个问题一般是 Grantlee 未被 Cutelyst 检测到CMake 静默跳过了视图模块。解决回到第 3 章 3.2 节的验证步骤执行cmake -LA . | findstr GRANTLEE如果变量是 OFF先修CMAKE_PREFIX_PATH然后删掉 build 目录重新配置。记住重配之前要清空 CMake 缓存CMAKE_PREFIX_PATH改了之后如果不删缓存CMake 有可能继续沿用旧值。5.5 Grantlee 编译报错跟 Qt 版本相关现象编译 Grantlee 源码时CMake 报错或者编译中大量QStringRef、QTextCodec相关的错误看起来像是 API 不兼容。原因Grantlee 的源码分支不对。默认分支或 master 分支是为 Qt6 准备的很多 API 在 Qt6 里已经变了用 Qt 5.15.2 编译自然报错。解决git checkout 5.2.0这是 Grantlee 在 Qt5 时代的最后一个稳定版本。如果你已经 clone 了仓库但没切 tag在仓库根目录执行git checkout 5.2.0然后重新走一遍编译流程。这招我早年没在意被 Qt 版本坑过一次之后现在任何时候下载 Qt 相关依赖源码第一件事就是看它的 tag 列表里有没有明确标注 Qt5 支持版本。6. 用编译结果跑通 Grantlee 视图渲染find_package 与最小示例6.1 最小 CMake 工程与路由注册编译好的 Cutelyst 动态库最终要落到一个能跑的工程里才算闭环。我的做法是先建一个最小 demo只暴露一个路由渲染一个模板页确认整条链路通了再往业务上扩展。这个 demo 的 CMakeLists 长这样cmake_minimum_required(VERSION 3.16) project(demo LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_AUTOMOC ON) find_package(Qt5 COMPONENTS Core REQUIRED) find_package(Cutelyst3Qt5 CONFIG REQUIRED) add_executable(demo main.cpp) target_link_libraries(demo PRIVATE Cutelyst3Qt5::Cutelyst3Qt5 Qt5::Core )关键在find_package(Cutelyst3Qt5 CONFIG REQUIRED)CMake 靠它找到第 4 章分析的那组 Config 文件。Cutelyst3Qt5::Cutelyst3Qt5这个 target 名来自 Targers 文件不同版本可能略有差别以你安装目录里实际生成的名字为准。main.cpp 里注册一个控制器和一个 Grantlee 视图#include QCoreApplication #include Cutelyst/Application.h #include Cutelyst/Controller.h #include Cutelyst/Context.h #include Cutelyst/Response.h #include Cutelyst/Server.h #include Cutelyst/View/Grantlee/grantleeview.h using namespace Cutelyst; class HelloController : public Controller { Q_OBJECT public: explicit HelloController(QObject *parent nullptr) : Controller(parent) {} C_ATTR(index, :Path :Args(0)) void index(Context *c) { c-setStash(QStringLiteral(message), QStringLiteral(Hello from Cutelyst Grantlee!)); c-response()-body() c-view(QStringLiteral(grantlee))-render(c); } }; class DemoApp : public Application { Q_OBJECT public: explicit DemoApp(QObject *parent nullptr) : Application(parent) { auto view new View::Grantlee(this); view-setTemplatePath(QStringLiteral(templates)); view-setIncludePaths({QStringLiteral(templates)}); new HelloController(this); } }; int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); app.setApplicationName(QStringLiteral(demo)); Server server(app); server.setPort(8080); if (!server.init(QStringLiteral(demo))) { return 1; } return app.exec(); } #include main.mocC_ATTR是 Cutelyst 的路由宏:Path :Args(0)表示根路径且不接收参数。c-view(grantlee)会去查找名为 grantlee 的 View 实例名字来自View::Grantlee构造时的默认名称如果你在 Application 构造函数里给 view 起了别的名字这里要对应改。6.2 模板渲染验证与运行习惯在可执行文件同目录下建一个templates文件夹放一个index.html!DOCTYPE html html head meta charsetutf-8 titleCutelyst Grantlee Demo/title /head body h1{{ message }}/h1 /body /html运行 demo 后访问http://127.0.0.1:8080/如果页面渲染出白色背景黑色字体的标题说明 Cutelyst 到 Grantlee 的整条链路都是通的。这里最容易踩的坑是模板路径setTemplatePath(templates)是相对路径它相对于进程的工作目录不是 exe 所在目录。你如果在 IDE 里启动工作目录通常是工程目录直接在文件管理器双击 exe工作目录就是 exe 所在目录。模板找不到时 Grantlee 不会报错只是渲染出空页面这个排查起来特别抓瞎。从那以后我每次编译完 Cutelyst 或者升级 Qt 版本都是先把这个最小 demo 跑通再开始动业务代码。模板渲染这种看着简单的事一旦路径、编码、资源目录任何一个环节没对齐排查时间远超预期。这个习惯帮我避开了不少后续的坑希望这份编译记录也帮到你。本文还有配套的精品资源点击获取
返回列表