import { spawnSync } from "node:child_process"; import { fileURLToPath } from "node:url"; import path from "node:path"; import { getReleaseArch } from "./release-artifact-utils.mjs"; const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const hostArch = getReleaseArch(process.arch); const targetArchs = process.env.ELECTROBUN_TARGET_ARCH ? [getReleaseArch(process.env.ELECTROBUN_TARGET_ARCH)] : ["arm64", "x64"]; function canRunUnderArch(archFlag) { const result = spawnSync("arch", [archFlag, "true"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], }); return result.status === 0; } function run(command, args, options = {}) { const result = spawnSync(command, args, { cwd: rootDir, stdio: "inherit", env: process.env, ...options, }); if (result.status !== 0) { process.exit(result.status ?? 1); } } function buildElectrobunEnv(targetArch) { return { ...process.env, ELECTROBUN_BUILD_ENV: "stable", ELECTROBUN_OS: "macos", ELECTROBUN_ARCH: targetArch, ELECTROBUN_FORCE_ARCH: targetArch, ELECTROBUN_TARGET_ARCH: targetArch, NODE_ENV: "production", }; } function getInvocation(targetArch) { const env = buildElectrobunEnv(targetArch); const runScript = path.join(rootDir, "scripts/run-electrobun-build.mjs"); if (targetArch === hostArch) { return { command: "bun", args: [runScript], env }; } // Apple Silicon can build x64 under Rosetta; Electrobun sees an x64 host. if (targetArch === "x64" && hostArch === "arm64" && canRunUnderArch("-x86_64")) { return { command: "arch", args: ["-x86_64", "bun", runScript], env, }; } // Intel (and any host) can cross-build arm64 via the patched Electrobun Bun CLI. if (targetArch === "arm64" && hostArch === "x64") { return { command: "bun", args: [runScript], env }; } return null; } const orderedTargets = [...targetArchs].sort((a, b) => { if (a === hostArch) return -1; if (b === hostArch) return 1; return 0; }); console.log(`Host architecture: ${hostArch}`); console.log(`Build order: ${orderedTargets.join(", ")}`); let builtCount = 0; for (const targetArch of orderedTargets) { const invocation = getInvocation(targetArch); if (!invocation) { console.error( `Cannot build macOS ${targetArch} from host ${hostArch}.`, ); continue; } console.log(`\n=== Building macOS ${targetArch} (host ${hostArch}) ===`); console.log( `ELECTROBUN_BUILD_ENV=stable ELECTROBUN_OS=macos ELECTROBUN_ARCH=${targetArch}\n`, ); run(invocation.command, invocation.args, { env: invocation.env }); builtCount += 1; } if (builtCount === 0) { console.error("No macOS architectures were built."); process.exit(1); } if (builtCount < targetArchs.length) { console.error( `Built ${builtCount}/${targetArchs.length} macOS architectures.`, ); process.exit(1); } console.log(`\nBuilt macOS architectures: ${orderedTargets.join(", ")}`);