@@ -28,22 +28,98 @@ TMP=$(mktemp -d)
2828trap " rm -rf $TMP " EXIT
2929export MCPP_HOME=$HOME /.mcpp
3030
31- cd " $TMP "
32- " $MCPP " new gfxapp > /dev/null
33- cd gfxapp
34- cat >> mcpp.toml << 'EOF '
31+ # ── the capability comes from a DEPENDENCY, not from this project ───────────
32+ #
33+ # THIS IS THE SHAPE REAL PROJECTS HAVE, and getting it wrong is how the first
34+ # version of this gate shipped half-working. Almost no application declares
35+ # `capability:opengl.glx.driver` itself — it depends on glfw / an SDL wrapper /
36+ # a GL runtime that does, and the resolver stamps each requirement with its
37+ # requester. A gate that reads the ROOT manifest answers "did the author write
38+ # it down" (nearly always no) instead of "does the resolved graph need it".
39+ #
40+ # Measured on a real imgui project: `mcpp why runtime` listed
41+ # `capability:opengl.glx.driver [run] <- compat.glfw@3.4 (required)`, and
42+ # `--mode self-contained` packaged it happily — while THIS test passed, because
43+ # its fixture declared the capability at the root. The fixture had the one
44+ # shape real projects do not.
45+ INDEX_DIR=" $TMP /local-index"
46+ mkdir -p " $INDEX_DIR /pkgs/g"
47+ cat > " $INDEX_DIR /pkgs/g/gfx-runtime.lua" << 'EOF '
48+ package = {
49+ spec = "1",
50+ name = "gfx-runtime",
51+ description = "A dependency that needs the host to provide a driver",
52+ licenses = {"MIT"},
53+ type = "package",
54+ xpm = {
55+ linux = {
56+ ["1.0.0"] = {
57+ url = "https://example.invalid/gfx-runtime-1.0.0.tar.gz",
58+ sha256 = "0000000000000000000000000000000000000000000000000000000000000000",
59+ },
60+ },
61+ },
62+ mcpp = {
63+ language = "c++23",
64+ import_std = true,
65+ sources = { "src/**/*.cppm" },
66+ targets = { ["gfx-runtime"] = { kind = "lib" } },
67+ deps = {},
68+ runtime = {
69+ requirements = {
70+ { kind = "capability", value = "opengl.glx.driver", phase = "run",
71+ required = true, discovery = "rpath-of-dispatch" },
72+ },
73+ },
74+ },
75+ }
76+ EOF
77+
78+ mkdir -p " $TMP /gfxapp/src"
79+ mkdir -p " $TMP /gfxapp/.mcpp/.xlings/data/xpkgs/local-dev.gfx-runtime/1.0.0/src"
80+ cd " $TMP /gfxapp"
81+ cat > .mcpp/.xlings/data/xpkgs/local-dev.gfx-runtime/1.0.0/src/lib.cppm << 'EOF '
82+ export module gfx.runtime;
83+ export int gfx_ready() { return 1; }
84+ EOF
85+ cat > src/main.cpp << 'EOF '
86+ import gfx.runtime;
87+ int main() { return gfx_ready() == 1 ? 0 : 1; }
88+ EOF
89+ # The application itself declares NOTHING. That is the point.
90+ cat > mcpp.toml << EOF
91+ [package]
92+ name = "gfxapp"
93+ version = "0.1.0"
3594
36- [[runtime.requirements] ]
37- kind = "capability"
38- value = "opengl.glx.driver"
39- phase = "run"
40- # DECLARED by the package, not inferred by mcpp: which mechanism a capability
41- # uses is the provider's property. GLX is reached through the dispatch
42- # library's own DT_RPATH; EGL through a JSON file holding an ABSOLUTE path — so
43- # the two are not interchangeable, and a row without this is not actionable.
44- discovery = "rpath-of-dispatch "
95+ [indices ]
96+ local-dev = { path = "$INDEX_DIR " }
97+
98+ [dependencies]
99+ "local-dev.gfx-runtime" = "1.0.0"
100+
101+ [targets.gfxapp]
102+ kind = "bin"
103+ main = "src/main.cpp "
45104EOF
46105
106+ # Guard: if the requirement never reaches the resolved graph, everything below
107+ # would pass by refusing nothing — so assert it arrived first.
108+ " $MCPP " build > " $TMP /build.log" 2>&1 || { cat " $TMP /build.log" ; exit 1; }
109+ " $MCPP " why runtime > " $TMP /why.log" 2>&1 || { cat " $TMP /why.log" ; exit 1; }
110+ grep -q ' capability:opengl.glx.driver' " $TMP /why.log" || {
111+ echo " FAIL: the dependency's capability never reached the resolved graph —"
112+ echo " this test would then prove nothing about the gate"
113+ cat " $TMP /why.log"
114+ exit 1
115+ }
116+ grep -q ' gfx-runtime' " $TMP /why.log" || {
117+ echo " FAIL: the requirement is not attributed to the dependency"
118+ cat " $TMP /why.log"
119+ exit 1
120+ }
121+ echo " requirement arrives from the dependency, not from this project"
122+
47123# ── the two modes that carry their own libc must refuse ─────────────────────
48124for mode in self-contained static; do
49125 if " $MCPP " pack --mode " $mode " > " $TMP /$mode .log" 2>&1 ; then
0 commit comments