Slang AGENTS.md 深度解读:面向 AI 代理的编译器仓库工程规范、构建测试流程与缺陷修复方法论
【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang
AGENTS.md 是 Slang(shader-slang/slang,一个以 C++20 与 CMake 实现的着色语言编译器)仓库根目录下的"仓库工程规范"文档,它既是人类贡献者的协作契约,也是 AI 编程代理在该仓库中工作时的事实标准操作手册。本文完整梳理该文档覆盖的九大主题——项目结构、仓库本地 Skills、平台工具链选择、构建与测试命令、include 路径约定、编码风格与评审惯例、Shell 脚本可移植性、测试指南、以及独具特色的"原则化缺陷修复方法论"与五段式 PR 描述格式,并结合仓库内 CMakePresets.json、.clang-format、source/core/CMakeLists.txt 等真实文件逐项印证。读完后,你将掌握在 Slang 仓库中正确配置构建、运行并行测试套件、遵循命名与 include 规范,以及如何按"修根因、不打补丁"的原则完成一次编译器变更评审。
一、AGENTS.md 的定位:仓库级协作契约
AGENTS.md 采用 CC-BY-4.0 许可(文件头部的 SPDX 声明表明版权归 Khronos Group 所有)。与一般的 README 不同,它不介绍项目是什么,而是规定"在这个仓库里应当如何工作":目录如何组织、命令如何执行、代码如何书写、缺陷如何定位、PR 如何撰写。文档中多处内容明确面向自动化代理场景(例如 WSL 环境下的工具选择规则),这也是当前大型 C++ 开源项目中常见的"Agent 友好型"仓库治理实践。
二、项目结构与模块组织
AGENTS.md 开宗明义:Slang 是一个以 C++20 实现、使用 CMake 构建的着色语言编译器与运行时。文档列出的关键目录如下,均与仓库实际布局一致:
| 目录 | 职责 |
|---|---|
| source/ | 核心实现,包括source/slang/(编译器主体)、source/core/(基础库)、source/compiler-core/(词法/IR/下游编译器等),以及source/slangc/命令行工具 |
| include/ | 公共 API 头文件(如slang.h、slang-gfx.h) |
| prelude/ 与 source/standard-modules/ | 标准/前导头文件,即编译器生成的各目标语言前置代码与内建模块 |
| tests/ | 按功能或目标分组组织的测试套件(tests/diagnostics/、tests/hlsl-intrinsic/、tests/spirv/等) |
| tools/ | 测试基础设施与开发者工具(slang-test、slang-unit-test、gfx等) |
| docs/ | 文档,包括 docs/building.md 构建指南与 docs/design/coding-conventions.md 编码约定 |
| examples/ | 可运行示例(hello-world、ray-tracing、mlp-training等) |
| cmake/ | CMake 辅助脚本(SlangTarget.cmake、AutoOption.cmake等) |
| external/ | 以子模块形式 vendored 的第三方依赖(glslang、spirv-tools、llvm 相关等) |
理解这张目录地图是后续所有操作的前提:include 路径约定、测试放置位置、格式化脚本作用范围,全部以这些目录为锚点。
三、仓库本地 Skills:.claude/skills/
文档规定:本仓库在.claude/skills/下存放本地 agent skills,且Codex 及其他非 Claude 的代理框架在用户请求相关工作流时,也应查阅这些SKILL.md文件——即 skills 不绑定单一代理平台。
经核实,.claude/skills/ 目录下实际存在 11 个技能,每个目录内均有SKILL.md。AGENTS.md 点名的是七个评审(review)相关技能,构成一条"生成候选 → 合并去重 → 范围过滤 → 解决存疑项 → 发布"的流水线:
slang-review-clarity-workflow:协调端到端的清晰度评审工作流;slang-review-clarity:生成高层清晰度与可解释性评审候选项;slang-review-fine-grained-clarity:逐行生成命名/注释/类型/函数一致性评审候选项;slang-review-consolidate-candidates:合并候选文件,解决重复、重叠与被取代的评论;slang-review-scope-filter:保守地过滤候选评论,只保留 PR 作者能够合理负责的条目后再发布;slang-review-resolve-judgment-calls:在发布前对不确定的候选项做聚焦的后续分析;slang-review-post-github:将过滤后的候选项作为一条规范的 GitHub PR 评审发布。
目录中还存放着文档未列出的其他技能(如slang-release-process、repro-remix、slangpy-debug),说明该目录是持续扩展的仓库级工作流知识库。
四、平台工具链选择:WSL/Windows 与原生 Linux/macOS
AGENTS.md 用两节专门约束跨平台工具选择,这在 WSL 环境下维护 C++ 编译器项目时极具实战价值。
WSL 上的规则
当从 Windows 的 WSL 中工作时,默认使用 Windows 原生开发工具(除非用户明确要求 WSL/Linux 版本):
- 使用
git.exe而非裸git。文档给出的理由是:这些 worktree 使用 Windows 路径约定,WSL 侧的 Git 可能损坏或误判 worktree 状态,且 Windows Git 在此 checkout 上文件 I/O 性能更好; - 当
slang-build技能调用 CMake 时,使用cmake.exe而非裸cmake——Windows 版 CMake 能找到vs2026preset 所需的 Visual Studio 2026 与 Windows 工具链(该 preset 在 CMakePresets.json 中确实存在,generator为Visual Studio 18 2026); - 需要与 Windows 原生 Git 共享同一凭证上下文时,使用
gh.exe而非裸gh; - 传参前转换路径:WSL 路径传给 Windows 工具前先
wslpath -w "$path";Windows 工具输出的路径在 shell 中使用前先wslpath -u "$win_path"; - 若所需
.exe工具不可用,应停下来报告,而不是静默回退到 WSL/Linux 版本工具。这条"禁止静默降级"的规则对代理尤为关键。
原生 Linux 与 macOS 的规则
在原生 Linux 或 macOS 上,则直接使用平台原生工具,不带.exe后缀:用git、gh、cmake、python3,而不是git.exe等。两条规则互为镜像,核心思想是让工具与文件系统的宿主保持一致。
五、构建、测试与开发命令
5.1 构建入口:slang-build技能与回退文档
文档明确:Slang 的构建配置是平台相关的(尤其在 WSL 下)。构建编译器时应使用独立shader-slang/slang-skills仓库中skills/slang-build的slang-build技能,而不是照搬本文件中的硬编码命令。技能提供的用法示例:
/slang-build build debug # 构建 Debug 配置 /slang-build rebuild debug # 丢弃已有 build 目录后重建 Debug /slang-build configure releasewithdebug # 配置带符号的优化构建 /slang-build clean # 重命名并删除已有 build 目录文档特别强调:不要从通用 Linux 指令推断 WSL 构建命令,必须遵循技能中定义的平台探测、宿主工具选择、CMake preset 选择与干净构建步骤。当技能因无法安装或网络受限而不可用时,回退到 docs/building.md 作为构建参考——该文档给出了 TLDR 命令cmake --workflow --preset release,以及 CMake 3.25+ 下cmake --preset default+cmake --build --preset releaseWithDebugInfo的标准流程、vs2019/vs2022/vs2026等 Visual Studio preset、自定义编译标志覆盖(-DCMAKE_CXX_FLAGS_DEBUG="-O0 -g3"等)和CMakeUserPresets.json用法。
5.2 CMake Presets 全景(仓库证据)
CMakePresets.json(version 6,要求 CMake 3.25.0+)是上述命令的落地。从配置 preset 看:
default:Ninja Multi-Config 生成器,输出到${sourceDir}/build,一次配置四种配置类型(Debug;Release;RelWithDebInfo;MinSizeRel),Debug 下开启SLANG_ENABLE_IR_BREAK_ALLOC;vs2019/vs2022/vs2026及对应*-dev变体:*-dev额外设置SLANG_ENABLE_IR_BREAK_ALLOC: TRUE(一种 IR 内存破坏检测的调试辅助),其中vs2022-dev输出到build/windows-vs2022-dev;emscripten:Wasm 构建,关闭 GFX/CUDA/OptiX/Replayer 等可选组件并禁用 LLVM 后端;android-arm64/android-x86_64:基于 NDK toolchain(ANDROID_PLATFORM=android-31)的移动端构建;slang-llvm(USE_SYSTEM_LLVM)、generators(构建期代码生成器)、coverage(SLANG_ENABLE_COVERAGE)。
build presets 与 AGENTS.md 提到的构建配置一一对应:debug、release、releaseWithDebugInfo、minSizeRel等;workflow presets 则将 configure → build → package 串成一条cmake --workflow流水线。
5.3 运行测试:slang-test与并行测试服务器
构建完成后,从仓库根目录用所选配置目录中生成的slang-test二进制运行测试:
# 运行 Debug 测试套件 build/Debug/bin/slang-test # 使用测试服务器并行运行带符号的优化测试 build/RelWithDebInfo/bin/slang-test -use-test-server -server-count 8 # 并行运行 Release 测试 build/Release/bin/slang-test -use-test-server -server-count 8在 Windows 宿主构建中,若生成的二进制带后缀则加上.exe。从源码看,这两个参数在 tools/slang-test/options.cpp 中定义:-use-test-server启用"通过测试服务器运行测试",-server-count <n>设置服务器数量(默认 1),与 tools/test-server/ 目录配套——这正是大测试套件能通过多进程并行显著缩短耗时的机制。
六、Include 路径约定:直连路径优先于相对跳转
AGENTS.md 规定#include指令优先使用直连路径而非../相对跳转。原因在 source/core/CMakeLists.txt 中可以找到直接证据:core静态库目标通过INCLUDE_DIRECTORIES_PUBLIC把${slang_SOURCE_DIR}/source与${slang_SOURCE_DIR}/include加入了公共 include 路径,因此跨模块头文件无需../即可触达:
// 新代码中的首选形式 #include "core/slang-string.h" #include "compiler-core/slang-source-loc.h" // 存量代码仍是相对形式;不要仅为风格而修改 #include "../core/slang-string.h" #include "../compiler-core/slang-source-loc.h"处理原则是典型的渐进式迁移:新文件一律使用直连路径;存量文件不因风格问题被强制改写,但在因其他原因(如安全修复、新功能大量触改)实质性修改该文件时,可以"顺手"更新。
七、编码风格与命名约定
7.1 格式化
- C/C++/头文件与 Slang 文件统一使用4 空格缩进;
- 提交前运行 ./extras/formatting.sh 应用 .clang-format 与 .editorconfig 中的规则;
- 风格要点:Allman 大括号、100 列限制、左对齐指针、文件末尾换行。
仓库中的 .clang-format 完整给出了机器可读的规则:BasedOnStyle: LLVM基础上IndentWidth: 4、ColumnLimit: 100、BreakBeforeBraces: Allman、PointerAlignment: Left,以及BinPackArguments: false、AlignCaseBlocks: true等细节;.editorconfig 则约束编辑器侧行为——c/cpp/h/slang文件使用 UTF-8、4 空格缩进、补末尾换行。两份配置与文档文字描述完全吻合。
7.2 通用约定
- 遵循 docs/design/coding-conventions.md;
- 普通错误处理中避免 STL 容器、iostreams、RTTI 与异常——这是编译器这类基础设施项目控制二进制尺寸与错误处理确定性的常见取舍;
- 类型用
UpperCamelCase,值用lowerCamelCase; - 宏用
SLANG_前缀的SCREAMING_SNAKE_CASE; - 注释优先解释"代码为什么存在"。
7.3 评审惯例:用文档化的"高频评审反馈"避免返工
文档专门列出"反复出现的评审意见",遵循它们即可减少评审轮次,这是极具信息量的实战清单:
- 函数注释用完整句子:先说做什么,非显而易见时再说为什么;非平凡逻辑要附具体示例;
- 解释性注释采用会话式(conversational)风格:偏好 "Consider this example:" 后接相关用户代码,避免 "Full source shape"、"AST trace"、"IR trace" 这类抽象标签;示例之后用自然语言逐步说明——哪个 producer 构造了该 AST/IR/值形态、这段代码维护什么不变量、哪个下游 consumer 依赖它;示例要包含足够的原始用户代码,使读者无需凭记忆重建周边程序;
- 先复用再新写:新增 helper 前先查共享头文件(
slang-ast-type.h、slang-ir-util.h、各*-util.h)是否已有现成工具(例如isDeclRefTypeOf<T>);逻辑确实新时,应提取为有命名、有文档的 helper,而不是内联 lambda 或长代码块; - 映射/分类保持单一事实来源,并删除重构后不可达的分支与回退路径;
- 不要为已有表示的值再造第二套 AST/IR/
Val表示(会破坏equals/去重),应在构造点用SLANG_ASSERT守护此类不变量; - 对违约输入使用
SLANG_RELEASE_ASSERT,而不是静默返回默认值。
八、Shell 脚本:bash 3.2 可移植性硬约束
文档要求extras/下(及其他仓库 shell 脚本)必须能在 bash 3.2 上运行——这是 Apple 在 macOS 上/bin/bash的实际版本。明令禁止的 bash 4+ 特性包括:${var,,}/${var^^}大小写转换、关联数组(declare -A)、mapfile/readarray、namerefs(local -n);替代方案示例:用小写转换时用tr '[:upper:]' '[:lower:]'。验证方式为在系统 bash 下执行bash -n script.sh。
extras/formatting.sh 本身就是这条约束的活样本:脚本开头显式解析BASH_VERSINFO,版本低于 3.2 时报错退出,并在检测到Darwin时提示用 Homebrew 安装新版 bash。
九、测试指南
- 新测试放在 tests/ 中相关覆盖附近的目录(按功能/目标分组,如
tests/diagnostics/、tests/hlsl-intrinsic/); - Slang 测试使用前导指令(directive),如
//TEST(smoke):SIMPLE:(仓库中的实际测试以该体系派生出//DIAGNOSTIC_TEST(smoke):SIMPLE(diag=CHK):-target spirv ...等变体,如 tests/diagnostics/call-argument-type.slang); //DISABLE_TEST只允许伴随明确理由使用;- 定向运行传前缀,例如
build/Debug/bin/slang-test tests/diagnostics/my-test; - C++ 单元测试位于 tools/slang-unit-test/,惯例使用
SLANG_UNIT_TEST(name)宏(如 tools/slang-unit-test/unit-test-allocator.cpp 中的SLANG_UNIT_TEST(defaultAllocator))。
十、问题解决方法论:走原则化路径,而非最小编辑距离路径
这是 AGENTS.md 中最具思想性的一节,明确反对"最小改动距离"式的补丁思维。
10.1 核心原则
- 修根因,不修症状:一个在 emit/codegen 阶段显现的 bug,通常源自上游(某个 IR pass、lowering、类型合法化、特化,或 AST/IR 表示本身),应追到那里;
- 质疑每一处改动:如果你说不出"哪个测试在没有该改动时会失败",这个改动大概率不该存在;同时反问问题是否在提示方向/表示本身有缺陷;
- 不要掩盖:为畸形 AST/IR/witness-table 数据打掩护的守卫、空检查或特例,是遮住表示层 bug 的创可贴——应把表示修对,让消费者保持简单;
- 审问输入形态:对处理特定输入形态(AST 节点、IR inst、witness、类型……)的代码,永远先问"该形态本身是否正确、原则化?还是上游 producer 应该修?"形态错误就修 producer;只有形态确实是合法输入时才在本地处理,并把结论写进 PR 描述(Process report);
- 对概念上无序的 key→value 数据(witness-table / interface 需求条目),按角色/键处理,绝不按位置/索引;
- 全程维护工作日志:问题与动机示例、问题如何级联(一个修复暴露下一个)、每个修复及其原则化理由(附代码追踪)、被否决的替代方案;日志最终浓缩进 PR 描述,但不提交。
10.2 非原则化改动的自我评审清单
对任何非平凡的编译器变更定稿前,应把 diff 当作"是否在补偿一套糟糕的 AST/IR/Val/witness 表示"来审。文档列出七类"高风险模式",在证明其处于正确层级之前一律视为高危:
- 对
DeclRef/Val/Type/Witness或 IR 形态新引入的自定义等价关系(形如are...Equivalent、does...Match、try...Match的递归 helper)——先问为什么既有的substitute、resolve、getCanonicalType、equals或既有规范化构造器不能让两个值天然一致; - 只为让一个失败测试通过而存在的新 helper/回退/"try..." 函数——每个新 helper 都要审计:如果它重复做了替换、解析、AST 拷贝、泛型求解、查找或 lowering,多半是在掩盖真正的不变量破坏;
- 把已检查的语义数据重新变回语法的代码(如从
Val/Type/DeclRef/witness 重建Expr或TypeExp)——已检查的语义字段通常应保留为事实来源;重建语法是 producer 或 copier 存错表示的强烈信号; - 遍历任意操作数图、替换链、witness 链或查找路径以"重新发现"上下文(泛型实参、需求键、规范路径、父声明)的代码——producer 通常应直接存储或构造规范形态;
- 在 lowering/emit/特化/typeflow 中修补前一阶段畸形 AST/IR 形态的逻辑——这些消费者应当是简单的;若需要针对前端表示"意外"的目标特定知识,应去追 producer;
- 硬编码特定
DeclRef子类、内建魔法类型名、泛型实参索引、witness-table 条目顺序、嵌套/扁平特化形态的知识——此类代码需要强不变量支撑,且通常应位于规范化构造边界; - 对"不可能"形态静默返回默认值的守卫——形态确实违约就用断言;否则说明该形态为何是合法输入并补充测试覆盖。
评审执行方式:先对 diff 中每个新增 helper/回退/特例做清单盘点,逐项记录"保留、回退、还是需要 producer 侧修复";对每个被标记的改动,在保留之前先完成六步"输入形态审计":
- 到达这段代码的确切形态是什么?给出具体示例与产生它的函数;
- 该形态是规范且被有意允许的,还是意外的替代写法?
- 若是意外的,能否修 producer 使下游直接走既有
substitute/resolve/规范化路径? - 已有的语义事实来源是什么?这段代码是否在从它重建语法/结构形态而非保持它?
- 移除该改动后哪个测试失败?该测试能否证明这一层就是责任方?条件允许时做回退演练(revert drill):删掉 helper/特例,跑最小的失败测试,用失败定位真正的 producer-consumer 断裂;
- 该特例能否被"断言 + producer 侧修复"或复用既有 helper 取代?
结论底线:不能仅因"让测试通过了"就保留被标记的改动。若确有必要保留,PR 描述的 Process report 必须论证该输入形态为何合法、为何这一层拥有这段逻辑,并给出从 producer 到 consumer 的代码追踪。
十一、提交与 PR 指南
11.1 提交与合入要求
- commit 主题简短、祈使句,例如
Reject invalid descriptor heap access; - PR 保持小粒度,基于
master; - 合入要求:工作流(workflow)通过、评审批准、打上
pr: non-breaking或pr: breaking change标签;人类贡献者在被提示时签署 CLA; - 格式化失败时:运行 ./extras/install-git-hooks.sh 安装的钩子,或请求格式机器人(
/format)。
11.2 五段式 PR 描述格式
PR 描述按固定五段撰写,且写作对象是"脑中不持有全部上下文的评审者",采用与代码注释相同的会话式文风:从具体用户代码示例出发,贴出完整的相关片段而非仅类型或函数名,按逻辑顺序解释每一步,说明编译器构造了什么、该表示如何流经具名函数或 IR 指令、所选修复为何保持住了不变量;避免 "AST trace" 这类干瘪标题。
- Motivation——问题本身,附具体示例/动机测试用例;
- Proposed solution——方案及其原则化理由;
- Change summary——触及的文件/区域及各自作用;
- Concepts and vocabulary——介于 change summary 与 process report 之间的短词汇表,只复述报告所依赖的代码库特有或微妙术语(如 witness、facet、fixpoint solver、修复所依赖的某个非显而易见的区分)作为提醒;基础且众所周知的概念(interface、associated type)不必解释——默认评审者已知;
- Process report——为每处改动给出逻辑理由。对级联问题的修复,描述问题(附动机测试用例)并用代码追踪(涉及的确切函数/inst)论证修复为何必要且原则化、而非权宜之计;任何处理、守卫或特例化某个输入形态的改动,必须回答第十节方法论中的"输入形态检查"——该形态是否正确原则化、还是应修 producer——以便评审者确认修复处于正确层级。
十二、小结
AGENTS.md 的价值在于把"如何在这个仓库里高效且低摩擦地工作"沉淀为可执行文本:目录地图与 include 约定解决"代码在哪、怎么引用";skills 与构建命令解决"怎么编译和测试";格式化与命名规则解决"代码长什么样";而"原则化修复方法论 + 输入形态审计 + 五段式 PR"则解决编译器开发中最难的"改动该落在哪一层"问题。对贡献者而言,逐条对照本文即可对齐仓库预期;对 AI 代理而言,这份文档本身就是其行为边界的权威定义。
【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考