Slang 构建依赖图文档的评审修复:子系统粒度、链接不变量与生成式架构文档的质量闭环
【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang
导读
本文围绕 Slang 开源仓库中 docs/generated/design/architecture/dependency-graph.md 及其评审修复报告 dependency-graph.md.remediation.md 展开,完整还原这份"子系统级构建依赖图"文档的成文逻辑、CMake 证据链,以及一次真实的"评审 → 修复"质量闭环:三个评审发现(F-001/F-002/F-003)如何被逐条核实并修复。读完本文,你将掌握 Slang 源码树中source/各子系统之间的静态链接关系、四个生成代码目标的真实身份,以及SLANG_EMBED_CORE_MODULE等关键 CMake 选项对构建结构的影响;同时理解该仓库如何用"机器可校验的生成式文档"防止架构文档与源码漂移。
一、背景:生成式架构文档与"评审 → 修复"闭环
Slang 项目维护了一套由 AI 代理生成、经脚本驱动的架构文档,位于docs/generated/design/下。这类文档不是手写草稿,而是由 regenerate.md 描述的流水线产出:
- 每份文档对应一份提示词模板(如 architecture-dependency-graph.md),模板定义文档必须包含的章节、粒度规则与质量清单;
- 每个文档有"被监视路径"(watched paths)与内容摘要(digest),
regenerate.py list-stale可以判定文档是missing、stale还是fresh; - 文档头部 front-matter 记录
source_commit、watched_paths_digest,并带有警告"Auto-generated. May drift from source. Do not edit by hand."——意味着文档只允许重新生成,不允许手工修补。
在这套体系之上,还有一个显式的质量关卡:评审报告(review)与修复报告(remediation)。本主题的修复报告由claude-opus-5于2026-08-04T09:06:00Z生成,针对的评审报告来自gpt-5.6-sol(dependency-graph.md.review.md),修复前后的源码提交均为53b76e6d3009b8e6434d41573524c7ce5c499d23,动作统计为fixed: 3,其余(拒绝伪发现、超出范围、延迟、升级)均为 0——即三个发现全部属实并已修复。修复报告的结构规范见 _remediate.md,要求以表格逐条给出 Finding ID、Action、Rationale 与 Fix summary,动作计数必须与评审报告的finding_count一致。
二、被评审的文档讲了什么:子系统级构建依赖图
2.1 粒度定义:子系统级,而非文件级
依赖图文档的核心定位是:预测修改某个子系统时会波及其他哪些子系统。其粒度被严格限定为"子系统级"——一个节点对应一个source/<subsystem>/目录,而不是单个文件。文件级清单由 module-map.md 承担,文档开篇即明确两者的分工:
- 依赖图(本文主题):
source/下各子系统之间的静态链接依赖; - 模块映射(module-map.md):每个子系统内文件的逻辑单元与职责。
这份文档的边并非拍脑袋画出来的,而是逐条从各目录CMakeLists.txt的slang_add_target(... LINK_WITH_PRIVATE ...)与LINK_WITH_PUBLIC子句中推导得到。提示词模板 architecture-dependency-graph.md 的硬性要求包括:
- 图中每个节点必须对应
source/下的目录或module-map.md中的标题(模板第 42-44 行); - 每条边必须有
CMakeLists.txt引用作为依据,禁止发明构建文件未证实的边; - Mermaid 语法遵循项目约定(camelCase 节点 ID、节点名不含空格、不着色);
- 文档体积不得超过 16 KB。
2.2 依赖图全貌(修复后的最终形态)
修复后的 Mermaid 图只保留真正的子系统节点,外部依赖(miniz、lz4_static、Threads::Threads、unordered_dense、fast_float、SPIRV-Headers、SPIRV-Tools-opt、SPIRV-Tools-link、SPIRV、glslang、${CMAKE_DL_LIBS})全部从图中省略,仅在节点注释中概述,以保持图聚焦于项目内部结构:
注意其中两条特殊边:
coreModule -->|generated targets| slangLib是一条带标签的实线边,语义并非"slang-core-module 链接了编译器库",而是它链接了source/slang/所拥有的生成产物(详见 3.1 节 F-001 的修复);slangLib -.->|source include| slangRecordReplay是虚线边,它不是LINK_WITH_*链接关系,而是源文件并入关系。
三个在 module-map.md 中存在、但在图中没有普通链接边的子系统也需要特别说明:
source/standard-modules/:其 CMakeLists.txt 只configure_file一个配置头并add_subdirectoryneural、experimental、numerics三个模块,不声明自己的链接目标,模块产物以独立的.slang-module文件形式发布;source/slang-record-replay/:没有自己的CMakeLists.txt,源码通过source/slang/CMakeLists.txt中的EXTRA_SOURCE_DIRS ${SLANG_RECORD_REPLAY_SYSTEM}直接并入slang目标(即图中的虚线边);source/slang-llvm/:同样没有自己的CMakeLists.txt,slang-llvm在树外构建(或下载预编译二进制,由根 CMakeLists.txt 第 385-401 行的SLANG_SLANG_LLVM_FLAVOR控制),源码树内没有任何目标直接链接它。
三、三个评审发现与修复:从"看起来对"到"逐条可核实"
这是本主题修复报告的核心。评审报告发现 3 个问题(1 个 major、2 个 minor),修复报告全部核实并修复。下面逐条还原"问题 → 证据 → 修复"。
3.1 F-001(major):生成代码 target 混入子系统图
问题:原图中slang-fiddle-output、slang-capability-defs、slang-capability-lookup、slang-lookup-tables被画成了独立节点。但它们是定义在source/slang/内部的 CMake 构建目标,既不是source/下的子系统目录,也不是module-map.md的标题,违反了提示词"每个节点必须对应 source 目录或 module-map 标题"的节点覆盖规则,导致图混用了"目标级"与"子系统级"两种抽象。
证据:评审报告核实四个目标分别定义于 source/slang/CMakeLists.txt 的slang-fiddle-output(第 56-66 行,INTERFACE 库,由slang-fiddle工具生成 AST/IR 支持代码)、能力相关目标(第 119-143 行区域)与slang-lookup-tables(第 198-210 行,OBJECT 库)。从源码可以进一步确认它们的生成机制:
slang-fiddle-output:由自定义命令驱动slang-fiddle工具,把*.lua与 FIDDLE 输入生成到SLANG_FIDDLE_OUTPUT_DIR,再用一个.fiddle.stamp时间戳文件作为产出标记,避免陈旧 mtime 干扰增量构建(source/slang/CMakeLists.txt);slang-capability-defs/slang-capability-lookup:由slang-capability-generator从*.capdef生成能力表头文件与查找源码(slang-generated-capability-defs.h、slang-lookup-capability-defs.cpp等),生成时还会同步刷新 a4-02-reference-capability-atoms.md 这份用户文档;slang-lookup-tables:由slang-spirv-embed-generator从 SPIR-V 核心文法 JSON 生成查表源码,是 OBJECT 库,LINK_WITH_PRIVATE core SPIRV-Headers::SPIRV-Headers。
修复:从图中移除这 4 个节点及其 14 条边,改为在图后以文字段落描述它们及其消费者(slang与slang-wasm都消费这些生成目标);新增coreModule → slangLib的"generated targets"标签边,把slang-core-module对source/slang/生成产物的依赖显式化——因为 source/slang-core-module/CMakeLists.txt 第 60-64 行的LINK_WITH_PRIVATE列表里同时含有core、slang-capability-defs和slang-fiddle-output,也就是说它依赖source/slang/拥有的生成产物,却并不链接编译器库本身;同时把## Edge citations表格中原来逐 target 的 4 行折叠,并改写slang与slang-wasm两行的措辞。修复后文档从 16384 字节上限内的 10661 字节变为 12275 字节,regenerate.py lint通过。
3.2 F-002(minor):源归属不变量在嵌入式构建下不成立
问题:原文档断言主库slang是"唯一拉入 AST/IR/emit/check 源码的目标"(the only target)。当SLANG_EMBED_CORE_MODULE开启时这个说法是错的。
证据:从 source/slang/CMakeLists.txt 可以看到两条构建路径的分叉:
SLANG_EMBED_CORE_MODULE关闭时:直接slang_add_target(. ${SLANG_LIB_TYPE} ...)正常构建slang,源文件由slang自己持有,slang-without-embedded-core-module只是它的 ALIAS;SLANG_EMBED_CORE_MODULE开启时:第 322-329 行先以.为源目录声明一个 OBJECT 库slang-common-objects,把整目录源码编译成对象文件;随后第 330-358 行声明的两个库目标slang-without-embedded-core-module与主slang均带NO_SOURCE,只通过LINK_WITH_PRIVATE slang-common-objects链接这些对象。
换言之,真正持有 AST/IR/emit/check 源码的"源归属目标"在两种模式下不同。
修复:把不变量的表述从"目标级"降为"子系统级",明确写出:非嵌入式构建中源归属目标是slang,SLANG_EMBED_CORE_MODULE开启时则是slang-common-objects。这也与文档 "Cycles and known irregularities" 一节中关于slang-common-objects间接层的描述(同一批源文件被编译成对象库后,再重链接进两个库,以便随编译器一同发布"无嵌入式 core module 的生成器")保持一致,消除了文档内部的自相矛盾。
顺带一提,同文件中slang目标的链接清单(第 270-281 行)把core、prelude、compiler-core、slang-capability-defs、slang-capability-lookup、slang-fiddle-output、slang-lookup-tables、SPIRV-Headers、libcmark-gfm全部列为LINK_WITH_PRIVATE——这正是图中slang → {core, prelude, compiler-core, core-module}多条边以及"生成目标消费关系"的直接依据(其中prelude实际是私有 include 依赖而非静态链接,文档专门注明这一点以与 module-map.md 对齐)。
3.3 F-003(minor):过时的根 CMake 行号引用
问题:原文档在slang-llvm注释中把SLANG_SLANG_LLVM_FLAVOR说成位于根CMakeLists.txt"around line 366",实际行号偏差约 20 行。
证据:评审报告核实根 CMakeLists.txt 第 366 行声明的是SLANG_ENABLE_RELEASE_DEBUG_INFO;SLANG_SLANG_LLVM_FLAVOR是第 386 行的enum_option标识符,其处理逻辑延伸到第 401 行。
修复:把引用改为"lines 385-401"。这个细节看似微小,但对机器校验驱动的文档体系意义重大——行号是评审与再生成时核对的重点,过期行号会让后续自动化核对产生误报。
四、修复后沉淀的构建不变量:可逐条对证的架构规则
修复后的## Notable invariants一节给出若干方向性约束,每一条都有具体的构建文件背书:
source/core/不依赖任何内部子系统。从 source/core/CMakeLists.txt 可见其LINK_WITH_PRIVATE只列外部库(miniz lz4_static Threads::Threads ${CMAKE_DL_LIBS}),LINK_WITH_PUBLIC只有unordered_dense;source/compiler-core/可依赖source/core/,但不得依赖source/slang/。其 CMakeLists.txt 只有LINK_WITH_PRIVATE core fast_float(fast_float用于快速浮点解析);source/slang/是唯一拉入 AST/IR/emit/check 源码的子系统(具体源归属目标见 3.2 节的两种模式);其他需要编译服务的二进制(如slangc,见 source/slangc/CMakeLists.txt 的LINK_WITH_PRIVATE core slang)都链接slang而不是逐文件接入;- 能力子系统拆分为两个库:
slang-capability-defs(生成的头文件库)与slang-capability-lookup(生成的源码库),主slang目标同时消费两者; - 核心模块可选链接:
SLANG_EMBED_CORE_MODULE通过 source/slang/CMakeLists.txt 的生成器表达式在slang-embedded-core-module与slang-no-embedded-core-module之间选择;当该选项关闭且SLANG_LIB_TYPE为SHARED时,同文件还会新增generate_core_module_cache目标,用slang-core-module-cache工具处理新链接的库与source/slang-core-module/产出的core_module_archive_without_timestamp归档,在库旁写出slang-core-module.bin——这是对tools/下目标的构建顺序依赖而非链接边,且把库文件的时间戳纳入缓存有效性; slang-rt不依赖编译器:它随 CPU 目标输出一起发布,LINK_WITH_PRIVATE中没有任何编译器内部库;但"不链接"不等于"源码无关"——其 CMakeLists.txt 通过EXTRA_SOURCE_DIRS ${slang_SOURCE_DIR}/source/core把source/core/的源码以SLANG_RT_DYNAMIC_EXPORT重新编译进运行时,并配置INCLUDE_DIRECTORIES_PRIVATE ${slang_SOURCE_DIR}/source使这些源码能解析#include "core/slang-basic.h"这类直连路径包含;slang-glslang的导出面由一份文件限定,而非编译器可见性设置:CXX_VISIBILITY_PRESET hidden与-Wl,--exclude-libs,ALL只能隐藏自身与静态链接依赖的非导出符号,真正"一锤定音"的是slang-glslang.version-script。ELF 直接消费该文件;Mach-O 没有 version-script 概念,因此同一份 CMake 在 configure 阶段解析脚本的global:块,推导出-exported_symbols_list(每个符号加 ld64 前缀下划线,如glslang_compile→_glslang_compile),并且解析逻辑被写成"宁可报错也不静默漏导出"——提取不到任何名字、或移除name;条目后还有残留字符时都会message(FATAL_ERROR)。对贡献者的实际含义记录在 shim 头文件注释中:新增导出入口必须同时加入 version-script,否则在 ELF 与 macOS 上都不会被导出;include/公共头不得包含source/私有头:这是项目规则而非构建系统约束(见 CLAUDE.md),遵守它才能保证下游用户只需消费include/slang.h。
五、循环与已知异常
评审与修复都确认:各目录 CMake 文件中未观察到链接级循环(文档明确写出 "No link-level cycles are observed")。
但有两处值得知道的"异常":
slang库向上侵入 tools 树取头文件:source/slang/CMakeLists.txt 把${slang_SOURCE_DIR}/tools加入INCLUDE_DIRECTORIES_PRIVATE,这让slang-language-server.cpp能编译#include "platform/performance-counter.h"(来自 tools/platform)。没有伴随链接边——头文件只用于其内联定义——但意味着tools/platform/不能随意搬移而不触碰库;slang-common-objects间接层(见 3.2 节):某些配置模式下,同一批源文件先编译成对象库,再被重链接进slang-without-embedded-core-module与主slang,这是为了随用户可见的slang一并发布"无嵌入式 core module 的编译器"生成器而做的构建系统便利。
六、外部依赖清单:图外的真实链接面
图内只画内部结构,但每个节点的外部依赖在节点注释与 Edge citations 一节 中均有交代:
| 节点 | 主要外部依赖 | 依据文件 |
|---|---|---|
core | miniz、lz4_static、Threads::Threads、unordered_dense、${CMAKE_DL_LIBS};SLANG_ENABLE_MIMALLOC开启时 PUBLIC 链接mimalloc-static并传播SLANG_ENABLE_MIMALLOC=1编译定义(配置阶段若找不到mimalloc-static目标会直接硬失败) | source/core/CMakeLists.txt |
compiler-core | fast_float(除内部core链接外) | source/compiler-core/CMakeLists.txt |
slang、slang-wasm | SPIRV-Headers;wasm 目标另有miniz、lz4_static | source/slang/CMakeLists.txt、source/slang-wasm/CMakeLists.txt |
slang-rt | miniz、lz4_static、Threads、unordered_dense、${CMAKE_DL_LIBS}(无任何 Slang 内部库依赖) | source/slang-rt/CMakeLists.txt |
slang-glslang | glslang、SPIRV、SPIRV-Tools-opt、SPIRV-Tools-link | source/slang-glslang/CMakeLists.txt |
slang-lookup-tables | SPIRV-Headers | source/slang/CMakeLists.txt |
完整的逐边引用表(Edge citations)覆盖了图中每一条实线边:例如compiler-core → core对应 source/compiler-core/CMakeLists.txt 的LINK_WITH_PRIVATE core;core-module → {core, slang}对应 source/slang-core-module/CMakeLists.txt 的LINK_WITH_PRIVATE core slang-capability-defs slang-fiddle-output;slang-wasm → {slang, core, compiler-core}对应 wasm 目标上的LINK_WITH_PRIVATE miniz lz4_static slang core compiler-core slang-capability-defs slang-capability-lookup slang-fiddle-output slang-lookup-tables;虚线边slang -.-> slang-record-replay则只由EXTRA_SOURCE_DIRS源列表包含所证明,不依赖任何LINK_WITH_*子句。
七、这套质量闭环对我们意味着什么
把评审报告、修复报告与最终文档放在一起看,可以得到几条方法论层面的结论:
- 文档的"粒度纪律"是被强制执行的。提示词模板规定节点必须对应 source 目录或 module-map 标题,评审据此抓出了四个"目标混入子系统图"的节点;修复时没有简单地把它们从图中删掉就完事,而是用带标签的边和文字段落保住了信息量(
coreModule →|generated targets| slangLib反而比原来更准确地表达了"跨子系统依赖生成产物但不链接编译器"这一微妙关系); - 不变量必须区分"构建模式"。
SLANG_EMBED_CORE_MODULE开关会改变源归属目标、核心模块链接方式,甚至动态库缓存生成逻辑——把"唯一持有源码的目标"写成绝对化断言,在另一种配置下就会失真;修复后的表述(slang或slang-common-objects)才是可移植的真相; - 行号、字节上限、digest 都是校验资产。
regenerate.py lint会检查 front-matter 键、链接可解析性与 16 KB 体积上限;watched_paths_digest与source_commit让任何一次源码变动都能被标记为stale。修复报告特别指出"文档现为 12275 字节,低于 16384 字节上限,regenerate.py lint通过"——这就是机器可验证的完成定义。
如果你正想深入 Slang 源码:文件级清单请查阅 module-map.md;运行时数据流(而非构建依赖)请沿 pipeline/overview.md 的编译流水线继续追踪;而本主题的完整证据链——评审报告、修复报告、提示词模板与被监视的 CMake 文件——都可以在 docs/generated/design/_meta 目录下对照阅读。
【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考