farmcontrol-ui/scripts/build-macos-effects.mjs
Tom Butcher a8339aa9f8
Some checks failed
farmcontrol/farmcontrol-ui/pipeline/head There was a failure building this commit
Enhance macOS window effects validation and build process
- Introduced functions to validate the macOS dynamic library, ensuring it meets size and architecture requirements.
- Updated build scripts to resolve target architecture dynamically and validate the generated dylib.
- Enhanced the macOS window effects implementation to include traffic light positioning and improved error handling.
- Refactored the dylib path resolution logic to support multiple potential locations for the library.
2026-08-02 13:05:28 +01:00

122 lines
3.0 KiB
JavaScript

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})`,
);