#!/usr/bin/env node import assert from "node:assert/strict"; import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { spawnSync } from "node:child_process"; import { fileURLToPath } from "node:url"; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const upstream = path.resolve(root, "../linuxcnc"); const generator = path.join(upstream, "bin/halcompile"); const outDir = path.join(root, "build/generated/hal-components"); const components = ["and2", "or2", "not", "mux2", "scale"]; const sha256 = (data) => crypto.createHash("sha256").update(data).digest("hex"); const baseline = fs.readFileSync(path.join(root, "tools/upstream-baseline.txt"), "utf8").trim(); const head = spawnSync("git", ["-C", upstream, "rev-parse", "HEAD"], { encoding: "utf8" }); assert.equal(head.status, 0, head.stderr); assert.equal(head.stdout.trim(), baseline, "LinuxCNC baseline drift"); fs.mkdirSync(outDir, { recursive: true }); const generatorSha256 = sha256(fs.readFileSync(generator)); const rows = []; for (const component of components) { const sourcePath = `vendor/linuxcnc/src/hal/components/${component}.comp`; const generatedPath = `build/generated/hal-components/${component}.c`; const source = path.join(root, sourcePath); const generated = path.join(root, generatedPath); const result = spawnSync(generator, ["--preprocess", "-o", generated, sourcePath], { cwd: root, encoding: "utf8", }); assert.equal(result.status, 0, result.stderr || result.stdout); const normalized = `${fs .readFileSync(generated, "utf8") .replace(/^\/\* Autogenerated by .*? -- do not edit \*\//, "/* Autogenerated by locked LinuxCNC halcompile -- do not edit */")} int halcomp_${component}_start(char *instance_names, int instance_count) { names = instance_names; count = instance_count; int result = rtapi_app_main(); names = ""; count = 0; return result; } void halcomp_${component}_reset(void) { __comp_first_inst = NULL; __comp_last_inst = NULL; names = ""; count = 0; } `; fs.writeFileSync(generated, normalized); rows.push({ component, sourcePath, sourceSha256: sha256(fs.readFileSync(source)), generatedPath, generatedSha256: sha256(normalized), generator: "../linuxcnc/bin/halcompile --preprocess", generatorSha256, commandFingerprint: sha256(`halcompile:${generatorSha256}:--preprocess:${sourcePath}`), }); } const report = { apiName: "hal_component_generation_report", schemaVersion: 1, upstreamCommit: baseline, components: rows, }; fs.writeFileSync(path.join(outDir, "generation-report.json"), `${JSON.stringify(report, null, 2)}\n`); console.log(`hal_component_generated_count=${rows.length}`); console.log("hal_component_generation=ok");