Build and verify the candidate-only FreeCAD naming bridge and OCCT worker path, including three-stage StringHasher restoration. Add Datum, ShapeBinder, attachment-mode, and PartDesign structure oracles plus offline SDK build plans and CI boundary checks.
93 lines
3.9 KiB
JavaScript
93 lines
3.9 KiB
JavaScript
import { mkdir, writeFile } from 'node:fs/promises'
|
|
import { resolve, relative } from 'node:path'
|
|
import {
|
|
REQUIRED_FREECAD_NAMING_CALLBACKS,
|
|
REQUIRED_FREECAD_NAMING_DEFINITIONS,
|
|
inspectIncludeDirectory,
|
|
inspectPlannedLibrary,
|
|
inspectPlannedRuntimeAsset,
|
|
loadSdkPlan,
|
|
resolveFrom,
|
|
exists,
|
|
sha256File,
|
|
} from './freecad-naming-sdk-lib.mjs'
|
|
|
|
const root = resolve(new URL('..', import.meta.url).pathname)
|
|
const outputRoot = process.env.FREECAD_WASM_SDK_OUTPUT_DIR
|
|
? resolve(root, process.env.FREECAD_WASM_SDK_OUTPUT_DIR)
|
|
: resolve(root, '.cache/toolchains/freecad-naming-sdk')
|
|
const plan = await loadSdkPlan(root)
|
|
const fail = (message) => { throw new Error(`FreeCAD WASM SDK manifest generation: ${message}`) }
|
|
|
|
const libraries = []
|
|
for (const library of [...(plan.libraries ?? []), ...(plan.linkDependencies ?? [])]) {
|
|
const inspected = await inspectPlannedLibrary(root, library)
|
|
if (inspected.status !== 'verified') fail(`missing ${library.name} wasm static library: ${resolveFrom(root, library.path)}`)
|
|
libraries.push({
|
|
name: library.name,
|
|
path: relative(outputRoot, resolveFrom(root, library.path)),
|
|
sha256: inspected.sha256,
|
|
})
|
|
}
|
|
const includeDirs = []
|
|
for (const includeDir of plan.includeDirs ?? []) {
|
|
const inspected = await inspectIncludeDirectory(root, includeDir)
|
|
if (inspected.status !== 'verified') fail(`include directory ${includeDir.name} is incomplete: ${inspected.missingHeaders.join(', ')}`)
|
|
includeDirs.push(relative(outputRoot, resolveFrom(root, includeDir.path)))
|
|
}
|
|
const bridge = resolveFrom(root, plan.namingBridge.path)
|
|
if (!await exists(bridge)) fail(`missing naming bridge source: ${bridge}`)
|
|
const hostAdapter = resolveFrom(root, plan.namingBridge.hostAdapter)
|
|
if (!await exists(hostAdapter)) fail(`missing naming host adapter: ${hostAdapter}`)
|
|
const forceInclude = resolveFrom(root, plan.compileOptions.forceInclude)
|
|
if (!await exists(forceInclude)) fail(`missing force-include header: ${forceInclude}`)
|
|
if (plan.compileOptions.cxxStandard !== 'c++20' || plan.compileOptions.pthread !== true || JSON.stringify(plan.compileOptions.definitions) !== JSON.stringify(REQUIRED_FREECAD_NAMING_DEFINITIONS)) fail('compile options do not match the locked SDK contract')
|
|
const bridgeSha256 = await sha256File(bridge)
|
|
const runtimeAssets = []
|
|
for (const asset of plan.runtimeAssets ?? []) {
|
|
const inspected = await inspectPlannedRuntimeAsset(root, asset)
|
|
if (inspected.status !== 'verified') fail(`runtime asset ${asset.name} is incomplete: ${inspected.missingFiles.join(', ')}`)
|
|
runtimeAssets.push({
|
|
name: asset.name,
|
|
path: relative(outputRoot, resolveFrom(root, asset.path)),
|
|
preloadTo: asset.preloadTo,
|
|
files: inspected.files,
|
|
})
|
|
}
|
|
const manifest = {
|
|
schemaVersion: 1,
|
|
freecadVersion: plan.baseline.freecadVersion,
|
|
sourceCommit: plan.baseline.sourceCommit,
|
|
emscriptenVersion: plan.baseline.emscriptenVersion,
|
|
qtTarget: plan.baseline.target,
|
|
pythonTarget: plan.baseline.target,
|
|
includeDirs,
|
|
libraries,
|
|
namingBridge: {
|
|
source: relative(outputRoot, bridge),
|
|
sha256: bridgeSha256,
|
|
hostAdapter: relative(outputRoot, hostAdapter),
|
|
hostAdapterSha256: await sha256File(hostAdapter),
|
|
exports: [...REQUIRED_FREECAD_NAMING_CALLBACKS],
|
|
},
|
|
compileOptions: {
|
|
cxxStandard: plan.compileOptions.cxxStandard,
|
|
pthread: plan.compileOptions.pthread,
|
|
forceInclude: relative(outputRoot, forceInclude),
|
|
forceIncludeSha256: await sha256File(forceInclude),
|
|
definitions: [...plan.compileOptions.definitions],
|
|
},
|
|
runtimeAssets,
|
|
productionPublication: false,
|
|
boundary: { ...plan.boundary },
|
|
}
|
|
await mkdir(outputRoot, { recursive: true })
|
|
const output = resolve(outputRoot, 'manifest.json')
|
|
await writeFile(output, `${JSON.stringify(manifest, null, 2)}\n`)
|
|
console.log(JSON.stringify({
|
|
status: 'freecad-naming-sdk-manifest-generated',
|
|
output,
|
|
productionPublished: false,
|
|
systemExact: false,
|
|
}, null, 2))
|