@@ -25,6 +25,87 @@ set -e
2525TMP=$( mktemp -d)
2626trap " rm -rf $TMP " EXIT
2727
28+ # ── half 0: a farm this test OWNS ───────────────────────────────────────────
29+ #
30+ # The opportunistic half below can only measure what this machine happens to
31+ # have installed, and on a CI SubOS that is nothing the payloads do not already
32+ # provide — so it skips, and the decisive assertion never runs where it matters
33+ # most. This half builds the condition instead of hoping for it.
34+ #
35+ # A project-local named SubOS (`<project>/.mcpp/.xlings/subos/<name>`) is a real
36+ # SubOS as far as the binding is concerned, and it lives entirely inside this
37+ # test's temp directory. Nothing shared is written — writing a probe library
38+ # into the machine's actual SubOS would be the "one test's failure comes from
39+ # the previous run" defect this suite has already paid for once.
40+ #
41+ # `allow_host_libs` is required and is not a workaround: a SubOS with no
42+ # `subos_info` names no runtime, so mcpp declines payload-first rather than
43+ # guessing a libc, and the hermeticity check correctly reports the host
44+ # fallback. The declaration is what says "yes, I meant that".
45+ mkdir -p " $TMP /ownfarm/src" " $TMP /ownfarm/.mcpp/.xlings/subos/probe/lib"
46+ cd " $TMP /ownfarm"
47+ FARM_OWN=" $TMP /ownfarm/.mcpp/.xlings/subos/probe/lib"
48+
49+ # The probe library, built by mcpp itself so it matches the toolchain exactly.
50+ mkdir -p " $TMP /probelib/src"
51+ cat > " $TMP /probelib/mcpp.toml" << 'EOF '
52+ [package]
53+ name = "probelib"
54+ version = "0.1.0"
55+
56+ [targets.mcppfarmprobe]
57+ kind = "shared"
58+ EOF
59+ cat > " $TMP /probelib/src/probe.cppm" << 'EOF '
60+ export module probelib.probe;
61+ export int mcpp_farm_probe() { return 42; }
62+ EOF
63+ ( cd " $TMP /probelib" && " $MCPP " build > build.log 2>&1 ) || {
64+ echo " FAIL: probe library build" ; cat " $TMP /probelib/build.log" ; exit 1; }
65+ PROBE_SO=" $( ls " $TMP " /probelib/target/* /* /bin/libmcppfarmprobe.so | head -1) "
66+ [[ -n " $PROBE_SO " ]] || { echo " FAIL: no probe .so" ; ls -R " $TMP /probelib/target" | head -20; exit 1; }
67+ cp " $PROBE_SO " " $FARM_OWN /libmcppfarmprobe.so"
68+
69+ cat > mcpp.toml << EOF
70+ [package]
71+ name = "ownfarm"
72+ version = "0.1.0"
73+
74+ [xlings]
75+ subos = "probe"
76+
77+ [build]
78+ allow_host_libs = true
79+ ldflags = ["-Wl,--no-as-needed", "-L$FARM_OWN ", "-lmcppfarmprobe", "-Wl,--as-needed"]
80+ EOF
81+ echo ' int main() { return 0; }' > src/main.cpp
82+ " $MCPP " build > build.log 2>&1 || {
83+ echo " FAIL: build against a SubOS-provided library" ; cat build.log; exit 1; }
84+
85+ OWN_BIN=" $( ls target/* /* /bin/ownfarm | head -1) "
86+ [[ -n " $OWN_BIN " ]] || { echo " FAIL: no artifact" ; exit 1; }
87+
88+ # The library exists ONLY under the SubOS view. `-L` got it linked; only the
89+ # farm entry in DT_RPATH can get it loaded — nothing else on the search path
90+ # has ever heard of it.
91+ " $OWN_BIN "
92+ rc=$?
93+ [[ $rc -eq 0 ]] || {
94+ echo " FAIL: an artifact could not load a library its own SubOS provides (exit $rc )"
95+ echo " farm: $FARM_OWN "
96+ echo " This is the run-time half of the closure: the SubOS is the"
97+ echo " sysroot at link time and must be on the search path at load time."
98+ exit 1
99+ }
100+ echo " ran: exit 0 against a library only this SubOS provides"
101+ # Measured against the previous release (2026.8.10.3) this half fails at the
102+ # BINDING — an undeclared SubOS was a hard error there — so it exercises both
103+ # halves of this change together rather than isolating the farm. The half below
104+ # isolates the farm alone, when the machine has a populated SubOS to isolate it
105+ # with; on the machine this was written on, `-lEGL` linked and exited 127 before
106+ # the change and exits 0 after.
107+ cd " $TMP "
108+
28109# ── find a library only the farm provides ───────────────────────────────────
29110#
30111# Derived from the recorded closure rather than hardcoded to libGL: CI SubOSes
0 commit comments