66 lines · 2.6 KB · JavaScript
RawDownload
import * as NodeChildProcess from "node:child_process";import * as NodeFS from "node:fs";import * as NodePath from "node:path";import * as NodeURL from "node:url";import * as NodeUtil from "node:util"; // oxlint-disable-next-line t3code/no-global-process-runtime -- The native compiler targets the actual host; this script has no Effect runtime.const hostArch = process.arch;// oxlint-disable-next-line t3code/no-global-process-runtime -- Native compilation only runs on the actual Linux host.const hostPlatform = process.platform; const { values } = NodeUtil.parseArgs({  options: { output: { type: "string" }, arch: { type: "string", default: hostArch } },}); if (hostPlatform === "linux") {  const machine = { x64: 62, arm64: 183 }[values.arch];  if (machine === undefined) throw new Error(`Unsupported Linux architecture: ${values.arch}`);  const root = NodeURL.fileURLToPath(new URL("../../../native/browser-secret/", import.meta.url));  const source = NodePath.resolve(root, "main.c");  const output = values.output ?? NodePath.resolve(root, "build", values.arch, "t3-browser-secret");  const matchesArchitecture = (file) => {    const header = NodeFS.readFileSync(file).subarray(0, 20);    return header.toString("hex", 0, 6) === "7f454c460201" && header.readUInt16LE(18) === machine;  };  let current = false;  try {    current =      NodeFS.statSync(output).mtimeMs >=        Math.max(          NodeFS.statSync(source).mtimeMs,          NodeFS.statSync(NodeURL.fileURLToPath(import.meta.url)).mtimeMs,        ) && matchesArchitecture(output);  } catch {    /* The first build has no output yet. */  }  if (!current) {    let flags;    try {      flags = NodeChildProcess.execFileSync("pkg-config", ["--cflags", "--libs", "libsecret-1"], {        encoding: "utf8",      })        .trim()        .split(/\s+/);    } catch (cause) {      throw new Error(        "Building the Linux browser import helper requires pkg-config and libsecret development headers (Ubuntu/Debian: libsecret-1-dev).",        { cause },      );    }    NodeFS.mkdirSync(NodePath.dirname(output), { recursive: true });    const temporary = `${output}.${process.pid}.tmp`;    try {      NodeChildProcess.execFileSync(        process.env.CC || "cc",        ["-std=c11", "-O2", "-Wall", "-Wextra", "-Werror", source, "-o", temporary, ...flags],        { stdio: "inherit" },      );      if (!matchesArchitecture(temporary))        throw new Error(`C compiler did not produce a Linux ${values.arch} executable.`);      NodeFS.renameSync(temporary, output);    } finally {      NodeFS.rmSync(temporary, { force: true });    }  }}