
1. 开篇为什么要在 Ubuntu 上折腾 Cutelyst作为一个常年用 Qt 写桌面应用的开发者我一直觉得 Qt 就是用来做 GUI 的。直到去年某个项目里需要给内部工具加一个轻量级的 Web 管理界面我才开始接触 Cutelyst——这个把 Qt 的异步能力和 Web 服务端逻辑结合起来的 C 框架。说实话第一次看到这个名字我也是一脸懵但用了一段时间之后不得不承认如果你已经熟悉 Qt 的信号槽机制和 QObject 模型Cutelyst 的上手成本比想象中低很多而且对于本来就是 C 技术栈的团队来说整套服务的可维护性比混插 Python 或 Node 的方案要好不少。这篇笔记是我个人实际操作记录的第九篇重点讲在 Ubuntu 20.04 环境下搭配 Qt 5.15.2用 Qt Creator 从零到一把 Cutelyst 编译成可运行的 web 服务器。这篇内容的适用对象很明确已经会基础 Qt 开发、想尝试用 C 写 Web 服务、但不想走编译地狱弯路的开发者。这篇文章不是官方文档的翻译也不会从头讲 Cutelyst 的完整 API我只把从环境准备、依赖安装、源码编译到 Qt Creator 工程配置这一路踩过的坑和验证过的方法完整记录下来。如果你跟着做一遍还编译不过欢迎对照我在文末写的排查清单逐项检查大概率问题就出在那一两个容易被忽略的依赖版本上。2. 编译前的三个关键选择Qt 版本、Cutelyst 分支、编译器2.1 为什么选 Ubuntu 20.04 Qt 5.15.2 这套组合先说结论这不是随意搭配而是经过验证的稳定组合。很多人在 Windows 或 macOS 上编译 Cutelyst 其实更省事因为依赖库都好找但生产环境跑 Linux 服务器的团队占了大多数所以 Ubuntu 20.04 的系统镜像非常常见既不会太老导致新库不兼容也不会太新导致文档跟不上。Qt 5.15.2 是 Qt 5 系列的长期支持版本对 Cutelyst 1.0 系列来说足够稳定而且 5.15.2 是最后一代支持很多老式 Ubuntu 20.04 默认编译环境的 Qt 版本。如果选 Qt 6Cutelyst 的某些模块尤其是插件系统相关的部分会有额外的兼容工作对新手不太友好所以我建议初学阶段老老实实用 Qt 5.15.2。2.2 Cutelyst 分支选择的逻辑Cutelyst 官方仓库的主分支常年保持开发状态功能最新但某些时刻尤其是依赖库更新之后可能出现构建脚本和依赖版本不匹配的情况。我实际操作中默认选择 v1.0.0 系列的稳定 tag 或者最新的 release 分支不追主分支原因很简单这个框架更新频率不高稳定分支和主分支之间差异没那么大但稳定分支的文档、示例代码和网上讨论的匹配度更高出了问题容易搜到答案。这个选择逻辑和 Qt 版本选择是一个道理——开发框架的稳定性永远比追新版本带来的新鲜感更重要。2.3 编译器与 CMake 版本检查Ubuntu 20.04 系统自带的默认 gcc 是 9.4 版本这足够支持 C17 标准而 Cutelyst 1.0 正好要求 C17所以直接用系统自带 gcc 就好不需要额外升级编译器省掉了很多不必要的折腾。但有两个东西必须查版本很重要CMakeCutelyst 使用 CMake 作为构建系统官方 README 写的最低要求是 CMake 3.14。Ubuntu 20.04 默认的 CMake 据我所知是 3.16.3刚好满足要求。额外检查Qt5 的 CMake 配置文件是否能被正确找到这直接关系到后面 Qt Creator 能否正确加载项目。后面会详细说。提示最好别在 Ubuntu 20.04 上去 apt 装最新 CMake默认源版本就已经够用。如果你之前装过其他版本建议用 cmake --version 先确认避免版本混乱。3. 依赖库的安装顺序一个都不能漏3.1 Cutelyst 的完整依赖清单Cutelyst 不是单个库它包含核心模块和一堆可选插件。编译的时候如果你的系统里缺了对应依赖CMake 会自动跳过某些模块的编译表面上看起来编译成功了实际上你需要的功能并不在包里。这就是好多人编译完之后发现“怎么少了某某模块”的原因。就算你只想跑个 Hello World 服务器下面这些依赖也必须装齐。我列一张我在 Ubuntu 20.04 上验证过的清单依赖库系统包名用途是否必需Qt 5 核心模块qtbase5-dev提供 Qt Core、Qt Network 等基础模块必需Qt 5 SQL 模块libqt5sql5Cutelyst 的部分插件需要数据库支持推荐安装OpenSSLlibssl-dev提供 HTTPS 加密支持推荐安装CMakecmake构建工具必需g 编译器g编译 C 代码必需UUID 库uuid-dev用于生成请求唯一标识等操作必需3.2 具体安装命令与一条附加建议在 Ubuntu 20.04 上用 apt 装依赖是最省心的方式sudo apt update sudo apt install -y build-essential cmake uuid-dev libssl-dev libqt5sql5 qtbase5-dev其中 build-essential 会带出 gcc、g、make 等基础编译工具qtbase5-dev 是 Qt 5 开发包的核心uuid-dev 和 libssl-dev 是 Cutelyst 在编译时检查的硬性依赖。如果你后面打算连接 MySQL、PostgreSQL 或者使用 Redis 作为 session 存储建议提前把对应模块也装了免得第一次编译过了、后面加功能又要重新编译。我刚接触的时候踩过一个坑只装了 qtbase5-dev而没装 libqt5sql5结果最后 Cutelyst 的某个插件在 CMake 配置阶段被静默跳过导致我后面想用数据库持久化功能时找不到对应的头文件又要重新编译整个框架白白浪费了半小时。3.3 Qt 5.15.2 的安装建议Ubuntu 20.04 的 apt 源里自带的 Qt 版本我记得是 5.12.8 或者类似的老版本如果你想用 5.15.2建议直接去 Qt 官方下载 Qt 5.15.2 的离线安装包安装过程中只勾选你要用的模块就行。如果你硬盘空间和内存都够建议至少勾选 Qt 5.15.2 下的 Desktop gcc 64-bit 这一项这是编译期默认使用的工具链。这里有一个很多人不理解的细节qtbase5-dev 是给系统自带 Qt 用的开发包安装它的目的是为了让 Cutelyst 在依赖检查阶段能找到 Qt5 的基础模块。而你后续用 Qt Creator 新建项目时会指定刚才手动安装的 Qt 5.15.2 路径。两者各司其职不冲突。4. 编译 Cutelyst 源码从 clone 到 make install4.1 拉取源码并切换稳定分支我习惯先建一个专用目录把源码和后续构建文件都放在一起路径里不要有空格和中文字符这是 C 项目最常见的隐藏问题之一。mkdir -p ~/dev/cutelyst cd ~/dev/cutelyst git clone https://github.com/cutelyst/cutelyst.git cd cutelyst git checkout v1.0.0这里之所以 check out 到 v1.0.0是保证我们用的代码和这篇笔记里的验证结果是一致的。如果你想追最新版本可以把分支名换成最新的 release 标签但要注意依赖版本可能不同。4.2 配置 CMake 构建参数Cutelyst 的构建参数比较直观。我个人的建议是一切以默认参数为主只开启你确实需要的选项。新手不建议上来就改各种配置反而会因为配置组合太多而出莫名其妙的问题。mkdir build cd build cmake .. -DCMAKE_INSTALL_PREFIX/usr/local \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_PREFIX_PATH/opt/Qt/5.15.2/gcc_64解释几个关键点CMAKE_PREFIX_PATH指向你手动安装的 Qt 5.15.2 路径。这个很重要因为系统默认的 CMake 查找路径里不一定包含这个目录不指定的话 CMake 大概率会找到 /usr/lib/x86_64-linux-gnu/cmake 下的系统 Qt后续就不会报错。我遇到的情况是如果你之前用 apt 装过 qtbase5-dev系统 Qt 版本比 5.15.2 旧CMake 会默认找到旧版而 Cutelyst 要求 Qt 5.15.0 以上直接配置失败。所以这里一定要显式指定。CMAKE_BUILD_TYPERelease编译出来的库体积小而且正式运行也推荐 Release 版本。如果你想编译 Cutelyst 的测试用例可以加-DBUILD_TESTINGOFF跳过节省时间。配置完成后终端会输出一大段检查结果重点看这两点有没有出现Could NOT find开头的错误Qt 相关路径是否是/opt/Qt/5.15.2/gcc_644.3 编译与安装注意并发数配置完成后直接编译make -j$(nproc) sudo make install-j$(nproc)表示使用 CPU 的全部核心并行编译在你首次编译一个全新项目的时候明显提高速度。如果你内存不够比如虚拟机只分配了 2GB建议改成make -j2否则编译过程中可能出现内存耗尽导致编译器被杀进程的情况。sudo make install会把编译好的动态库安装到/usr/local/lib然后你需要刷新一下动态链接库缓存sudo ldconfig此时可以用一条命令验证 Cutelyst 是否安装成功pkg-config --modversion CutelystQt5如果输出类似 1.0.0 的版本号那恭喜你Cutelyst 核心库已经编译安装完成。这一步非常重要后面 Qt Creator 构建项目也要靠这个 pkg-config 文件来定位库。4.4 编译时长与性能参考在同一台 4 核 CPU、8GB 内存的虚拟机上从零开始编译整个 Cutelyst含核心模块和常用插件大概需要 8 到 15 分钟。如果你只是编译核心模块可以加-DBUILD_PLUGINSOFF跳过插件编译时间会更快一点。当然插件后面需要时再单独编译方式一样。5. 用 Qt Creator 创建第一个 Cutelyst Web 服务器5.1 新建项目配置 Kit打开 Qt Creator选择“New Project”在模板列表里找到 Cutelyst 相关的模板选项也可能你装的是较早版本模板不叫 Cutelyst而叫 “Qt Console Application” 之类的模板需要手动改 CMakeLists。我个人更容易上手的方式是手动创建一个 CMake 项目然后自己写 CMakeLists.txt。好处是能够直观感受到这个框架的构建逻辑如果后续要部署到服务器上这个过程会很有帮助。用以下内容创建 CMakeLists.txtcmake_minimum_required(VERSION 3.14) project(MyFirstServer CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(CutelystQt5 REQUIRED) add_executable(myfirstserver src/main.cpp) target_link_libraries(myfirstserver Cutelyst::Core)这里的关键之处是find_package(CutelystQt5 REQUIRED)它会让 CMake 运行pkg-config的封装逻辑来定位 Cutelyst 库。系统里如果没找到CMake 会在生成阶段直接停下来并报错。5.2 写一个能跑的入口 main.cppCutelyst 的入口看起来很像 Qt 的 main 函数因为它本身就是基于 Qt 事件循环的。最简单能跑的服务器代码如下#include Cutelyst/Application #include Cutelyst/Controller #include Cutelyst/Request #include Cutelyst/Response #include Cutelyst/Context using namespace Cutelyst; class RootController : public Controller { Q_OBJECT public: C_ATTR(display, :Path() :AutoArgs()) void display(Context *c) { c-response()-body() QStringLiteral(Hello Cutelyst!); } }; int main(int argc, char *argv[]) { QCoreApplication::setOrganizationName(MyDev); QCoreApplication::setApplicationName(MyFirstServer); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); Application app(argc, argv, new RootController); return app.exec(); }这里面有几个 Cutelyst 特有的语法点需要解释一下C_ATTR宏是 Cutelyst 用来声明路由的方式。:Path()表示请求路径为根路径/:AutoArgs()表示自动处理 URL 参数。Context是 Cutelyst 对一次请求的处理环境封装通过它来拿请求数据、写响应内容。根控制器要传给Application构造函数这个对象继承自QCoreApplication所以整个服务是跑在 Qt 的事件循环里的。5.3 在 Qt Creator 里配置构建套件新建项目后Qt Creator 会让你选择构建套件Kit这里必须选择一个能同时定位到 Qt 5.15.2 和系统编译器的套件。如果你安装 Qt 5.15.2 时是通过 Qt Catalog 安装的Qt Creator 会自动识别出对应的 Kit如果你只装了离线库、没装 Qt Creator 自带的 Kit手动添加 Kit 时记得同时指定编译器系统自带 gcc路径一般在/usr/bin/gcc和/usr/bin/gQt 版本/opt/Qt/5.15.2/gcc_64/bin/qmakeCMake系统自带的/usr/bin/cmakeKit 配置正确后直接点击构建。第一次构建时会比较慢因为 CMake 要重新跑一遍依赖解析之后每次只编译改动的文件速度就很快了。5.4 运行与验证构建成功后在 Qt Creator 里直接点击运行。此时应该能看到控制台输出类似这样的日志[INFO ] Application started on port 8080然后浏览器访问http://localhost:8080/就能看到 “Hello Cutelyst!” 字样。如果端口 8080 被占用了可以在 main 函数里设置环境变量CUTELYST_LISTEN_PORT来改端口或者干脆在编译前用setenv环境变量设置。我个人更喜欢在.env里维护这些配置不过这就属于后续部署的范畴了。6. 常见问题与排查技巧实录6.1 Qt 路径被系统旧版本抢占这个问题我遇到过不止一次CMake 配置阶段报Could NOT find Qt5: found unsuitable version 5.12.8说明 CMake 查找 Qt 的时候优先找到了 apt 里的旧版。解决办法很简单在 CMake 配置命令里显式指定cmake .. -DCMAKE_PREFIX_PATH/opt/Qt/5.15.2/gcc_64如果这个变量已经写了但依然不生效可以使用cmake -LA . | grep QT_来查看当前缓存里的 Qt 相关变量逐一确认路径是否被正确替换。6.2 Qt Creator 里无法找到 Cutelyst 的 CMake 包在 Qt Creator 构建时如果提示By not providing FindCutelystQt5.cmake通常不是 Cutelyst 没装好而是 Qt Creator 使用的 CMake 没有把/usr/local/lib/cmake/CutelystQt5这个路径加进查找目录。解决办法是在项目 CMakeLists.txt 里临时加一行list(APPEND CMAKE_PREFIX_PATH /usr/local)或者更优雅一点在项目里创建一个.cmake配置在你的用户目录下设置export CMAKE_PREFIX_PATH/usr/local:$CMAKE_PREFIX_PATH顺手说一句安装后 Cutelyst 的 CMake 配置文件默认被安装到了/usr/local/lib/cmake/CutelystQt5如果你的安装路径不同记得对应修改 CMAKE_PREFIX_PATH。6.3 运行时提示找不到动态库编译链接都成功了但运行时报error while loading shared libraries: libCutelystQt5Core.so.1: cannot open shared object file说明可执行文件在运行时找不到 Cutelyst 的.so文件。多数情况是动态链接库缓存没有刷新。依次跑sudo ldconfig ldd your_executable | grep Cutelyst如果 ldd 还是显示 not found那就把/usr/local/lib加入动态链接库配置echo /usr/local/lib | sudo tee /etc/ld.so.conf.d/cutelyst.conf sudo ldconfig这个问题在纯命令行编译时很常见但用 Qt Creator 有时候不太明显因为 Qt Creator 运行时环境设置会带上一些库路径但服务器部署时就会暴露出来。6.4 浏览器访问不了但启动日志正常如果你的服务启动日志显示监听端口正常但浏览器访问不通优先排查防火墙和监听地址。Cutelyst 默认监听的是所有网络接口也可能只监听 localhost这个要看版本默认配置。如果只监听了 localhost你把地址改成http://127.0.0.1:8080访问即可如果想外网访问需要在启动时设置监听地址为0.0.0.0。Ubuntu 20.04 的防火墙默认是 ufw如果你开着防火墙记得把对应端口放行sudo ufw allow 80806.5 虚机内存不足导致编译崩溃如果你是在虚拟机上操作内存分配少于 2GB编译 Cutelyst 时可能出现 “Killed” 提示——这不是代码问题是 OOM Killer 把编译进程杀了。建议把 swap 加上临时加个 2GB 的交换分区就行sudo fallocate -l 2G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile当然如果你本来就在编译大型项目还是建议物理机或内存大一点的 ECS 上操作省事得多。7. 我实际使用中的几个经验补充最后分享几个我这段时间使用 Cutelyst 总结下来的个人习惯。第一Cutelyst 的官方文档不厚但代码仓库里的示例工程反而是最靠谱的学习资料尤其examples/目录下的聊天室和博客示例数据结构简单、路由清晰适合作为第二个练手项目。第二Cutelyst 本身就是基于 Qt 的异步网络框架如果你的服务要处理长时间任务建议先把 Qt 的线程池机制理清楚这决定了后面会不会遇到事件循环阻塞。第三如果你只是想在现有 Qt 项目里快速加一层 Web API不一定非要把整个架构切到 Cutelyst——它内置了一个可以嵌入现有 Qt 应用的机制单片机和嵌入式领域也常拿它做设备管理后台这个用法比单独部署一个完整 web 服务要轻量得多。写这篇笔记的时候正好是本地新装了一台 64GB 内存的办公机编译 Cutelyst 从 configure 到 install 只花了不到三分钟想想自己第一次在虚拟机里等了十几分钟才成功确实还是硬件底子决定了起步体验。不管用什么环境把依赖搞对、把流程理顺Cutelyst 编译这件事其实就这么大点事。