| … | … | @@ -73,6 +73,18 @@ console.log(' out: ' + path.join(OUT_DIR, TARBALL_NAME)) |
| 73 | 73 | |
| 74 | 74 | // ── Verify bare binary exists for target arch ── |
| 75 | 75 | |
| 76 | // Additional arches staged under by-arch/<label>/runtime/bare. The install |
| 77 | // side already prefers by-arch/<host>/runtime/bare (lib/runtime-factory.js) and |
| 78 | // skips foreign subtrees when materialising (lib/store.js), so a multi-arch |
| 79 | // tree costs a remote host nothing to install — but WITHOUT it an x64 publisher |
| 80 | // can only ever produce x64-runnable installs, because both the runtime binary |
| 81 | // and the native prebuilds are pruned to the build host. That is why an aarch64 |
| 82 | // device could fetch pgh-sidecar and still not run it. |
| 83 | const EXTRA_ARCHES = (getFlag('extra-arch', '') || '') |
| 84 | .split(',').map((a) => a.trim()).filter(Boolean) |
| 85 | const EXTRA_LABELS = EXTRA_ARCHES.map((a) => archLabel(OS, a)).filter((l) => l !== LABEL) |
| 86 | const ALL_LABELS = [LABEL, ...EXTRA_LABELS] |
| 87 | |
| 76 | 88 | const BARE_ARCH_PKG = `bare-runtime-${LABEL}` |
| 77 | 89 | const BARE_BIN_SRC = path.join(ROOT, 'node_modules', BARE_ARCH_PKG, 'bin', 'bare') |
| 78 | 90 | if (!fs.existsSync(BARE_BIN_SRC)) { |
| … | … | @@ -205,14 +217,14 @@ console.log(' smart-nested: removed ' + nestedStats.dupsRemoved + ' hoist-dup |
| 205 | 217 | const afterNested = du(path.join(stageRoot, 'node_modules')) |
| 206 | 218 | console.log(' after smart-nested-dup prune: ' + fmtBytes(afterNested)) |
| 207 | 219 | |
| 208 | | prunePrebuilds(path.join(stageRoot, 'node_modules'), LABEL) |
| 220 | prunePrebuilds(path.join(stageRoot, 'node_modules'), ALL_LABELS) |
| 209 | 221 | const afterPrebuilds = du(path.join(stageRoot, 'node_modules')) |
| 210 | 222 | console.log(' after prebuilds prune: ' + fmtBytes(afterPrebuilds)) |
| 211 | 223 | |
| 212 | 224 | // Prune non-target bare-runtime per-arch packages. We only need the |
| 213 | 225 | // target's binary; the others (bare-runtime-darwin-arm64, etc.) are |
| 214 | 226 | // pulled by npm as optional deps but useless on this bundle. |
| 215 | | pruneOtherBareArches(path.join(stageRoot, 'node_modules'), LABEL) |
| 227 | pruneOtherBareArches(path.join(stageRoot, 'node_modules'), ALL_LABELS) |
| 216 | 228 | const afterArches = du(path.join(stageRoot, 'node_modules')) |
| 217 | 229 | console.log(' after bare-runtime arch prune: ' + fmtBytes(afterArches)) |
| 218 | 230 | |
| … | … | @@ -230,6 +242,27 @@ fs.copyFileSync(BARE_BIN_SRC, bareBinDest) |
| 230 | 242 | fs.chmodSync(bareBinDest, 0o755) |
| 231 | 243 | console.log(' + runtime/bare (' + fmtBytes(fs.statSync(bareBinDest).size) + ')') |
| 232 | 244 | |
| 245 | // Extra arches live at by-arch/<label>/runtime/bare. runtime/bare stays the |
| 246 | // BUILD host's copy so existing launchers, which hardcode that path, keep |
| 247 | // working against an older tree. |
| 248 | for (const label of EXTRA_LABELS) { |
| 249 | const src = path.join(ROOT, 'node_modules', 'bare-runtime-' + label, 'bin', 'bare') |
| 250 | if (!fs.existsSync(src)) { |
| 251 | // Hard failure: a silently-missing arch produces a by-arch/ tree that |
| 252 | // LOOKS multi-arch and still cannot run on that host. |
| 253 | console.error('error: --extra-arch ' + label + ' requested but ' + src + ' not found.') |
| 254 | console.error(' Vendor it first: npm pack bare-runtime-' + label + '@<pinned>') |
| 255 | console.error(' and extract into node_modules/bare-runtime-' + label + '/') |
| 256 | process.exit(1) |
| 257 | } |
| 258 | const dir = path.join(stageRoot, 'by-arch', label, 'runtime') |
| 259 | fs.mkdirSync(dir, { recursive: true }) |
| 260 | const dest = path.join(dir, 'bare') |
| 261 | fs.copyFileSync(src, dest) |
| 262 | fs.chmodSync(dest, 0o755) |
| 263 | console.log(' + by-arch/' + label + '/runtime/bare (' + fmtBytes(fs.statSync(dest).size) + ')') |
| 264 | } |
| 265 | |
| 233 | 266 | // ── Shell launcher at bin/<BIN_NAME> + entry preserved as .bare.js ── |
| 234 | 267 | // |
| 235 | 268 | // install.sh symlinks ~/.local/bin/<BIN_NAME> -> <bootstrap>/bin/<BIN_NAME>, |
| … | … | @@ -269,7 +302,12 @@ const launcherScript = `#!/bin/sh |
| 269 | 302 | # (or wherever install.sh placed it) still finds the bundled runtime. |
| 270 | 303 | HERE="$(cd "$(dirname "$(readlink -f "$0" || echo "$0")")" >/dev/null 2>&1 && pwd)" |
| 271 | 304 | ROOT="$(cd "$HERE/.." >/dev/null 2>&1 && pwd)" |
| 272 | | exec "$ROOT/runtime/bare" "$ROOT/${entryFromRoot}" "$@" |
| 305 | # Prefer this host's arch when the tree carries several; fall back to the |
| 306 | # build host's copy for single-arch trees. |
| 307 | HOSTLABEL="$(uname -s | tr 'A-Z' 'a-z')-$(uname -m | sed 's/x86_64/x64/; s/aarch64/arm64/')" |
| 308 | BARE="$ROOT/by-arch/$HOSTLABEL/runtime/bare" |
| 309 | [ -x "$BARE" ] || BARE="$ROOT/runtime/bare" |
| 310 | exec "$BARE" "$ROOT/${entryFromRoot}" "$@" |
| 273 | 311 | ` |
| 274 | 312 | fs.writeFileSync(launcherPath, launcherScript) |
| 275 | 313 | fs.chmodSync(launcherPath, 0o755) |
| … | … | @@ -506,7 +544,8 @@ function pruneForceStrip (topNodeModules) { |
| 506 | 544 | // The fix there resolves a nested copy against its NEAREST node_modules |
| 507 | 545 | // ancestor, not just the bundle root — see that module for why. |
| 508 | 546 | |
| 509 | | function prunePrebuilds (rootDir, targetLabel) { |
| 547 | function prunePrebuilds (rootDir, targetLabels) { |
| 548 | const keep = new Set([].concat(targetLabels)) |
| 510 | 549 | function visit (dir) { |
| 511 | 550 | let entries |
| 512 | 551 | try { entries = fs.readdirSync(dir) } catch { return } |
| … | … | @@ -517,7 +556,7 @@ function prunePrebuilds (rootDir, targetLabel) { |
| 517 | 556 | if (!stat.isDirectory() || stat.isSymbolicLink()) continue |
| 518 | 557 | if (name === 'prebuilds') { |
| 519 | 558 | for (const arch of fs.readdirSync(p)) { |
| 520 | | if (arch !== targetLabel) fs.rmSync(path.join(p, arch), { recursive: true, force: true }) |
| 559 | if (!keep.has(arch)) fs.rmSync(path.join(p, arch), { recursive: true, force: true }) |
| 521 | 560 | } |
| 522 | 561 | } else { |
| 523 | 562 | visit(p) |
| … | … | @@ -527,9 +566,10 @@ function prunePrebuilds (rootDir, targetLabel) { |
| 527 | 566 | visit(rootDir) |
| 528 | 567 | } |
| 529 | 568 | |
| 530 | | function pruneOtherBareArches (topNodeModules, keepLabel) { |
| 569 | function pruneOtherBareArches (topNodeModules, keepLabels) { |
| 570 | const keep = new Set([].concat(keepLabels).map((l) => 'bare-runtime-' + l)) |
| 531 | 571 | for (const name of fs.readdirSync(topNodeModules)) { |
| 532 | | if (name.startsWith('bare-runtime-') && name !== 'bare-runtime-' + keepLabel) { |
| 572 | if (name.startsWith('bare-runtime-') && !keep.has(name)) { |
| 533 | 573 | fs.rmSync(path.join(topNodeModules, name), { recursive: true, force: true }) |
| 534 | 574 | } |
| 535 | 575 | } |