Skip to content

Commit 95a7553

Browse files
authored
0.7.0: the Slang rule takes the project's arguments, per-file ones, and a storage (#17)
Three things a real Slang project needed and the rule could not say, found by transcribing xrgui's shader config (17 shaders, five common slangc flags, one shader with a flag of its own, `.spv` files loaded at run time): options::extra_args slangc takes some two hundred options; the rule keeps the ones that decide WHAT is produced and passes the rest through verbatim, after its own and before `-o`. options::per_file what one shader gets that the others do not. One `compile()` call writes one surface, so calling it twice with two option sets rewrote the generated module with only the second call's shaders. A table keyed by the path the constrained glob names keeps the one call. A key naming no shader is refused, listing the shaders seen: a typo that silently applied nothing is the failure the table would otherwise hide. options::storage the axis `rules-spirv` already had. header embeds (`-source-embed-style u32`, as before and still the default); object and sidecar ask slangc for a bare `.spv`, and the surface does the rest. Measured under all three; the consumer's source is the same. `profile_for` gains the 1.4 row: Vulkan 1.4 requires SPIR-V 1.6, and without the row a 1.4 build fell to spirv_1_0. The fixture grows a second shader and reads the ENTRY POINT'S NAME out of the SPIR-V bytes: `-fvk-use-entrypoint-name` through extra_args makes both modules carry their function's name, `-DOFFSET_ENTRY` through per_file switches one of them again, and `scale.slang` would report `wrongMain` if the per-file macro had leaked. CI adds the negative leg (a mistyped key refuses the build by name) and a `slang-sidecar` fixture with the wrong-directory half. No engine floor moves: everything here is spelling inside the rule.
1 parent 9064107 commit 95a7553

13 files changed

Lines changed: 370 additions & 27 deletions

File tree

.github/workflows/ci.yml

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,16 @@ jobs:
894894
run: |
895895
"$MCPP" build
896896
"$MCPP" run | tee run.log
897-
grep -q '^scale.slang: magic=07230203' run.log
897+
# TWO SHADERS, AND THE ENTRY POINT'S NAME IS THE MEASUREMENT.
898+
#
899+
# `-fvk-use-entrypoint-name` reaches slangc through
900+
# `options::extra_args` and makes the module carry the function's
901+
# name instead of `main`; `-DOFFSET_ENTRY` reaches ONE shader through
902+
# `options::per_file` and switches its name again. The consumer reads
903+
# both names out of the SPIR-V bytes, and `scale.slang` would report
904+
# `wrongMain` if the per-file macro had leaked to it.
905+
grep -q '^scale.slang: magic=07230203 .* entry=computeMain ok' run.log
906+
grep -q '^offset.slang: magic=07230203 .* entry=offsetMainDefined ok' run.log
898907
grep -q '^all ok' run.log
899908
if grep -rn 'scale\.h\|\.inc"' src/; then
900909
echo "FAIL: a consumer source names a generated file"
@@ -904,6 +913,51 @@ jobs:
904913
target/.build-mcpp/out/slang/slang_consumer.shaders.cppm
905914
echo "ok: a Slang shader reached through the same surface as a GLSL one"
906915
916+
# THE NEGATIVE LEG. A `per_file` key that names no shader must refuse the
917+
# build and list what it could have named; a rule that applied nothing
918+
# and built anyway would hand the project a module it believes carries
919+
# the option. Without this half the table could silently become a no-op
920+
# and every positive assertion above would still pass.
921+
- name: rules-slang refuses a per_file key that names no shader
922+
working-directory: tests/slang-consumer
923+
run: |
924+
cp build.mcpp /tmp/build.mcpp.bak
925+
sed -i 's|shaders/offset.slang|shaders/offest.slang|' build.mcpp
926+
if "$MCPP" build > refused.log 2>&1; then
927+
cp /tmp/build.mcpp.bak build.mcpp
928+
echo "FAIL: a mistyped per_file key built anyway"; cat refused.log; exit 1
929+
fi
930+
cp /tmp/build.mcpp.bak build.mcpp
931+
grep -q 'per_file. names .shaders/offest.slang., and no shader' refused.log
932+
grep -q '^ shaders/offset.slang' refused.log
933+
echo "ok: refused by name, and the shaders it could have named were listed"
934+
935+
# THE THIRD STORAGE, FOR SLANG. `options::storage` is new in 0.7.0; before
936+
# it the rule embedded unconditionally. The consumer's source is the one
937+
# `slang-consumer` has minus the per-file assertions, and the reverse leg
938+
# is the point of the storage, as `spirv-sidecar` records.
939+
- name: rules-slang with sidecar storage
940+
working-directory: tests/slang-sidecar
941+
run: |
942+
"$MCPP" build
943+
"$MCPP" run | tee run.log
944+
grep -q '^magic=07230203' run.log
945+
grep -q '^all ok' run.log
946+
test -f target/.build-mcpp/out/slang/scale.spv
947+
if grep -q 'source-embed' target/*/*/build.ninja; then
948+
echo "FAIL: sidecar storage still asked slangc to embed"; exit 1
949+
fi
950+
bin=$(ls target/*/*/bin/slang-sidecar)
951+
bin=$(cd "$(dirname "$bin")" && pwd)/$(basename "$bin")
952+
if (cd /tmp && "$bin" > away.log 2>&1); then
953+
echo "FAIL: the sidecar program succeeded from the wrong directory"
954+
cat /tmp/away.log
955+
exit 1
956+
fi
957+
grep -q 'sidecar payload was not found' /tmp/away.log \
958+
|| { echo "FAIL: it failed for some other reason"; cat /tmp/away.log; exit 1; }
959+
echo "ok: a Slang payload found from the package root, reported missing from elsewhere"
960+
907961
# A tool, not a rule: the header is written while the build program runs,
908962
# so there is no action to schedule. The second build is the measurement
909963
# that matters -- editing the data file must reach the binary, which is

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ imports each one from `build.mcpp` under the module name the member declares.
66

