- 图形学
- 桌面应用
【免费下载链接】krita
Krita is a free and open source cross-platform application that offers an end-to-end solution for creating digital art files from scratch built on the KDE and Qt frameworks.
导读
Krita 作为一套横跨 Linux、Windows、macOS 与 Android 的大型 C++ 工程,其持续集成流水线由 GitLab CI 承载,包含 Qt5/Qt6 双线构建、每日构建(nightly)、每周构建(weekly)与发布(release)等多个 job 家族。本文以仓库根目录下的 HACKING.gitlab-ci.md 为骨架,完整解析 Krita 团队为 CI 流水线开发者制定的五条核心规范(缩进、日志、脚本语言、引号策略、布尔值与多行参数),并结合 .gitlab-ci.yml 与 build-tools/ci-scripts 下的真实平台配置文件逐一印证。读完本文,你将掌握一套可直接复用的 Krita 风格 GitLab CI 编写规范,理解KDECI_*/KRITACI_*环境变量的真实作用,以及如何为长耗时构建 job 构建可靠的日志与制品策略。
1. Krita 的 CI 骨架:从 HACKING 文档到流水线实景
HACKING.gitlab-ci.md是 Krita 仓库为维护 CI 流水线本身的开发者(而非为应用功能开发者)准备的短小规范手册。它不讲解功能开发,而是聚焦「如何写出整洁、可维护、跨平台一致的 GitLab CI YAML 与配套脚本」。
该规范在仓库中的落地形态非常清晰:根目录的 .gitlab-ci.yml 负责全局变量、workflow 规则与通用 mixin 定义,并通过include: local:引入四个平台级流水线文件:
include: - local: /build-tools/ci-scripts/linux.yml - local: /build-tools/ci-scripts/windows.yml - local: /build-tools/ci-scripts/android.yml - local: /build-tools/ci-scripts/macos.yml而 .gitlab-ci.yml 顶部集中声明了跨平台共享的顶层变量,例如各平台依赖分支名(DEPS_BRANCH_NAME_WINDOWS/LINUX/MACOS/ANDROID)、Qt6 迁移分支名(DEPS_QT6_BRANCH_NAME_*)、以及各平台 VM 镜像名(VM_IMAGE_NAME_WINDOWS/LINUX/ANDROID)。这些变量正是下文各条规范反复操作的对象。
接下来,我们逐条展开 HACKING 文档中的五条规则。
2. 规则 0:YAML 缩进统一为 2 空格
Krita 的 C++ 源码遵循 KDE 惯例的 4 空格缩进,但 CI 的 YAML 文件刻意与 C++ 风格区分——统一使用2 空格缩进,理由是跟随系统管理员(Sysadmin)编写脚本的习惯。
HACKING 文档为此给出了 VSCode 的编辑器配置片段,可直接写入 VSCode 的settings.json,确保编辑 YAML 时不会被自动格式化工具擅自改写缩进:
"[yaml]": { "editor.formatOnSave": false, "editor.tabSize": 2, "editor.insertSpaces": true, "editor.detectIndentation": true, "editor.wrappingIndent": "indent", "editor.autoIndent": "full" },各配置项的含义与价值:
| 配置项 | 值 | 作用 |
|---|---|---|
editor.formatOnSave | false | 禁止保存时自动格式化,避免 Prettier/YAML 插件把 2 空格改成 4 空格或制表符 |
editor.tabSize | 2 | 一个制表符视作 2 列宽,与渲染宽度对齐 |
editor.insertSpaces | true | 按下 Tab 时插入空格而非制表符字符 |
editor.detectIndentation | true | 根据文件已有缩进自动探测,兼容仓库内不同文件 |
editor.wrappingIndent | indent | 长行折行时按当前缩进层级续行,便于阅读多行变量(见规则 5) |
editor.autoIndent | full | 回车换行时沿用上级缩进,减少手工调整 |
从仓库实景看,.gitlab-ci.yml 与 build-tools/ci-scripts 下的四个 yml 文件均严格使用 2 空格层级缩进,例如
variables:下的每个键名都比上级多两个空格。这与文档规定完全一致,也是 GitLab 解析 YAML 的前提——GitLab Runner 对缩进错误非常敏感,混用 Tab 与空格会直接导致流水线解析失败。
3. 规则 1:为长构建 job 建立日志备份,规避 GitLab 日志上限
GitLab 对单个 job 的日志有约4 MiB的体积限制。当 Krita 这类大型工程的编译日志溢出该上限时,超出部分会被直接丢弃,排障时便无从查起。因此 HACKING 文档规定:凡是可能溢出日志上限的构建 job,每一个 build step 都要将输出同时写入文件:
job-step.py 2>&1 | tee build-step.log在 job 结束时,将这些.log文件上传为 CI 制品(artifacts)。这样即使 GitLab 在线日志被截断,也能从制品中找回完整日志。
在 Windows 上则使用 PowerShell 风格的等价命令:
job-step.py 2>&1 | Tee-Object -FilePath "build-step.log"这两条命令的原理一致:2>&1先把 stderr 并入 stdout,再交给tee(Linux)或Tee-Object(Windows PowerShell)同时输出到控制台与文件。
3.1 仓库中的实际运用
该规则在平台流水线中已有直接落地,且日志文件会被制品收集逻辑捕获:
- Windows:build-tools/ci-scripts/windows.yml 中每一步都使用
Tee-Object落盘,分别生成build-krita.log、build-installers.log、installers-publish.log; - Linux:build-tools/ci-scripts/linux.yml 中有一段重要注释——GitLab 在处理
tee保存日志时曾出现 job 静默挂起的问题,因此 Linux 端刻意不再手动加日志,这是对规范「因地制宜」的例外; - 制品收集:.gitlab-ci.yml 的
.ci-artifacts-with-packages-mixin将"*.log"及_dmg/*.log(macOS 签名/公证日志)列入artifacts.paths,并设置expire_in: 10 days、when: always,保证日志无论 job 成败都会保留十天。
注意:
job-step.py本身并不在本仓库内,它来自 KDE 的ci-utilities/krita-deps-management外部工具仓(平台 yml 的before_script中会克隆这些仓库)。本仓库内的用法是直接调用该工具配合tee。从源码结构看,Android 流水线(build-tools/ci-scripts/android.yml)同样采用| tee build-krita.log的写法,可见这一模式在 KDE 生态中是跨平台通用的。
4. 规则 2:脚本一律优先 Python3,回避 Windows Batch
Krita 的 CI 脚本被要求优先使用 Python3 编写(只要目标平台支持),并尽量避免使用 Windows Batch(.cmd/.bat)脚本。理由是 Batch 脚本众所周知的不可移植性:它在消费级 Windows 与 Windows Server 上的行为差异巨大,极易在 CI 环境中产生难以排查的偶发问题。
从仓库实景可以印证这一原则:
- build-tools/ci-scripts 下的辅助脚本全部为 Python3 实现,例如
upload-nightly-packages.py、merge-libs-xml.py、move-signing-logs.py、rename-signed-apk-packages.py、show-updates-status.py; - 各平台 yml 中大量直接调用
python3 -u xxx.py,且-u参数保证 stdout 无缓冲、日志实时可见; - Windows 构建链在 build-tools/ci-scripts/windows.yml 中先以
BOOTSTRAP_PYTHON_EXE_WINDOWS(如C:\tools\Python-3.13\python.exe)创建 venv,后续统一使用python -u调用脚本——即连 Windows 上也坚持 Python 而不是 Batch; - 平台差异仅通过条件判断收敛在少数地方,例如 android.yml 中
if [ "$KRITACI_ANDROID_PACKAGE_TYPE" == "nightly" ]这类 shell 条件,而不是写成多份平台专属脚本。
从源码结构可以推断:Krita 团队把「跨平台行为一致性」视为 CI 脚本的首要目标,Python3 + 集中式 Python 工具链是达成该目标的核心手段。
5. 规则 3:YAML 字符串的引号策略——默认不引,特殊情况才引
HACKING 文档对 yml 文件中的字符串给出明确约定:
所有字符串默认不加引号;仅当字符串包含通配符(如
*)或 YAML 控制字符(如 Windows 路径中的:)时,才用引号包裹。
文档自带的对照示例:
windows-build: variables: KDECI_BUILD_TYPE: Release # simple string -> unquoted KDECI_EXTRA_CMAKE_ARGS: -DHIDE_SAFE_ASSERTS=OFF # simple string -> unquoted KDECI_CC_CACHE: "C:\\Gitlab\\Caches\\krita-windows" # Windows path -> quoted linux-build: variables: KDECI_CC_CACHE: /mnt/caches/krita-appimage/ # Linux path -> unquoted这条规范在平台 yml 中得到了忠实执行:
- Windows(build-tools/ci-scripts/windows.yml):
KDECI_CC_CACHE: "Z:\\krita-windows\\caches" KDECI_CACHE_PATH: "Z:\\krita-windows\\artifacts"因为
Z:\...中的冒号:是 YAML 的键值分隔符/控制字符,Windows 路径又含反斜杠转义,所以必须双引号包裹(注意反斜杠需写成\\转义); - Linux/macOS(build-tools/ci-scripts/linux.yml):
KDECI_CC_CACHE: /mnt/krita-appimage/caches/ KDECI_CACHE_PATH: /mnt/krita-appimage/artifacts/纯路径不含特殊字符,直接不加引号;
- 此外,
MACOSX_DEPLOYMENT_TARGET: "10.15"(build-tools/ci-scripts/macos.yml)被引号包裹,因为裸10.15会被 YAML 解析为浮点数而非字符串——这也属于「必须加引号」的隐含场景。
推论:加不加引号的判断标准是「解析安全性」。一旦字符串可能被 YAML 误解析(数字、时间、
:、*通配、特殊符号),就加引号;其余一律裸写,保证文件简洁且 diff 干净。
6. 规则 4:传给 CI 脚本的布尔值必须是非引号的 True / False
Krita 的 CI 脚本通过环境变量接收开关参数,HACKING 文档规定这些布尔开关必须写为不带引号的字符串True/False(注意首字母大写):
windows-build: variables: KDECI_COMPRESS_PACKAGES_ON_DOWNLOAD: False KRITACI_SKIP_UPLOAD_NIGHTLY_PACKAGE: True为什么刻意强调「不带引号」?因为加了引号后 YAML 会保留'False'的字面字符串,而下游脚本(多为 Python)如果按"False"字符串做真值判断,容易与 YAML 原生布尔语义混淆。统一裸写True/False字符串,语义唯一、跨平台稳定。
仓库中的实际使用非常密集,例如:
- build-tools/ci-scripts/linux.yml:
KDECI_COMPRESS_PACKAGES_ON_DOWNLOAD: False、KRITACI_SKIP_UPLOAD_NIGHTLY_PACKAGE: True; - build-tools/ci-scripts/windows.yml:
KDECI_COMPRESS_PACKAGES_ON_DOWNLOAD: False、KDECI_SIGN_BINARIES: False(注释说明只对 nightly 与 release 包签名); - .gitlab-ci.yml 的
.upload-packages-to-cdn-base-mixin:KDECI_ONLY_BUILD: True、KRITACI_SKIP_DEBUG_PACKAGE: False、KRITACI_SKIP_UPLOAD_NIGHTLY_PACKAGE: False、KRITACI_BUILD_INSTALLERS: True; - 也有个别键值使用带引号的
"True"(如 linux.yml 中KDECI_ONLY_BUILD: "True"),从源码结构看这属于历史写法残留,新代码应以文档规定的裸写形式为准。
常见开关含义速查(依据仓库变量命名与使用位置归纳):
| 变量 | 常见取值 | 作用 |
|---|---|---|
KDECI_ONLY_BUILD | True/False | 仅构建不运行测试(macOS 当前因日志泛滥临时启用,见 build-tools/ci-scripts/macos.yml 的 TODO 注释) |
KDECI_BUILD_TYPE | Release/RelWithDebInfo/Debug | CMake 构建类型;发布与 nightly 常为RelWithDebInfo |
KDECI_SIGN_BINARIES | True/False | 是否对二进制签名(仅 nightly/release 打开) |
KRITACI_SKIP_UPLOAD_NIGHTLY_PACKAGE | True/False | 是否跳过向 CDN 上传 nightly 包 |
KRITACI_BUILD_INSTALLERS | True/False | 是否构建安装程序(Windows 的 release job 为True) |
KRITACI_SKIP_DEBUG_PACKAGE | True/False | 是否跳过调试包生成 |
KRITACI_PARALLEL_JOBS | 整数 | 并行 job 数;ASAN 构建降为1以避免 OOM(build-tools/ci-scripts/linux.yml) |
7. 规则 5:多行 CMake 参数用>折叠
当通过环境变量向 CI 脚本传递多个 CMake 选项时,HACKING 文档规定使用 YAML 的块折叠标量>把参数拆成多行,提升可读性与 git diff 的可追踪性:
linux-nightly: variables: KDECI_EXTRA_CMAKE_ARGS: > -DHIDE_SAFE_ASSERTS=OFF -DBUILD_TESTING=OFF>会把后续缩进块中的换行折叠为单个空格,最终环境变量值等价于-DHIDE_SAFE_ASSERTS=OFF -DBUILD_TESTING=OFF。
仓库中的典型用法(含 Qt6 双线构建)来自 build-tools/ci-scripts/linux.yml:
KDECI_EXTRA_CMAKE_ARGS: > -DHIDE_SAFE_ASSERTS=OFF -DBUILD_TESTING=ON -DBUILD_WITH_QT6=ON -DALLOW_UNSTABLE=QT6同类写法还出现在:
- build-tools/ci-scripts/linux.yml 的 nightly job:
-DHIDE_SAFE_ASSERTS=OFF -DBUILD_TESTING=OFF; - build-tools/ci-scripts/linux.yml 的 ASAN weekly job:追加
-DECM_ENABLE_SANITIZERS=address -DENABLE_UPDATERS=OFF; - build-tools/ci-scripts/windows.yml、build-tools/ci-scripts/android.yml、build-tools/ci-scripts/macos.yml 中均有同款折叠。
由此可以看出一个隐含的工程习惯:KDECI_EXTRA_CMAKE_ARGS是向 Krita 的 CMake 构建注入选项的唯一入口,将-DBUILD_WITH_QT6=ON、-DALLOW_UNSTABLE=QT6等关键开关集中放在一处并逐行书写,正是为了 code review 时能一眼看到每个开关的增删。
8. 从规范到流水线:mixin 复用与 job 组合实战
读懂五条规则后,再看 Krita 如何用它们组织出整个流水线,会更有整体感。.gitlab-ci.yml 中定义了大量以.开头的mixin(隐藏 job 模板),通过extends组合复用,这正是规则 0(2 空格缩进)能长期稳定运行的组织基础:
| Mixin | 作用 |
|---|---|
.nightly-job-mixin | 定时流水线(schedule)中KRITACI_SCHEDULED_JOB_NAME == "nightly"时运行 |
.weekly-job-mixin | schedule 中weekly时运行 |
.ci-manual-job-mixin | schedule 与 release 分支永不自动运行,仅手动触发 |
.ci-always-job-mixin | 排除 schedule 与 release 分支后始终运行(普通 MR/分支流水线) |
.ci-release-job-mixin | 仅在release/*分支 push 时手动触发,且interruptible: false(不可被新提交抢占) |
.ci-artifacts-with-packages-mixin | 定义制品与 JUnit/覆盖率报告,包含安装包产物 |
.ci-artifacts-without-packages-mixin | nightly 专用,包已上传 CDN,不再重复存制品 |
.upload-packages-to-cdn-base-mixin | 组合以上两者,设置KRITACI_ONLY_BUILD等上传相关开关 |
组合示例(build-tools/ci-scripts/linux.yml):
linux-build-qt6-nightly: extends: - .linux-qt6-base - .nightly-job-mixin - .upload-packages-to-cdn-base-mixin variables: KDECI_EXTRA_CMAKE_ARGS: > -DHIDE_SAFE_ASSERTS=OFF -DBUILD_TESTING=OFF -DBUILD_WITH_QT6=ON -DALLOW_UNSTABLE=QT6这一小段同时示范了规则 3(KDECI_BUILD_TYPE: Release裸写)、规则 4(布尔值裸写True/False)与规则 5(>折叠多行参数)。各平台作业矩阵如下:
- Linux:
linux-build-qt5/qt6、linux-build-qt5/qt6-nightly、linux-qt5-debug-weekly、linux-qt5-asan-weekly/manual、linux-release-qt5/qt6; - Windows:build-tools/ci-scripts/windows.yml 中
windows-build-qt5/qt6、windows-build-qt5/qt6-nightly、windows-qt5-asan-weekly、windows-release-qt5/qt6,release 包还打开KRITACI_RELEASE_PACKAGE_NAMING: True; - Android:build-tools/ci-scripts/android.yml 针对
x86_64、arm64-v8a、armeabi-v7a三个 ABI 各派生 build/nightly/release 三档 job,并由android-build-appbundle(-release)汇总打 AAB 包; - macOS:build-tools/ci-scripts/macos.yml 走完整的「构建 → 打包 .app → 签名 → 公证 → 打包 .dmg → 再签名 → 再公证 → 上传」链路,每一步都配
tee日志(对应规则 1)。
9. 总结
HACKING.gitlab-ci.md虽然只有短短六条规则,却是理解 Krita CI 全貌的钥匙。把五条规范与仓库实景对应起来,可以得到一套可复用的工程结论:
- 缩进即纪律:YAML 一律 2 空格,与 C++ 代码刻意区分,用编辑器配置(
formatOnSave: false)守住它; - 日志即证据:长 job 必须
tee落盘并作为制品保留,Windows 用Tee-Object,同时要留意 Linux 上 GitLab 对tee的已知挂起问题(build-tools/ci-scripts/linux.yml); - 脚本即语言:优先 Python3,用
-u保证日志实时,彻底回避 Batch; - 字符串引号按需:默认裸写,仅在含
:、*、数字语义等解析风险时加引号(Windows 路径"Z:\\..."是标准反面教材式示例); - 布尔与多行有固定写法:布尔裸写
True/False,多行 CMake 参数用>折叠并经KDECI_EXTRA_CMAKE_ARGS注入。
当你为 Krita(或同类 KDE 生态项目)新增一个 CI job 时,只需照此约定:用 2 空格写出 mixin 组合,按需声明KDECI_*/KRITACI_*变量,把每一步包进tee日志,并让脚本与参数写法严格遵循上述五条规则——这既是 Krita 团队内部的可读性要求,也是让 CI 问题可定位、可追溯、跨平台可复现的最短路径。
进一步查阅材料:流水线入口 .gitlab-ci.yml、平台作业定义 build-tools/ci-scripts/linux.yml、build-tools/ci-scripts/windows.yml、build-tools/ci-scripts/android.yml、build-tools/ci-scripts/macos.yml,以及规范原文 HACKING.gitlab-ci.md。
- 图形学
- 桌面应用
【免费下载链接】krita
Krita is a free and open source cross-platform application that offers an end-to-end solution for creating digital art files from scratch built on the KDE and Qt frameworks.
相关推荐
Flame多平台构建:CI/CD流水线自动化
Flame多平台构建:CI/CD流水线自动化 概述 Flame作为基于Flutter的游戏引擎,支持多平台构建是其核心优势之一。本文将深入探讨如何为Flame项
游戏开发图形学终极指南:OpenCore Legacy Patcher让老款Mac完美运行最新macOS系统
终极指南:OpenCore Legacy Patcher让老款Mac完美运行最新macOS系统 还在为老款Mac无法升级最新macOS而烦恼吗?当你的设备提示"
操作系统固件驱动开发突破架构壁垒:GitLab CI+buildx打造跨平台Docker镜像构建流水线
突破架构壁垒:GitLab CI+buildx打造跨平台Docker镜像构建流水线 你是否还在为多架构Docker镜像构建烦恼?手动适配不同CPU架构、重复编写
云原生DevOps
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考