Windows上搭建GitLab CI/CD实现Qt项目自动化构建

发布时间:2026/9/14 16:13:15
Windows上搭建GitLab CI/CD实现Qt项目自动化构建 1. 整体设计思路与方案选型先把话说在前面Windows 平台上跑 GitLab CI/CD其实是个有点“拧巴”的需求。绝大多数团队会用一台 Linux 服务器来跑 GitLab 和 GitLab RunnerWindows 机器只当开发机用。但你一旦做主攻 Qt 桌面应用的开发情况就不一样了——你面对的是一大堆 MSVC 编译器、Windows SDK、Qt 的 msvc2019_64 套件、windeployqt 打包工具这些玩意儿天生就依赖 Windows 环境。与其让 Linux CI 服务器交叉编译、折腾 wine不如老老实实在 Windows 上把 CI/CD 链条搭起来。这就是这篇文章的出发点。标题里写的是“windos 系统”我猜你要的就是 Windows。在这个平台上把 Qt 项目和 GitLab CI/CD 串起来核心要解决三件事第一GitLab 服务本身装在哪、怎么长期稳定跑第二GitLab Runner 怎么和 Windows 构建机配合第三Qt 项目的流水线脚本怎么写才能在 Windows 上顺畅构建、测试、打包。下面我按实际搭建顺序从架构选型开始一步一步展开。1.1 为什么选 GitLab 而不是 Jenkins你可能会有疑问搞 CI/CDJenkins 不是更常见吗在 Windows 生态里Jenkins 确实历史悠久但 GitLab 有一个别人比不了的优势代码仓库和 CI/CD 是天然一体的。代码推送到 GitLab 仓库Merge Request 一开Pipeline 自动跑测试结果直接显示在 MR 页面里。开发人员不需要额外打开一个 Jenkins 页面去查构建状态所有信息都在一个平台内闭环。另外 GitLab 对 CI/CD 的配置管理更现代化。.gitlab-ci.yml文件直接放在仓库根目录跟着代码走分支不同可以有不同的流水线Jenkins 的 Job 配置默认存在 Jenkins 服务器本地虽然也可以搞 Pipeline as Code但毕竟没有 GitLab 这么原生。对于一个小型团队或者个人项目来说GitLab 这套简直是开箱即用的体验。当然 Jenkins 也不是没优点——它的插件生态极其丰富很多老牌企业系统里全是 Jenkins。但如果你是从零开始而且本来就是 Qt 项目的代码仓库还没定那我强烈建议直接上 GitLab。一个东西解决代码托管、Code Review、CI/CD、制品管理省心不少。1.2 整体架构取舍GitLab 服务端放哪这是整个部署里最关键的一个决策。在 Windows 上装 GitLab CE社区版有几个选择方案 ADocker Desktop gitlab-ce 容器这是很多教程推荐的做法我也推荐。GitLab 官方其实没有发布针对 Windows 原生安装包Windows 上跑 GitLab 走 Docker 是最成熟的路径。Docker Desktop 在 Windows 上基于 WSL2 或 Hyper-V 运行一个轻量 Linux 虚拟机然后在虚拟机里跑 gitlab-ce 镜像。好处是一条命令就能拉起整个 GitLab升级就是换个镜像版本不会把 Windows 系统搞脏卸载也干净数据通过 volume 持久化误删容器也不怕缺点是内存占用偏高。GitLab CE 全家桶包括 PostgreSQL、Redis、Gitaly、Sidekiq 等一堆内部组件对内存要求不低Docker Desktop 本身还要吃掉一部分。建议电脑至少 16GB 内存给 Docker 虚拟机分配 8GB 以上。方案 B虚拟机里装 Ubuntu GitLab CE如果 WSL2 内存管理让你难受或者你有现成的 VMware/VirtualBox 环境也可以创建一个 Ubuntu 虚拟机在虚拟机里按 Linux 原生方式安装 GitLab。这种方案更稳网上资料也多GitLab 官方文档全是针对 Linux 的。缺点是虚拟机占用的磁盘比 WSL2 的 ext4 vhdx 还大管理也更笨重。方案 CWindows 上装 GitLab Runner服务端放局域网另一台 Linux如果团队里已经有一台 Linux 服务器那就不用纠结了GitLab 装 Linux 上Windows 机器单独装一个 GitLab Runner注册到同一个 GitLab 实例。这才是真正的“混合架构”也是实际企业里最常见的形式。文章后面讲的 Runner 配置和 Qt 构建流水线完全适用于这种方案。这里我默认你是一个人或者小团队想在一台 Windows 机器上把整套体系跑起来。那最常见的选择就是方案 AWindows 宿主机装 Docker DesktopWSL2 里跑 gitlab-ce 容器然后宿主机再装一个 GitLab Runner 来执行构建任务。整个架构的数据流是这样的开发者提交代码 ↓ GitLab CE (Docker容器, WSL2内) ↓ 触发Pipeline GitLab Runner (Windows宿主机, shell executor) ↓ 执行 .gitlab-ci.yml 中定义的 job Qt构建 → 单元测试 → windeployqt打包 → 上传制品到GitLab注意 Runner 没有跑在 Docker 里而是直接跑在 Windows 宿主机上。这一点对 Qt 项目尤其重要下面我会详细解释为什么。2. GitLab CE 本地部署实操2.1 Docker Desktop 安装与内存分配如果还没装 Docker Desktop先去官网下载 Docker Desktop for Windows。安装过程比较傻瓜但有几个点要留意第一确保 Windows 功能里“适用于 Linux 的 Windows 子系统”和“虚拟机平台”两个选项已经打开。安装 Docker Desktop 时它会提示你如果没有开启需要重启系统。第二安装完成后在 Docker Desktop 设置里找到 Resources 选项卡把 WSL2 的 Memory 调大。我一开始保持默认的 4GB结果 GitLab 容器起来没几分钟就 OOM。我建议至少分配 8GB 内存给 WSL2CPU 保持默认即可。如果你宿主机内存只有 16GB那分配给 WSL2 后还剩 8GB 给 Windows 日常用差不多能撑住。另外在 Docker Desktop 的 Resources 里把 Disk image size 也调大一点默认 64GB 偏小因为 GitLab 的镜像加数据很容易超过 20GB加上 Docker 里其他镜像64GB 有点紧张我建议直接给 128GB。2.2 用 docker-compose 跑 GitLab CE我不建议直接用docker run命令拉 GitLab参数太多了容易漏。更推荐写一个 docker-compose.yml以后升级、迁移都方便。以下是我在 Windows 上实际使用的配置version: 3.8 services: gitlab: image: gitlab/gitlab-ce:16.11.2-ce.0 container_name: gitlab restart: always hostname: gitlab.local environment: GITLAB_OMNIBUS_CONFIG: | external_url http://gitlab.local:8929 gitlab_rails[gitlab_shell_ssh_port] 2224 # 关掉一些用不上的组件省内存 prometheus_monitoring[enable] false alertmanager[enable] false node_exporter[enable] false redis_exporter[enable] false postgres_exporter[enable] false gitlab_exporter[enable] false puma[worker_processes] 2 sidekiq[max_concurrency] 5 nginx[enable] true ports: - 8929:8929 - 2224:22 volumes: - D:/docker/gitlab/config:/etc/gitlab - D:/docker/gitlab/logs:/var/log/gitlab - D:/docker/gitlab/data:/var/opt/gitlab shm_size: 256m这里有几个关键点要解释。hostname 和 external_url 的端口问题。我刻意把 GitLab 的 Web 端口从默认的 80 改成 8929是因为 Windows 上 80 端口经常被其他程序占用比如 IIS、某些开发工具。external_url里必须带端口号否则容器内生成的链接会指向错误地址。SSH 端口映射成 2224。GitLab 默认的 SSH 端口是 22Windows 上 22 端口同样容易冲突而且很多公司网络会屏蔽非标准端口。我映射成 2224克隆仓库时地址就是ssh://gitgitlab.local:2224/group/project.git。这个端口号可以在 GitLab 的 Admin Area 里查看和修改显示。关掉 Prometheus 监控。这是省内存的关键操作。GitLab CE 自带一堆监控组件单个占用内存不大但加起来很可观。本地搭建、不是生产环境没必要开监控全部关掉能省出 1~2GB 内存。如果你内存充足也可以开着毕竟监控数据对排查问题有帮助。puma 和 sidekiq 的并发数调低。GitLab 内部 Web 服务端 Puma 默认按 CPU 核心数开 workerSidekiq 是后台任务队列。个人使用、团队人数少的情况下这些并发数调低完全够用还能显著降低内存压力。保存好 docker-compose.yml 后执行docker compose up -d第一次启动要拉镜像大小几个 GB视网速可能要等很久。启动后 GitLab 初始化比较慢尤其容器第一次起来要做数据库迁移、编译 assets整个过程可能持续 5~15 分钟。期间docker ps看到容器状态是 healthy 不代表完全就绪最好直接浏览器访问http://localhost:8929看到登录页面才算真正完成。2.3 初始密码与基础配置新装好的 GitLab CE 会默认生成一个root用户密码在容器内的/etc/gitlab/initial_root_password文件里。执行docker exec -it gitlab cat /etc/gitlab/initial_root_password拿到密码后用 root 登录第一件事就是去 User Settings 里改密码。然后建议在 Admin Area - Settings 里做几项基础配置关闭用户自助注册。本地搭建的 GitLab 不对外开放把注册关掉避免不相干的人注册进来。改成中文界面。GitLab 有国际化支持在 User Settings - Preferences 里把语言改成 Chinese。不过我还是建议保留英文界面因为很多报错信息、文档、社区讨论都是英文的直接用英文界面能减少认知偏差。检查 SSH 端口显示。Settings - Network - SSH port 里填 2224这样仓库页面上显示的克隆命令就会带上正确端口。等 GitLab 稳定运行后在 Windows 任务管理器里观察 WSL2 进程vmmemWSL的内存占用。正常情况下会在 6~8GB 之间浮动如果超过 10GB要么是你设置不对要么是配置的组件没关干净回头检查一下 GITLAB_OMNIBUS_CONFIG 里是否写错键名。3. Windows 版 GitLab Runner 的安装与注册3.1 为什么 Runner 用 shell executor 而不是 docker executorGitLab CI/CD 的构建任务需要由 Runner 执行。GitLab Runner 可以在 GitLab 容器里装但我强烈建议在 Windows 宿主机上单独装一个 Runner并且 executor 选择shell而不是docker。道理很简单Qt 项目在 Windows 上的构建链路涉及 MSVC 编译器、Windows SDK、Qt 库、甚至可能有第三方 Windows 依赖库。用 docker executor 意味着每次构建都要在一个 Windows 容器里重装一遍 Qt 和编译器配置极其痛苦而且 Windows 容器本身对 GPU、图形库的支持也很不友好。用 shell executorRunner 直接在 Windows 宿主机上执行命令行构建环境就是你平时的开发环境Qt、编译器、环境变量全都在效率最高、最容易排错。GitLab 官方其实也推荐在 Windows 上用 shell executor。去 GitLab 官网下载 Windows 版的 gitlab-runner.exe放在一个固定目录比如C:\GitLabRunner然后在命令行注册gitlab-runner.exe register注册过程是交互式的要填 GitLab 实例地址http://gitlab.local:8929、注册 token在 GitLab 项目的 Settings - CI/CD - Runners 里能找到、描述信息、标签tags最后选 executor 为shell。注册完成后编辑C:\GitLabRunner\config.toml把 shell 指定为powershell[[runners]] name windows-qt-runner url http://gitlab.local:8929 token xxxxxxxxxxxx executor shell shell powershell [runners.custom_build_dir] [runners.cache]3.2 Windows 环境准备Qt、编译器与系统路径Runner 跑流水线时本质上就是在一个非交互式的 Windows 会话里打开 PowerShell 执行命令。这个会话的 PATH 环境变量和你平时在命令行窗口里看到的不太一样因为 GitLab Runner 以 Windows 服务方式运行时不会加载用户级别的 PATH这算是老版本的一个坑新版本有所改善所以你最好在 Runner 服务里设置好环境变量或者在流水线脚本中显式声明。我的建议是把 Qt 和编译器的路径写进系统环境变量而不是用户环境变量QTDIRD:\Qt\5.15.2\msvc2019_64 PATH...;D:\Qt\5.15.2\msvc2019_64\bin;C:\Qt\Tools\mingw810_64\bin如果用MinGW另外确认能保证qmake、cmake、jomQt 自带的并行构建工具在任意的 PowerShell 会话里都能直接调用。怎么验证在 Windows 服务管理器里找到 GitLab Runner 对应的服务默认是“GitLab Runner”不管它以什么账户运行你先手动开一个 PowerShell执行qmake --version jom cl如果这里能跑通Runner 里基本也能跑通。如果cl命令不行那还得把 MSVC 的环境引入。MSVC 的环境很烦人它需要调用vcvarsall.bat来设置一大堆环境变量。比较稳妥的做法是在流水线脚本的最前面调用它后面我会给出具体写法。顺带说一个坑新版本 Windows 的 GitLab Runner 注册时如果以 Local System 账户运行可能会遇到不加载用户环境变量的问题。解决方案是在 Windows 服务管理器里打开 GitLab Runner 服务属性设置登录身份为你的 Windows 用户名和密码然后重启服务。这样 Runner 就能拿到你用户级别的环境变量了。不过这样做有个副作用用户修改环境变量后需要重启 GitLab Runner 服务才能生效。我个人的习惯是构建相关的重要路径全部写在系统环境变量里Runner 服务用 Local System 跑也不用担心。3.3 验证 Runner 状态启动 Runner 服务后回到 GitLab 网页进入 Admin Area - Runners 页面能看到一个绿色的、带windows-qt-runner描述的 runner 出现。如果状态不是绿色而是显示灰色或者 offline那就是服务没起来或者注册 token 有问题。这时候先回头检查注册 token 是否正确再查 config.toml 是否写了shell powershell。还有一种可能你的 GitLab 实例用了自签名证书Runner 访问时会提示证书错误。GitLab 安装到 Windows Docker 环境时一般不会去改证书这个问题比较少出现但如果你改了记得在注册 runner 时加--tls-ca-file参数。4. Qt 项目接入.gitlab-ci.yml 的设计与实现4.1 构建环境的初始化脚本前面说过MSVC 的命令行环境需要 vcvarsall.bat 来初始化。Qt 项目如果在 Windows 上走 MSVC 工具链流水线的第一个 job 里必须先做这一步。我用的写法是在仓库根目录放一个build_init.ps1param( [string]$VcVarsPath C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat ) if (!(Test-Path $VcVarsPath)) { Write-Error vcvars64.bat not found: $VcVarsPath exit 1 } # 执行 vcvars64.bat 并捕获环境变量 cmd /c $VcVarsPath set | ForEach-Object { if ($_ -match ^(.*?)(.*)$) { Set-Item -Path Env:$($matches[1]) -Value $matches[2] } }这段脚本的原理不复杂vcvars64.bat 本身是批处理只能在 cmd 里执行。我们用cmd /c vcvars64.bat set让它执行完所有环境变量设置后把当前环境下所有的环境变量打印出来set命令然后在 PowerShell 里逐行解析KEYVALUE格式并设置到当前会话。这样 PowerShell 会话里就有了 cl.exe、link.exe、nmake、INCLUDE、LIB 等 MSVC 必需的环境变量。这个脚本对 Qt 的 MSVC 构建是必须的。Qt 的 msvc2019_64 套件编译出来的程序要正常编译、链接必须有完整的 MSVC 工具链和 SDK 环境。如果你已经通过 Qt 自带的“Qt 5.15.2 (MSVC 2019 64-bit)”快捷方式手动运行过 qmake应该能理解这种痛苦——命令行构建最烦的就是环境变量继承。4.2 流水线阶段与 Job 定义下面是我实际使用的一个 Qt 5.15.2 MSVC2019 项目的.gitlab-ci.yml精简版。GitLab 的 CI 阶段用stages定义我这里分了build、test、package三个阶段stages: - build - test - package variables: QTDIR: D:/Qt/5.15.2/msvc2019_64 BUILD_DIR: build_ci build: stage: build tags: - qt script: - powershell -ExecutionPolicy Bypass -File .\build_init.ps1 - mkdir $env:BUILD_DIR -Force - cd $env:BUILD_DIR - qmake ..\MyProject.pro CONFIGrelease - jom artifacts: paths: - build_ci\release\*.exe expire_in: 1 week test: stage: test tags: - qt script: - powershell -ExecutionPolicy Bypass -File .\build_init.ps1 - cd $env:BUILD_DIR\tests - .\run_unit_tests.exe --gtest_outputxml:test_results.xml artifacts: paths: - build_ci\tests\test_results.xml expire_in: 1 week package: stage: package tags: - qt script: - powershell -ExecutionPolicy Bypass -File .\build_init.ps1 - cd $env:BUILD_DIR\release - windeployqt --release MyApp.exe - # 这里可以继续做 Inno Setup 安装包、7z 压缩等 artifacts: paths: - build_ci\release\*.exe expire_in: 1 week这套配置有几个细节想重点说一下。状态一qmake 换成 CMake 更通用。如果你用的是 Qt 6或者团队更习惯 CMake就把qmake和jom换成cmake --build。最新 Qt 版本官方已经主推 CMake但 Qt 5 项目用 qmake 完全没毛病。如果你的团队既有 Qt 5 又有 Qt 6 项目建议统一到 CMake避免两套构建脚本。状态二每次 commit 都安装依赖不现实。install_deps这行我没写是因为在 Windows 上如果每次流水线都执行vcpkg install或者pip install速度会非常慢。正确做法是提前在构建机里装好依赖流水线里只做构建。如果依赖库版本变了更新构建机或者用缓存。GitLab CI 的cache功能在 Windows 上表现一般要小心使用特别是大体积 Qt 库缓存反而比直接读取慢。状态三jom和并行构建。jom是 Qt 官方出的 make 工具它基于 nMake 的规则支持并行编译。默认会开满 CPU 核心小项目无所谓但大项目如果其它构建任务同时跑CPU 会被拉爆。建议限制一下比如jom -j4。如果 CPU 核心数少比如 4 核并行数设成 4 也没问题内存不够就设 2。这个参数要按构建机的实际能力来定。4.3 Windows 特有的路径与编码问题Windows 上的 CI/CD 脚本最让人头疼的其实不是逻辑设计而是一堆环境层面的坑。我把踩过的坑集中整理在第五节这里先挑两个最重要的说。第一个是换行符。如果你在 Windows 上把.gitlab-ci.yml文件保存成 CRLF 换行GitLab Runner 解析时可能会出问题尤其是脚本里的多行命令。解决办法是在仓库根目录放一个.gitattributes文件强制统一换行符.gitlab-ci.yml text eollf *.ps1 text eolcrlf注意 runtest 脚本*.ps1用 CRLF 没问题PowerShell 认但 YAML 文件一定要 LF。第二个是文件路径中的反斜杠。在 YAML 里写 Windows 路径时D:\Qt\5.15.2\msvc2019_64里\Q会被解析成一个转义字符。所以要么把路径写成D:/Qt/5.15.2/msvc2019_64正斜杠要么在 YAML 配置里给路径加上单引号或双引号。写路径时统一用正斜杠最省心Windows 的命令行工具和 PowerShell 基本都兼容正斜杠。4.4 Artifacts、Cache 与版本号管理一个容易混淆的概念是 artifacts 和 cache。简单说artifacts 是构建产物的传递机制比如把 exe 从 build 阶段传给 package 阶段用cache 是用来加速依赖安装的缓存目录比如 npm 缓存、vcpkg 缓存等。在 Windows Qt 场景下我几乎不用 cache因为 Qt 本身就装在构建机里构建过程不做依赖安装但如果你的项目用 MSYS2、Chocolatey 或者 vcpkg 来管依赖那 cache 也会有点作用不过 Windows 上 cache 的命中率经常让人一言难尽。我的态度是能用 artifacts 传递的产物就不用 cache真正要加速就靠构建机本地已装好的环境。版本号怎么嵌入构建产物一个比较常见的方式是不用手动维护版本号直接用 GitLab 的CI_PIPELINE_ID或CI_COMMIT_SHORT_SHA来自动拼一个构建号。在.gitlab-ci.yml里定义一个变量variables: APP_VERSION: 1.0.${CI_PIPELINE_ID}然后在 qmake 的工程文件里可以用$$(APP_VERSION)读取这个环境变量Windows 下 qmake 读取环境变量的语法和 Linux 略有区别要注意大小写或者在打包阶段用它来重命名 exeCopy-Item MyApp.exe MyApp_$env:APP_VERSION.exe这样每个流水线跑出来的 exe 都带有独立的构建号回传问题、定位版本都方便很多。5. 常见问题与排查技巧实录5.1 Runner 注册时报 “login failed. check api token or gitlab version”这是 Windows 上注册 runner 最常见的报错大概率是 GitLab 版本和 Runner 版本不匹配导致的。GitLab Runner 的新版本往往主动去兼容旧版 GitLab但反过来未必成立。解决办法很简单先用gitlab-runner --version查看本机 Runner 版本再去 GitLab 的 Admin Area 里看实例版本。如果 Runner 版本比 GitLab 版本新太多就给 Runner 降级到和 GitLab 差不多或略低的版本。另外一种是注册 token 问题。新版 GitLab 把项目级和实例级的 runner 注册 token 管理分开了。项目里 Settings - CI/CD - Runners 页面显示的 token仅用于给该项目注册专用 runner如果是管理员要注册全局 runner得去 Admin Area - CI/CD - Runners 页面拿。很多教程不区分导致新手拿着实例级 token 去项目里配一直报这个错误。注意一下就能解决。5.2 流水线跑起来后提示 qmake 不是内部或外部命令这就是环境变量没加载成功。现象是 GitLab 网页里 pipeline 日志显示qmake : 无法识别或者qmake is not recognized as an internal or external command。先从这几个方向排查在 Runner 服务所用的账户下手动执行qmake --version是否正常。如果手动正常但流水线里不行多半是 GitLab Runner 服务没有加载用户环境变量。按前面说的把服务登录身份改成你自己的 Windows 账户或者把 Qt 路径写进系统环境变量。检查 config.toml 里shell powershell之后有没有写[runners.shell]相关配置有些版本还需要指定fallback_to_bash参数不过这是 Linux 的事Windows 上较少遇到。5.3 MSVC 相关错误fatal error C1083、LNK1104 等如果你在流水线里执行cl或者jom时报fatal error C1083: Cannot open include file: corecrt.h之类的问题说明 INCLUDE 环境变量没设置。这个基本可以判定为 vcvars 没有生效回到 4.1 节的build_init.ps1脚本确认执行成功。一个常见的翻车点是我把 vcvars64.bat 路径写成了2019\Community但你的机器上装的是 Build Tools 版本路径其实是2019\BuildTools。这需要按实际安装版本调整脚本参数也可以在脚本里用-ErrorAction Stop做路径检查找不到就直接报错至少不要让它带着残缺环境继续跑。如果你遇到LNK1104: cannot open file Qt5Cored.lib说明链接器找不到 Qt 的 debug 库。这多半是你在 release 构建里误用了debug_and_release配置或者 Qt 套件本身没有安装 debug 库。Qt 在 Windows 上安装时默认把 debug 和 release 库都装上了如果没有可以回 Qt Maintenance Tool 里补装对应套件。5.4 中文路径 / 空格路径引发的各种怪问题Windows 上 Qt 项目的路径中含空格太常见了比如C:\Program Files\Qt。这类路径在命令行里如果不加引号会被拆分成两段。流水线脚本里尤其明显qmake 参数、jom 参数、windeployqt 的路径全都可能被空格切断。更麻烦的是中文路径。Qt 某些版本的 windeployqt 对中文路径支持有问题可能出现“无法访问 目录”之类的诡异错误。我的建议是构建机上的 Qt 安装目录、项目存放目录、Runner 工作目录全部不要出现空格和中文。偷懒的解决办法就是在 D 盘建一个D:\Qt放到 QtD:\GitLabRunner放 RunnerD:\gitlab-builds作为 Runner builds_dir。这套命名能避开 90% 的路径问题。如果你硬要在代码里处理空格路径记得所有命令行工具调用时给路径加双引号并在 PowerShell 里用调用运算符执行 D:\Qt\5.15.2\msvc2019_64\bin\qmake.exe ..\MyProject.pro不要在脚本里手动拼路径字符串除非你能保证两端永远没有空格。5.5 构建目录无限膨胀流水线跑得越多构建目录越来越大这几乎是必然的。每一个 job 在 Runner 上都会分配一个新的工作目录GitLab 默认的 builds_dir 下每个 pipeline 有自己独立的文件夹pipeline 执行完后文件夹不会自动清理。跑几十次流水线后几十 GB 的磁盘空间就没了。解决思路有两个方向。一是全局清理写一个定时任务Windows 任务计划程序定期删除builds_dir下超过 N 天的目录。二是充分利用variables.FF_USE_FASTZIP或清理策略。但最实用的还是在 Runner 的 config.toml 里配一个[runners.custom_build_dir]把所有 job 的构建目录放到同一个项目目录下job 执行前先删旧目录再构建。体积控制更可控构建速度也会更快目录切换少文件系统缓存命中率高。5.6 运行基类测试、文件路径大小写问题Qt 项目里如果用到 QtTest 做单元测试测试执行器往往要调 DLL。在 CI 环境里PATH可能没有包含 Qt 的 bin 目录导致测试跑起来报“无法加载 Qt5Test.dll”。此时在跑测试前把 Qt bin 目录加进 PATH 就行$env:PATH D:/Qt/5.15.2/msvc2019_64/bin;$env:PATH另外提醒一点Windows 文件系统默认大小写不敏感但 GitLab CI 的 artifacts 上传到服务器后下载到本地再解压时如果脚本里有大小写敏感的文件名判断就可能在 Windows/Linux 之间出现不一致。项目里如果既有 Windows 又有 Linux 构建机尽量统一小写文件名别玩大小写不同的两个文件。6. 高阶技巧与后续演进思考6.1 利用 GitLab CI 的规则做分支差异化构建用rules关键字可以按分支、标签、管道类型做差异化的任务调度。比如只有打 tag 时才走package阶段并生成安装包日常 push 到 develop 分支只做 build test。package: stage: package rules: - if: $CI_COMMIT_TAG - if: $CI_COMMIT_BRANCH main script: - powershell -ExecutionPolicy Bypass -File .\build_init.ps1 - cd $env:BUILD_DIR\release - windeployqt --release MyApp.exe这样能控制磁盘用量和流水线总时长。全量构建每次 commit 都跑代价不小tag 构建才出安装包更符合软件发布习惯。6.2 多套 Qt 版本的矩阵构建团队项目可能需要同时兼容 Qt 5.12、Qt 5.15 甚至 Qt 6.x。GitLab CI 的matrix语法在这里就派上用场了build: stage: build parallel: matrix: - QT_VERSION: [5.12.12, 5.15.2, 6.2.4] script: - powershell -ExecutionPolicy Bypass -File .\build_init.ps1 - set QTDIRD:/Qt/$env:QT_VERSION/msvc2019_64 - mkdir $env:BUILD_DIR -Force - cd $env:BUILD_DIR - qmake ..\MyProject.pro - jom前提是构建机上装了所有版本的 Qt。构建机数量有限时矩阵任务会让队列变长但胜在一次性把所有版本的兼容性问题暴露出来。对 Qt 插件或库类项目来说这是非常有价值的自动化保障。6.3 从 Windows 构建机到 Docker 化部署的演进前面说过 Windows 上用 shell executor 最合适但如果你做的不只是 Windows 桌面应用还涉及服务端或者跨平台部署那可以迈出第二步同一套 GitLab Runner 既跑 Windows shell executor又在 Linux 上加一个 docker executor。这样 Qt 项目的 Windows 安装包在 Windows runner 上出Linux 服务端镜像在 docker runner 上出。GitLab CI 的 runner 管理支持多 runner 并行各干各的互不干扰。架构上是从单机走向混合构建机的自然延伸。如果以后构建机器多了可以给 runner 打上不同的访问标签比如tag: qt-windowstag: docker-linux仓库里 job 通过 tags 去指定用哪台机器跑。GitLab 这套标签机制在异构 CI 环境里非常顺手。6.4 关于版本升级与备份GitLab 的升级路径比较讲究社区版不支持跨大版本直接升级比如从 14 直接升 16 会很危险需要逐个大版本走 migration。Docker 部署升级倒是简单——改 docker-compose 里的镜像 tagdocker compose pull docker compose up -d但它内部依然会跑数据库 migration速度视数据量而定。本地使用的话不频繁升级也没关系唯一需要上心的是备份。Docker volume 目录D:/docker/gitlab/config和data定期备份下来哪天出问题恢复就靠它们了。另外最好在 GitLab 管理后台开启每日自动备份备份文件存到另一个磁盘或 NAS 上省心。还有一点必须提醒GitLab 升级容易踩坑的地方是external_url变更。如果你中途改过端口或域名GitLab 生成的仓库克隆 URL、CI/CD 相关地址都会变Runner 连接和已有 clone 地址都可能失效。改配置前一定先想清楚。写在最后的经验这套 GitLab Qt 的本地 CI/CD 体系我前前后后踩了不少坑核心就是两个一是 Windows 环境变量和路径的问题占据了一半以上的排错时间二是 GitLab Runner 和 GitLab 服务端的版本匹配、注册流程必须严格按照版本来。但是一旦打通了收益非常直观——代码一 pushWindows 上自动编译、自动跑测试、自动出包团队拿到的是一个随时可回滚、可追溯的构建记录而不是依赖某个人电脑上“我这能编过”的玄学。最后再分享一个小技巧Windows 流水线的日志里乱码问题多数是 PowerShell 输出编码和 GitLab 日志页面默认 UTF-8 不一致导致的。在脚本最前面加上[Console]::OutputEncoding [System.Text.Encoding]::UTF8强制让 PowerShell 输出 UTF-8很多中文报错信息就能正常显示了。这个小设置会让排查问题的效率提高很多。