77
```toml
88
[build-dependencies.mcpp]
9-
plugins = { version = "0.6.0", features = ["rules-spirv"], host-module = true }
9+
plugins = { version = "0.7.0", features = ["rules-spirv"], host-module = true }
1010
```
1111

1212
`[build-dependencies]`, not `[dependencies]`. The two keys answer separate
@@ -66,7 +66,7 @@ engine's own module family and is not used here.
6666
| `rules-ascendc` | `mcpp.rules.ascendc` | 2026.9.6.6 | `[build] accel = "ascend8.5+{dav-c220}"`, a constrained glob for `*.asc`. Compiles with BiSheng in MIXED mode, so the object carries the device binary and a host-callable launcher and joins the ordinary link -- no registration file and no device-link step. Its own engine needs are `.asc` in the device-source table and `mcpp::link_flag` for the `-rpath-link` the toolkit's shared libraries require, both 2026.9.6.5 |
6767
| `rules-cuda` | `mcpp.rules.cuda` | 2026.9.6.6 | `[build] accel = "cuda…"`, a constrained glob for `*.cu`; the clang route with an LLVM toolchain, the nvcc route with a GCC one |
6868
| `rules-hip` | `mcpp.rules.hip` | 2026.9.6.6 | `[build] accel = "hip, cuda12.9+{sm_89}"`, a constrained glob for `*.hip`. On the NVIDIA platform HIP is a header layer over the CUDA runtime, so the compiler is the project's own clang and there is no ROCm on the machine |
69-
| `rules-slang` | `mcpp.rules.slang` | 2026.9.7.1 | `[build] accel = "vulkan1.2"`, a constrained glob for `*.slang`. Slang is a different language from GLSL rather than a second driver for it -- its own module system, generics, and targets beyond SPIR-V -- so it is a rule of its own. `.slang` is **not** in the engine's device-source table: this feature declares `device_extensions = [".slang"]` and `rule_module = "mcpp.rules.slang"`, and the engine routes it from there. That is the criterion for the whole arrangement -- a new device language costs no engine release |
69+
| `rules-slang` | `mcpp.rules.slang` | 2026.9.7.1 | `[build] accel = "vulkan1.2"`, a constrained glob for `*.slang`. Slang is a different language from GLSL rather than a second driver for it -- its own module system, generics, and targets beyond SPIR-V -- so it is a rule of its own. `.slang` is **not** in the engine's device-source table: this feature declares `device_extensions = [".slang"]` and `rule_module = "mcpp.rules.slang"`, and the engine routes it from there. That is the criterion for the whole arrangement -- a new device language costs no engine release. Since 0.7.0 it has the same `options::storage` axis as `rules-spirv` (header / object / sidecar), `options::extra_args` for the arguments the rule has no field for, and `options::per_file` for what one shader gets that the others do not -- a project with a `-fvk-use-gl-layout` and one shader needing `-emit-spirv-via-glsl` writes both without leaving one `compile()` call |
7070
| `rules-spirv` | `mcpp.rules.spirv` | 2026.9.6.6 | `[build] accel = "vulkan1.2"`, a constrained glob for the shader stages; compiles each shader through a `role = "source"` action and states which of the two compilers produced it |
7171
| `rules-sycl` | `mcpp.rules.sycl` | 2026.9.6.6 | `[build] accel = "sycl"` or `"sycl, cuda12.9+{sm_89}"`, a constrained glob for `*.sycl`, and `compat:sycl-runtime` so the artifact can reach `libsycl.so.9` at run time. Its own engine need is `.sycl` in the device-source table, 2026.9.6.1 |
7272
| `tools-embed` | `mcpp.tools.embed` | 2026.9.5.4 | nothing beyond mcpp: it reads a file and writes a header while the build program runs. The floor is the release whose fast path compares a declared file input, without which an edit to the data does not reach the binary |
@@ -81,7 +81,7 @@ A project names the rule and nothing else:
8181

8282
```toml
8383
[build-dependencies.mcpp]
84-
plugins = { version = "0.6.0", features = ["rules-cuda"], host-module = true }
84+
plugins = { version = "0.7.0", features = ["rules-cuda"], host-module = true }
8585
```
8686

8787
The payloads each rule drives are declared **here**, under the feature that
@@ -322,8 +322,8 @@ consumer compiled either way is the same source.
322322
relative to the working directory, so the program finds its payloads when run
323323
from the package root and does not when run from elsewhere -- which is why it is
324324
not the default, and why `mcpp pack` of such a program has something further to
325-
collect. `tests/spirv-sidecar` asserts both halves: found from the root, and
326-
reported missing from `/tmp`.
325+
collect. `tests/spirv-sidecar` and `tests/slang-sidecar` assert both halves: found
326+
from the root, and reported missing from `/tmp`.
327327
328328
**The default follows the project.** `[language] modules = true` gives the
329329
module surface, `false` gives a header with the same declarations. mcpp reports

mcpp.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "plugins"
33
namespace = "mcpp"
4-
version = "0.6.0"
4+
version = "0.7.0"
55
description = "Official mcpp build plugins: rule packages under mcpp.rules.*, build-time utilities under mcpp.tools.*, each member selected by a feature"
66
license = "Apache-2.0"
77
authors = ["mcpp-community"]

0 commit comments

Comments
 (0)