import { existsSync, mkdirSync, statSync, writeFileSync } from "node:fs"; import path from "node:path"; import { spawnSync } from "node:child_process"; import { fileURLToPath } from "node:url"; const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const srcFile = path.join(rootDir, "native/macos/window-effects.mm"); export const outFile = path.join(rootDir, "src/bun/libMacWindowEffects.dylib"); const minDylibBytes = 10_000; function normalizeArch(value) { if (value === "x64" || value === "amd64" || value === "x86_64") { return "x86_64"; } if (value === "arm64" || value === "aarch64") { return "arm64"; } return null; } export function resolveTargetArch() { return ( normalizeArch(process.env.ELECTROBUN_TARGET_ARCH) || normalizeArch(process.env.ELECTROBUN_ARCH) || normalizeArch(process.arch) || "arm64" ); } function createPlaceholder() { mkdirSync(path.dirname(outFile), { recursive: true }); writeFileSync(outFile, ""); console.log(`build-macos-effects: created placeholder dylib at ${outFile}`); } function readDylibArch(dylibPath) { const lipo = spawnSync("lipo", ["-info", dylibPath], { encoding: "utf8" }); if (lipo.status === 0) { return lipo.stdout; } const file = spawnSync("file", ["-b", dylibPath], { encoding: "utf8" }); return file.stdout || ""; } export function validateMacosEffectsDylib({ dylibPath = outFile, expectedArch = resolveTargetArch(), required = process.platform === "darwin", } = {}) { if (!required) { return true; } if (!existsSync(dylibPath)) { console.error(`build-macos-effects: missing dylib at ${dylibPath}`); return false; } const { size } = statSync(dylibPath); if (size < minDylibBytes) { console.error( `build-macos-effects: dylib at ${dylibPath} is too small (${size} bytes)`, ); return false; } const archInfo = readDylibArch(dylibPath); if (!archInfo.includes(expectedArch)) { console.error( `build-macos-effects: dylib architecture mismatch (expected ${expectedArch}): ${archInfo.trim()}`, ); return false; } return true; } if (process.platform !== "darwin") { createPlaceholder(); process.exit(0); } if (!existsSync(srcFile)) { console.error(`build-macos-effects: missing source file ${srcFile}`); process.exit(1); } mkdirSync(path.dirname(outFile), { recursive: true }); const targetArch = resolveTargetArch(); const result = spawnSync( "xcrun", [ "clang++", "-dynamiclib", "-fobjc-arc", "-arch", targetArch, "-mmacosx-version-min=11.0", "-framework", "Cocoa", srcFile, "-o", outFile, ], { cwd: rootDir, stdio: "inherit" }, ); if (result.status !== 0) { process.exit(result.status ?? 1); } if (!validateMacosEffectsDylib({ dylibPath: outFile, expectedArch: targetArch })) { process.exit(1); } const { size } = statSync(outFile); console.log( `build-macos-effects: built ${outFile} (${size} bytes, arch=${targetArch})`, );