Skip to content

Commit c319c1b

Browse files
committed
docs: 每条 lane 到得了哪些平台,以及这一轮的实施回填
docs/20 新增一节「Which platforms each lane reaches」(中英双份):三件事同时为真 才叫「一条 lane 在某个平台上成立」—— 设备编译器发布了、产物要的运行时够得到、以及 规则自己那段按宿主分岔的代码在那里编译得过。第三件是最容易被默认成立的那一件,而 mcpp:plugins 现在为矩阵里每个平台编译每一条规则,正是它把三处潜伏的宿主差异变成了 对应 runner 上的编译错误。 同一节写明「一条 lane 到得了的平台,它到达的方式是同一个」:规则按宿主区别对待的 全部内容就是四处,每一处都是宿主的性质不是设备的。以及运行时适配层 (compat:*-runtime)是 Linux 的构造 —— 它们不该被「补到三平台」,在另外两个平台上 按构造就不存在。 「尚未实现」补两条按平台分的缺口(HIP 上 Windows、CUDA 13.x 上 Windows),都写明 它们是打包工作而不是引擎工作,以及各自缺的那一块具体是什么。 lane 表的载荷列改成按平台写:rules-spirv 的编译器与 rules-sycl 的三个「把宿主库挡 在外面」的载荷都不再是三平台通用的。 docs/01 加上 10-graphics 两行。 设计文档补 §10 实施回填:§9 三条自我 review 的读数(第一条比预期强、第二条被推翻但 缺陷是真的、第三条成立且是最贵的一条)、「上游有产物 ≠ 重打包就能用」的四处、以及 三处只在 Linux 之外成立的缺陷。
1 parent f244b7e commit c319c1b

5 files changed

Lines changed: 206 additions & 6 deletions

File tree

