|
7 | 7 |
|
8 | 8 | ## [2026.9.7.1] - 2026-09-07 |
9 | 9 |
|
10 | | -### 三条通道,都是「规则包知道而引擎收不到」的形状 |
| 10 | +### 四条通道,都是「规则包知道而引擎收不到」的形状 |
11 | 11 |
|
12 | | -这一版加的三样东西各自很小,共同点是它们补的都是同一类缺口:规则包已经知道某件事, |
13 | | -而没有任何通道把它送到引擎的决定上。 |
| 12 | +这一版加的四样东西各自很小,共同点是它们补的都是同一类缺口:一方已经知道某件事, |
| 13 | +而没有任何通道把它送到需要它的另一方。 |
14 | 14 |
|
15 | 15 | **`mcpp::action` 增加 `depfile`。** action 的输入在 `build.mcpp` 运行时就定死了,那时 |
16 | 16 | 命令还没执行。一个靠解析源码才知道自己 `#include` 图的编译器,因此没有办法把结果报回 |
|
23 | 23 | **不要同时把 depfile 声明为 `output()`**:`deps = gcc` 会让 ninja 读完即删,一条承诺了 |
24 | 24 | 该输出的边会永远是脏的。 |
25 | 25 |
|
26 | | -**`.slang` 进入设备源扩展名表。** 受限 glob 的 `accel` 键**不**决定一个文件是不是设备 |
27 | | -源,`kDeviceExtensions` 才决定。所以在此之前,一个规则包无法自己引入一门设备语言: |
| 26 | +**规则包自己声明它编译哪些扩展名(`device_extensions`),以及提供规则的模块 |
| 27 | +(`rule_module`)。** 受限 glob 的 `accel` 键**不**决定一个文件是不是设备源, |
| 28 | +`kDeviceExtensions` 才决定。所以在此之前,一个规则包无法自己引入一门设备语言: |
28 | 29 | `xim:slang` 装得上、规则也编得过,而文件仍然掉进普通源集,报的是「mcpp has no role for |
29 | | -the extension '.slang'」。Slang 是一门语言而不是 GLSL 的第二个驱动 —— 它有自己的模块 |
30 | | -系统、泛型,以及超出 SPIR-V 的目标集合 —— 所以它有自己的扩展名,外面也有自己的规则。 |
| 30 | +the extension '.slang'」。 |
| 31 | + |
| 32 | +第一版的修法是把 `.slang` 加进引擎那张表。那是**方向反了的依赖**:通用构建系统会因此 |
| 33 | +持有一份外部插件的语言清单,而第三方插件想引入一门语言仍要等一次引擎发布。最终的形状 |
| 34 | +是两个键写在规则包**自己**的 feature 上: |
| 35 | + |
| 36 | + [features.rules-slang] |
| 37 | + sources = ["rules/slang.cppm"] |
| 38 | + device_extensions = [".slang"] |
| 39 | + rule_module = "mcpp.rules.slang" |
| 40 | + |
| 41 | +引擎因此不持有任何包名、feature 拼写或模块名。两个键必须同时出现:一个声明了扩展名却 |
| 42 | +不说谁来编译它的 feature 会被拒绝,而不是让文件在后面某处静默掉队。 |
| 43 | + |
| 44 | +判据是直接的:`.slang` 已从 `kDeviceExtensions` **移除**,而 `tests/slang-consumer` |
| 45 | +照常构建与运行。一门新设备语言不再需要引擎发一个版本。 |
| 46 | + |
| 47 | +**`[rules]` 声明了规则的项目不必写 `build.mcpp`。** 规则模块被声明之后,那个程序的内容 |
| 48 | +就是确定的 —— 导入这些模块、依次调用 `compile()`、有一条失败就返回非零。mcpp 把它写进 |
| 49 | +构建目录。项目要接管就把它拷到根目录改,合成随即停止:声明是 `build.mcpp` **之上**的 |
| 50 | +一层,不是它旁边的第二套机制。 |
31 | 51 |
|
32 | 52 | **`[language] modules` 以 `MCPP_LANGUAGE_MODULES` 报给构建程序。** **生成**面向消费者 |
33 | 53 | 声明的规则要在「模块接口」与「头文件」之间做选择,而项目已经声明过它用哪一种;用别的 |
34 | 54 | 方式推导就是同一个决定的第二种拼法。旧引擎不设这个变量,规则把缺席读作「头文件」—— |
35 | 55 | 也就是这个变量存在之前每个消费者的行为,所以升级不需要任何项目改一个字。 |
36 | 56 |
|
| 57 | +**包身份以 `MCPP_PKG_NAME` / `MCPP_PKG_NAMESPACE` 报给构建程序。** 规则包生成的每一个 |
| 58 | +名字都由包名推导 —— 消费者导入的模块、访问器所在的命名空间、生成头里的符号 —— 而构建 |
| 59 | +程序的契约里没有任何东西回答「我在构建哪个包」。此前可用的最接近的答案是 |
| 60 | +`MCPP_MANIFEST_DIR` 的末段,那是**目录名**。 |
| 61 | + |
| 62 | +两者在「包放在一个通用目录下」时不同,而这正是本仓库自己的布局: |
| 63 | +`examples/09-heterogeneous/vulkan/app/` 声明 `name = "vulkan-saxpy"`, |
| 64 | +`mcpp.rules.spirv` 生成的却是 `app.shaders` —— 工作区里每一个 `<something>/app/` 都会 |
| 65 | +声称拥有同一个模块,而且这个面向用户的名字会随着目录改名而改变。 |
| 66 | + |
| 67 | +配套的 e2e 按构造区分这两种推导:夹具的目录叫 `app`、包叫 `vulkan-saxpy`。名字与目录 |
| 68 | +相同的夹具对两种实现都通过 —— 而在此之前每一个夹具都是这样。 |
| 69 | + |
37 | 70 | ### 两处只在 Linux 之外成立的缺陷,以及第一条图形管线 |
38 | 71 |
|
39 | 72 | **引擎与规则层早就与平台无关,而生态只在 Linux 上完整。** 把规则包在另外两个平台上 |
@@ -128,18 +161,37 @@ loader 默认不把它交给 `vkEnumeratePhysicalDevices`:实例要同时启用 |
128 | 161 | Linux 上跑翻译层的机器也有它,macOS 上对着原生驱动构建的程序并不需要它。Linux/lavapipe |
129 | 162 | 上读数不变,中心像素仍是 `(124, 70, 62, 255)`,设备名仍是 `llvmpipe`。 |
130 | 163 |
|
131 | | -**示例本身补齐了另外两个平台的设备声明** —— `cfg(macos)` 下 `xim:moltenvk`,`cfg(windows)` |
132 | | -下 `xim:mesa-lavapipe`。这个缺口在示例只构建不运行时是看不见的:不运行的程序从不向 |
133 | | -loader 要设备。声明写在示例里而不是 CI 步骤里,是为了让**任何人**检出它都能跑,而不只是 |
134 | | -那台多跑了一条命令的 runner。 |
135 | | - |
136 | | -于是两个新 CI 步骤**什么都不装**:它们找构建已经供给的 ICD 并设 `VK_DRIVER_FILES`,所以 |
137 | | -一份没能声明驱动的 manifest 会让步骤变红。步骤里放 `xlings install` 会让它两种情况都通过。 |
138 | | - |
139 | | -两个平台断言的东西不同,而这个差别正是重点。lavapipe 是软件光栅化器,像素由构造保证相同, |
140 | | -所以图像分不出它,设备名才分得出。MoltenVK 是宿主自己的 GPU 经 Metal,名字随 runner 变, |
141 | | -所以那边区分「够到了设备」的是**报出了中心像素**这件事本身 —— 一个被 loader 拒绝展示的 |
142 | | -可移植性驱动不会产生它。 |
| 164 | +**示例本身补齐了 macOS 的设备声明** —— `cfg(macos)` 下 `xim:moltenvk`。这个缺口在示例 |
| 165 | +只构建不运行时是看不见的:不运行的程序从不向 loader 要设备。声明写在示例里而不是 CI |
| 166 | +步骤里,是为了让**任何人**检出它都能跑,而不只是那台多跑了一条命令的 runner。 |
| 167 | + |
| 168 | +于是新的 macOS CI 步骤**什么都不装**:它找构建已经供给的 ICD 并设 `VK_DRIVER_FILES`, |
| 169 | +所以一份没能声明驱动的 manifest 会让步骤变红。步骤里放 `xlings install` 会让它两种情况 |
| 170 | +都通过。 |
| 171 | + |
| 172 | +Linux 与 macOS 断言的东西不同,而这个差别正是重点。lavapipe 是软件光栅化器,像素由构造 |
| 173 | +保证相同,所以图像分不出它,设备名才分得出。MoltenVK 是宿主自己的 GPU 经 Metal,名字随 |
| 174 | +runner 变,所以那边区分「够到了设备」的是**报出了中心像素**这件事本身 —— 一个被 loader |
| 175 | +拒绝展示的可移植性驱动不会产生它。 |
| 176 | + |
| 177 | +**Windows 停在「构建」,而停在这里的理由被测量推翻过一次。** 运行步骤写过、推过、测过: |
| 178 | +`xim:mesa-lavapipe` 装上了,ICD 清单在 store 里找到了,程序打印 `render unavailable` —— |
| 179 | +那是 `src/main.cpp` 在渲染函数什么都没返回时的报告。 |
| 180 | + |
| 181 | +第一次读把它归因成缺少 loader。这个归因是错的,日志本身就说明了:Vulkan 那条腿经导入库 |
| 182 | +从 `vulkan-1.dll` 取 `vkCreateInstance`,一个找不到该 DLL 的进程会在映像加载期失败、 |
| 183 | +一个字都印不出来。它印出来了。loader 在,跑了,枚举不到设备 —— 这是关于 ICD 的陈述。 |
| 184 | +另一侧还有一个事实站在一起:mcpp-index 自己的 `vulkan-tests` 成员在 windows 分片上调用 |
| 185 | +`vkEnumerateInstanceVersion` 且通过。 |
| 186 | + |
| 187 | +顺带排掉了另一个嫌疑:`compat:vulkan` 里的 Khronos loader 能从索引已经携带的源码交叉 |
| 188 | +构建出可用的 `vulkan-1.dll` —— 265 个导出,与上游 `vulkan-1.def` 逐名吻合;`DllMain` |
| 189 | +在;只导入 ADVAPI32、CFGMGR32、KERNEL32 与 msvcrt。描述符那段注记论证的是「Windows 上 |
| 190 | +的 loader 必须是 DLL」,不是「它构建不出来」。所以这个包随时可以有,只是它不是这个步骤 |
| 191 | +在等的东西。 |
| 192 | + |
| 193 | +留待测量的是:lavapipe 的 Windows 载荷为什么在 mcpp 启动的进程里枚举不出设备。这一条的 |
| 194 | +一般形式值得记下 —— 被复查的是结论,理由不会。 |
143 | 195 |
|
144 | 196 | ### 文档 |
145 | 197 |
|
|
0 commit comments