#!/usr/bin/env node "use strict"; const { spawnSync } = require("child_process"); const fs = require("fs"); const path = require("path"); const os = require("os"); const root = path.resolve(__dirname, ".."); const bin = path.join(root, "bin"); const isWin = process.platform === "win32"; const isMac = process.platform === "darwin"; fs.mkdirSync(bin, { recursive: true }); function run(cmd, args, opts = {}) { console.log(`$ ${cmd} ${args.join(" ")}`); const result = spawnSync(cmd, args, { stdio: "inherit", ...opts }); if (result.error) { throw result.error; } if (result.status !== 0) { process.exit(result.status || 1); } } function which(cmd) { const probe = isWin ? "where" : "which"; const result = spawnSync(probe, [cmd], { encoding: "utf8" }); return result.status === 0; } function compileCpu() { const out = path.join(bin, isWin ? "med_cpu.exe" : "med_cpu"); const cpp = path.join(root, "native", "cpu", "med_cpu.cpp"); const csrc = path.join(root, "native", "common", "des.c"); const obj = path.join(bin, isWin ? "des.obj" : "des.o"); const compilers = isWin ? [ ["clang++", () => { run("clang", ["-O2", "-c", csrc, "-o", obj]); run("clang++", ["-O2", "-std=c++17", "-pthread", cpp, obj, "-o", out]); }], ["g++", () => { run("gcc", ["-O2", "-c", csrc, "-o", obj]); run("g++", ["-O2", "-std=c++17", "-pthread", cpp, obj, "-o", out]); }], ["cl", () => { run("cl", ["/nologo", "/O2", "/c", `/Fo${obj}`, csrc]); run("cl", ["/nologo", "/O2", "/EHsc", "/std:c++17", `/Fe:${out}`, cpp, obj]); }], ] : [ ["c++", () => { run("cc", ["-O2", "-c", csrc, "-o", obj]); run("c++", ["-O2", "-std=c++17", "-pthread", cpp, obj, "-o", out]); }], ]; let lastErr = null; for (const [cmd, fn] of compilers) { if (cmd !== "c++" && !which(cmd)) { continue; } try { fn(); console.log(`[native] CPU runner -> ${out}`); return; } catch (err) { lastErr = err; } } throw lastErr || new Error("no C++ compiler found for med_cpu"); } function compileMetal() { if (!isMac) { console.log("[native] skip Metal (not macOS)"); return; } const out = path.join(bin, "med_gpu"); run("clang", [ "-O2", "-fobjc-arc", "-framework", "Metal", "-framework", "Foundation", path.join(root, "native", "metal", "med_gpu.m"), "-o", out, ]); console.log(`[native] Metal runner -> ${out}`); } function compileCuda() { if (!isWin && process.env.FORCE_CUDA !== "1") { console.log("[native] skip CUDA (Windows-only unless FORCE_CUDA=1)"); return; } if (!which("nvcc")) { console.warn("[native] nvcc not found; CUDA backend skipped (CPU still works)"); return; } const out = path.join(bin, isWin ? "med_cuda.exe" : "med_cuda"); run("nvcc", ["-O2", "-std=c++17", "-o", out, path.join(root, "native", "cuda", "med_cuda.cu")]); console.log(`[native] CUDA runner -> ${out}`); } compileCpu(); compileMetal(); compileCuda(); console.log(`[native] done (${os.platform()} ${os.arch()})`);