.agents/docs/2026-09-07-heterogeneous-cross-platform-ecosystem.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,3 +261,78 @@ Host」相反,需要一次明确的例外裁决。建议**先不做,把它当作
261261
第一条最该被推翻。第三条最容易被低估:**「上游有产物」不等于「重打包就能用」**,规则
262262
侧的路径推导是按一个平台的布局写的,而那正是本轮 `xpkg_dir` 缺陷的同一种形状 ——
263263
一个函数只在它被写的那个环境里被验证过。
264+
265+
---
266+
267+
## 10. 实施回填(2026-09-07)
268+
269+
这一节把上面的判断与实际发生的事对齐。****出来的写在这里,****出来的如果被推翻
270+
也写在这里。分期没有被采纳:一二三期在同一天一起做了,四五期落成了记录在案的决定。
271+
272+
### 10.1 §9 的三条自我 review,读数
273+
274+
| 判断 | 结果 |
275+
|---|---|
276+
| 「离屏渲染像素确定」 | **比预期强**。lavapipe 与自写的软件光栅器给出**逐字节相同**的中心像素 `(124, 70, 62, 255)`,断言不需要写成区间。写法仍按 §9 的要求:先跑一次读真实值,再写断言 |
277+
| 「同名 stem 会静默覆盖」 | **被推翻,但缺陷是真的**。ninja 在加载图时就报 `multiple rules generate .../triangle_vert.h` —— 从来不是静默的。真正的缺陷是它报的是**生成的文件**而不是那两个源、以图加载失败的形态到达、并且不说出路。规则现在自己先查一遍并点名两者 |
278+
| 「Windows 的 CUDA 载荷装上就能用」 | **成立,而且是这一轮里最贵的一条**。见 10.2 |
279+
280+
### 10.2 「上游有产物」与「重打包就能用」之间的四处
281+
282+
Windows 的组件确实只需要一个 `windows` 段,但那四个配方与另外二十个共用一套
283+
install/config 形状,而那套形状是按 Linux 写的:
284+
285+
- `payload_root()` 只剥 `.tar.xz`。Windows 组件是 zip,按名字找不到解包目录,回落到
286+
扫描 —— 而被扫的是**共享**下载目录,谁先在那里解出一个 `bin/` 就装谁。
287+
- `scan_dir()``find` 加 GNU 参数。Windows 上 `find` 是 System32 那个按内容搜
288+
字符串的命令:它拒绝这些参数、往 stderr 写一行用法、返回空。**一个什么都没注册的
289+
组件,和一个本来就没有程序的组件,读数完全一样。**
290+
- `reunite_backend()``ln` 在 Windows 上不存在。12.x 线自带后端所以到不了,但一个
291+
13.x 的 Windows 条目会到 —— 它现在拒绝而不是执行。
292+
- 版本齐平检查(`tests/test_platform_version_parity.py`)的入口是
293+
`content.find("xpm")` —— 文件里第一次出现这三个字母,而这些配方的注释里写着
294+
`xpm.<os>.deps`**十五个配方对这条规则完全不可见**,其中 node.lua 声明了三个平台。
295+
修好之后补了一条分母判据。
296+
297+
### 10.3 三处只在 Linux 之外成立的缺陷,由「每条规则都为本宿主编译一次」抓到
298+
299+
`tests/all-rules-compile` 是这一轮加的夹具:不点名任何 accelerator(每条规则立刻
300+
返回,一个字节都不下载),只问六个模块编不编得过。它在第一批运行里抓到:
301+
302+
1. **macOS 14 / 15:`std::println` 不是 header-only。** 它的两个重载都要到 libc++
303+
**dylib** 里取 `__is_posix_terminal``__get_ostream_file`,而这两个符号是在
304+
macOS 14 不带的那一版里加进去的。规则改用 `std::format` 再 stream。
305+
**引擎侧还有一半**:`host_link_tokens` 的「信任 cfg」出口提前 return,从不发
306+
`-L`/`-rpath` 指向工具链自己的运行时目录,于是 `-lc++` 解析到系统那份而头文件来自
307+
载荷。已修,判据 `HostFlags.EveryExitNamesTheToolchainRuntimeDirs`
308+
2. **Windows:`popen` 拼作 `_popen`** `rules-spirv` 的宿主模块在那里编译失败。
309+
3. **Windows:版本约束里的 `>` 被 cmd.exe 读成重定向。** mcpp 把供给请求作为 JSON
310+
参数放在 shell 命令行上;`shell::quote` 回答的是子进程的 argv 解析(`\"`),而
311+
cmd 不认这个转义,于是走到 `>` 时引号数是偶数。`>=` 正是每个规则包声明下界用的
312+
形态,而**在此之前没有任何一条能在 Windows 上生效的声明带过 `>`**。已修(先按子
313+
进程规则引用,再给每个 cmd 元字符前缀 `^`),判据是两个解析器的模拟器加一条反向腿。
314+
315+
三条的共同形状:**一段代码的正确性依赖于宿主,而 CI 只在其中一个宿主上执行它**
316+
这正是 §9 第三行说的那个形状,只是它出现的次数比预期多。
317+
318+
### 10.4 分期没有采纳,四期与五期落成决定
319+
320+
- **一期(图形离屏)**:`examples/10-graphics/offscreen`,判据是像素。已实现。
321+
- **二期(shaderc 三平台)**:xim-pkgindex #778,规则按平台选编译器。已实现。
322+
- **三期(CUDA/SYCL 上 Windows)**:xim-pkgindex #779(五个包),规则侧的路径推导与
323+
路线判断。已实现;端到端由 `windows-test` job 装卸五个包并断言注册的程序验证。
324+
- **四期(软件设备把 CI 上限抬到运行)**:**未实现,记录为发布工作**。Windows 上需要
325+
一个 Mesa-on-Windows 的 `vulkan_lvp` 构建;macOS 上 runner 自带 GPU 与 MoltenVK,
326+
所以那一侧不需要软件设备,需要的是把 `compat.vulkan` 的 macOS 腿接到示例上。
327+
今天的上限:三平台**构建**,Linux **运行**
328+
- **五期(ROCm / Metal 准入)**:**决定是不收**,理由写在 §6.3,这里只补两条读数 ——
329+
Metal 的编译器只在 Xcode 内、不可再分发,所以它不是一个打包问题;ROCm 的运行时可
330+
再分发,但它需要的是一个 `rules-hip` 的 AMD 平台实现,而不是一个包。
331+
332+
### 10.5 一条留下的不一致,以及它什么时候消失
333+
334+
`mcpp:plugins` 0.2.5 里 `xim:shaderc` 在 macOS 与 Windows 上是**精确版本**,而
335+
Linux 上的 `xim:glslang`**下界**。这不是形态判断的差异,是 10.3 第 3 条的后果:
336+
发布中的引擎(2026.9.6.6)传不过去一个 `>`。引擎修复发布之后,那两处改回
337+
`>=2026.3`,而**那时 plugins 的 Windows job 就是这个引擎修复的端到端判据** ——
338+
今天它只有单元级的两个模拟器。

docs/01-examples.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ examples.
3838
| 09d | [`…/hip`](../examples/09-heterogeneous/hip/) | The same computation in HIP, reaching an NVIDIA device | `mcpp.rules.hip`, HIP as a header layer over the CUDA runtime, a two-chunk `accel` |
3939
| 09e | [`…/multi-backend`](../examples/09-heterogeneous/multi-backend/) | Several backends in ONE artifact, chosen at run time — the library shape, not the program shape | `accel` as a set, `cfg(accelerator = "none")` and its negation, a dispatch chain, a module seam over a C island boundary |
4040
| 09f | [`…/cann`](../examples/09-heterogeneous/cann/) | An Ascend C kernel behind the same seam. **Does not build yet** — its README names the two missing pieces | the `.asc` device extension, `op_kernel`/`op_host` as an island CANN already has, `accelerator = "none"` for the fallback |
41+
| 10 | [`examples/10-graphics`](../examples/10-graphics/) | Graphics rather than compute: a rendering pipeline whose result is pixels | `mcpp.rules.spirv` for the vertex and fragment stages, offscreen rendering as the assertable form |
42+
| 10a | [`…/offscreen`](../examples/10-graphics/offscreen/) | A triangle rasterised by Vulkan into a buffer, and the same triangle by a software rasteriser behind the same seam | two shader stages from one glob, a render pass with no window or swapchain, a pixel as the criterion |
4143

4244
## Suggested Reading Order
4345

docs/20-heterogeneous-builds.md

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -483,8 +483,8 @@ own denominator.
483483
|---|---|---|---|---|
484484
| `rules-cuda` | `mcpp.rules.cuda` | the project's own clang (`-x cuda`), or nvcc with a GCC toolchain | `xim:cuda-nvcc`, `xim:cuda-cudart`, `xim:libcurand`, `xim:cuda-cccl` | `cuda12.9+{sm_89} ptx>=89` |
485485
| `rules-hip` | `mcpp.rules.hip` | the project's own clang (`-x cuda`) on the NVIDIA platform | the above plus `xim:hip-nvidia` | `hip, cuda12.9+{sm_89}` |
486-
| `rules-sycl` | `mcpp.rules.sycl` | the `xim:dpcpp` payload's clang (`-fsycl`) | `xim:dpcpp`, `xim:gcc`, `xim:cuda-nvcc` for an NVIDIA target | `sycl` or `sycl, cuda12.9+{sm_89}` |
487-
| `rules-spirv` | `mcpp.rules.spirv` | `glslangValidator` or `glslc` | `xim:glslang` or `xim:shaderc` | `vulkan1.2` |
486+
| `rules-sycl` | `mcpp.rules.sycl` | the `xim:dpcpp` payload's clang (`-fsycl`) | `xim:dpcpp`; on Linux also `xim:gcc`, `xim:glibc`, `xim:linux-headers`; `xim:cuda-nvcc` for an NVIDIA target | `sycl` or `sycl, cuda12.9+{sm_89}` |
487+
| `rules-spirv` | `mcpp.rules.spirv` | `glslangValidator` or `glslc` | `xim:glslang` on Linux, `xim:shaderc` on macOS and Windows | `vulkan1.2` |
488488
| `rules-ascendc` | `mcpp.rules.ascendc` | `bisheng` (`-x asc`) from the CANN toolkit | `xim:cann-toolkit` | `ascend8.5+{dav-c220}` |
489489

490490
The payload column is what each rule declares for itself under
@@ -512,6 +512,61 @@ unwinder symbols they share. Nothing may cross the seam: a SYCL exception is
512512
caught in the device translation unit and returned as a code, because the
513513
runtime that threw it is not the one the caller would unwind with.
514514

515+
## Which platforms each lane reaches
516+
517+
A lane reaches a platform when three things hold there: the device compiler is
518+
published for it, the runtime the produced artifact needs can be reached, and
519+
the rule's own host-dependent code compiles for it. The third is the one that
520+
is easy to assume. `mcpp:plugins` compiles every rule for every platform in its
521+
CI matrix (`tests/all-rules-compile`, a fixture that names no accelerator, so
522+
it downloads nothing and asks only whether the modules compile); that fixture
523+
turned three latent host differences into compile errors on the runners that
524+
had them, and none of the three had been visible to a Linux build.
525+
526+
| lane | Linux | macOS | Windows | what decides it |
527+
|---|---|---|---|---|
528+
| `rules-spirv` | yes | yes | yes | the shader compiler is published for all three: `xim:glslang` on Linux, `xim:shaderc` on macOS arm64 and Windows x86_64 |
529+
| `rules-cuda` | yes | no | yes | NVIDIA publishes the redistributable components for Linux and Windows and has published no macOS toolkit since CUDA 10.2 |
530+
| `rules-sycl` | yes | no | Level Zero and OpenCL only | Intel publishes `sycl_linux` and `sycl_windows` from one tag and nothing for macOS; upstream states that the CUDA and HIP plugins are not built for Windows, and the Windows asset carries only the Level Zero and OpenCL adapters |
531+
| `rules-hip` | yes | no | no | the NVIDIA-platform header package is published for Linux alone; the AMD platform needs a ROCm runtime this ecosystem does not publish anywhere |
532+
| `rules-ascendc` | yes | no | no | the CANN toolkit is published for Linux alone |
533+
534+
**A vendor that does not publish for a platform ends the question.** No amount
535+
of engine work makes a CUDA toolkit exist for macOS. What the ecosystem can do
536+
is state the boundary at the point where a build asks to cross it, which is
537+
what each lane does: the SYCL rule refuses an ahead-of-time NVIDIA target on
538+
Windows and names the upstream release note that decides it, rather than
539+
compiling something the runtime cannot load.
540+
541+
**Where a lane reaches a platform, it reaches it the same way.** Four
542+
differences are the whole of what a rule does differently per host, and each is
543+
a property of the host rather than of the device:
544+
545+
- **The suffix on a program name.** `nvcc` and `nvcc.exe` are the same tool.
546+
- **Where the libraries are.** `lib` and `lib64` on ELF hosts, `lib/x64` in
547+
NVIDIA's Windows layout.
548+
- **Which host compiler the device compiler drives.** On Windows the CUDA rule
549+
takes its clang route whatever the project's compiler is: the nvcc route
550+
compiles the host half through a compiler named by `-ccbin`, and on that host
551+
the only one it accepts is MSVC's `cl.exe`, whose location is found by asking
552+
the machine about its Visual Studio installation. The clang route drives no
553+
second compiler and locates the MSVC headers itself.
554+
- **Which of the host's libraries have to be kept out.** On Linux the SYCL rule
555+
names `xim:gcc`, `xim:glibc` and `xim:linux-headers` because dpcpp's clang is
556+
not the clang mcpp resolved and is configured with neither library. On
557+
Windows there is one C++ runtime, MSVC's, and both compilers use it, so those
558+
three declarations do not exist there -- requiring them would refuse a build
559+
over three packages that this ecosystem does not publish for that platform
560+
and that its compiler does not need.
561+
562+
**The runtime adapters are a Linux construction.** `compat:cuda-runtime`,
563+
`compat:sycl-runtime` and `compat:vulkan-runtime` exist because an mcpp
564+
artifact on Linux runs behind a private loader that does not consult
565+
`/usr/lib`, so a vendor library installed by a driver package has to be brought
566+
onto the artifact's own search path. macOS (dyld) and Windows (the PE loader)
567+
have no such layer by construction, and a project targeting them declares no
568+
adapter.
569+
515570
## What a framework looks like on top of this
516571

517572
The five lanes prove a rule package can drive five compilers, the newest of
@@ -558,6 +613,20 @@ past it is the framework's own selector rather than a change to the packaging.
558613
## Not implemented
559614

560615
Device targets and the device linking they imply for the island shape, OpenMP
561-
offload and stdpar, the AMD platform of HIP, and Metal. See
616+
offload and stdpar, the AMD platform of HIP, and Metal.
617+
618+
Two further gaps are per-platform rather than per-model, and both are
619+
publishing work rather than engine work. **HIP on Windows** needs Windows
620+
sections for the NVIDIA-platform header package and for `cuda-profiler-api`,
621+
plus a Windows form for the header-declaration step that today writes into a
622+
Linux SubOS view. **The 13.x CUDA line on Windows** needs a Windows form for
623+
the back-end reunification: on that line upstream splits `nvvm/` and `crt/` out
624+
of `cuda_nvcc` into four separately published components, which the index
625+
reunites with symlinks, and `ln` is not a command on that host. The 12.x line
626+
keeps its back end inside the component and needs none of it, so that is the
627+
line Windows carries, declared as a deliberate divergence in each recipe rather
628+
than left to be read off the file.
629+
630+
See
562631
`.agents/docs/2026-09-05-heterogeneous-build-ecosystem-design-v2.md` for the
563632
design these follow from and the reason each is open.

docs/zh/01-examples.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ mcpp build && mcpp run
3535
| 09d | [`…/hip`](../../examples/09-heterogeneous/hip/) | 同一个计算写成 HIP,够到一台 NVIDIA 设备 | `mcpp.rules.hip`、HIP 作为 CUDA 运行时之上的一层头文件、两段式的 `accel` |
3636
| 09e | [`…/multi-backend`](../../examples/09-heterogeneous/multi-backend/) | 多个后端进**同一个产物**,运行期选择 —— 这是库的形态,不是程序的形态 | `accel` 作为集合、`cfg(accelerator = "none")` 及其否定、分发链、C 岛边界之上的模块接缝 |
3737
| 09f | [`…/cann`](../../examples/09-heterogeneous/cann/) | 同一道接缝背后的 Ascend C kernel。**目前还构建不了** —— README 里点明了缺的两块 | `.asc` 设备扩展名、CANN 本来就有的 `op_kernel`/`op_host` 岛、回退用 `accelerator = "none"` |
38+
| 10 | [`examples/10-graphics`](../../examples/10-graphics/) | 图形而不是计算:一条渲染管线,它的结果是像素 | `mcpp.rules.spirv` 编译顶点与片段两个阶段、离屏渲染作为可断言的形态 |
39+
| 10a | [`…/offscreen`](../../examples/10-graphics/offscreen/) | Vulkan 把一个三角形光栅化进缓冲区,同一道接缝背后是同一个三角形的软件光栅器 | 一个 glob 带出两个着色器阶段、无窗口无交换链的 render pass、判据是一个像素 |
3840

3941
## 推荐阅读顺序
4042

0 commit comments

Comments
 (0)