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.
106 lines
7.4 KiB
JavaScript
106 lines
7.4 KiB
JavaScript
import { mkdir, writeFile } from 'node:fs/promises'
|
|
import { execFile } from 'node:child_process'
|
|
import { promisify } from 'node:util'
|
|
import { resolve } from 'node:path'
|
|
|
|
const root = resolve(new URL('..', import.meta.url).pathname)
|
|
const run = promisify(execFile)
|
|
const sourceDir = resolve(root, '.cache/toolchains/freecad-naming-sdk/source-occt8')
|
|
const buildDir = resolve(root, '.cache/toolchains/freecad-naming-sdk/build-wasm')
|
|
const installDir = resolve(root, '.cache/toolchains/freecad-naming-sdk/install-wasm')
|
|
const qtPrefix = resolve(root, '.cache/toolchains/qt6/install-wasm-freecad')
|
|
const yamlPrefix = resolve(root, '.cache/toolchains/yaml-cpp/install-wasm')
|
|
const icuPrefix = resolve(root, '.cache/toolchains/icu/install-wasm')
|
|
const pythonPrefix = resolve(root, '.cache/toolchains/python/install-wasm')
|
|
const xercesPrefix = resolve(root, '.cache/toolchains/xerces-c/install-wasm')
|
|
const occtBuild = resolve(root, '.cache/bitbybit/occt-history-build-offline')
|
|
const occtSource = resolve(root, '.cache/occt/occt')
|
|
const offlineSysroot = resolve(root, '.cache/offline-sysroot')
|
|
const boostPrefix = resolve(root, '.cache/toolchains/boost/install-wasm')
|
|
const reportPath = resolve(root, '.cache/toolchains/freecad-naming-sdk/configure-report.json')
|
|
const command = [
|
|
'emcmake', 'cmake', '--fresh', '-S', sourceDir, '-B', buildDir, '-G', 'Ninja',
|
|
'-DCMAKE_BUILD_TYPE=Release',
|
|
`-DCMAKE_INSTALL_PREFIX=${installDir}`,
|
|
`-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=${resolve(root, 'config/freecad-wasm-sdk-bootstrap.cmake')}`,
|
|
'-DBUILD_GUI=OFF', '-DBUILD_PART=ON', '-DBUILD_MATERIAL=ON', '-DBUILD_BIM=OFF', '-DBUILD_FLAT_MESH=OFF',
|
|
'-DBUILD_PART_DESIGN=OFF', '-DBUILD_SKETCHER=OFF',
|
|
'-DBUILD_MESH=OFF', '-DBUILD_MESH_PART=OFF', '-DBUILD_FEM=OFF', '-DBUILD_CAM=OFF', '-DBUILD_ASSEMBLY=OFF',
|
|
'-DBUILD_DRAFT=OFF', '-DBUILD_DRAWING=OFF', '-DBUILD_HELP=OFF', '-DBUILD_IDF=OFF', '-DBUILD_IMPORT=OFF',
|
|
'-DBUILD_INSPECTION=OFF', '-DBUILD_OPENSCAD=OFF', '-DBUILD_PLOT=OFF', '-DBUILD_POINTS=OFF',
|
|
'-DBUILD_REVERSEENGINEERING=OFF', '-DBUILD_ROBOT=OFF', '-DBUILD_SHOW=OFF', '-DBUILD_SPREADSHEET=OFF',
|
|
'-DBUILD_START=OFF', '-DBUILD_SURFACE=OFF', '-DBUILD_TECHDRAW=OFF', '-DBUILD_TEST=OFF', '-DBUILD_TUX=OFF',
|
|
'-DBUILD_WEB=OFF', '-DBUILD_ADDONMGR=OFF', '-DBUILD_MEASURE=OFF', '-DBUILD_CLOUD=OFF', '-DBUILD_JTREADER=OFF',
|
|
'-DBUILD_VR=OFF', '-DBUILD_TEMPLATE=OFF', '-DBUILD_SANDBOX=OFF', '-DENABLE_DEVELOPER_TESTS=OFF',
|
|
'-DFREECAD_USE_FREETYPE=OFF', '-DFREECAD_USE_EXTERNAL_FMT=ON', '-DFREECAD_CHECK_PIVY=OFF',
|
|
'-DINSTALL_TO_SITEPACKAGES=OFF', '-DFREECAD_USE_CCACHE=OFF', '-DBUILD_DYNAMIC_LINK_PYTHON=OFF',
|
|
`-DFREECAD_WASM_OFFLINE_SYSROOT=${offlineSysroot}`,
|
|
`-DCMAKE_PREFIX_PATH=${qtPrefix};${yamlPrefix};${icuPrefix};${xercesPrefix}`,
|
|
`-DQt6_DIR=${resolve(qtPrefix, 'lib/cmake/Qt6')}`,
|
|
`-DQt6Core_DIR=${resolve(qtPrefix, 'lib/cmake/Qt6Core')}`,
|
|
`-DQt6Concurrent_DIR=${resolve(qtPrefix, 'lib/cmake/Qt6Concurrent')}`,
|
|
`-DQt6Network_DIR=${resolve(qtPrefix, 'lib/cmake/Qt6Network')}`,
|
|
`-DQt6Xml_DIR=${resolve(qtPrefix, 'lib/cmake/Qt6Xml')}`,
|
|
`-DQt6ZlibPrivate_DIR=${resolve(qtPrefix, 'lib/cmake/Qt6ZlibPrivate')}`,
|
|
`-DQt6BundledZLIB_DIR=${resolve(qtPrefix, 'lib/cmake/Qt6BundledZLIB')}`,
|
|
`-DQt6BundledPcre2_DIR=${resolve(qtPrefix, 'lib/cmake/Qt6BundledPcre2')}`,
|
|
`-DZLIB_INCLUDE_DIR=${resolve(qtPrefix, 'include/QtZlib')}`,
|
|
`-DZLIB_LIBRARY=${resolve(qtPrefix, 'lib/libQt6BundledZLIB.a')}`,
|
|
`-Dyaml-cpp_DIR=${resolve(yamlPrefix, 'lib/cmake/yaml-cpp')}`,
|
|
`-DICU_ROOT=${icuPrefix}`,
|
|
`-DICU_INCLUDE_DIR=${resolve(icuPrefix, 'include')}`,
|
|
`-DICU_UC_LIBRARY_RELEASE=${resolve(icuPrefix, 'lib/libicuuc.a')}`,
|
|
`-DICU_I18N_LIBRARY_RELEASE=${resolve(icuPrefix, 'lib/libicui18n.a')}`,
|
|
`-DXercesC_INCLUDE_DIR=${resolve(xercesPrefix, 'include')}`,
|
|
`-DXercesC_LIBRARY=${resolve(xercesPrefix, 'lib/libxerces-c.a')}`,
|
|
'-DPython3_EXECUTABLE=/usr/bin/python3.13',
|
|
`-DPython3_INCLUDE_DIR=${resolve(pythonPrefix, 'include/python3.13')}`,
|
|
`-DPython3_INCLUDE_DIRS=${resolve(pythonPrefix, 'include/python3.13')}`,
|
|
`-DPython3_LIBRARY=${resolve(pythonPrefix, 'lib/libpython3.13.a')}`,
|
|
'-DOCCT_CMAKE_FALLBACK=ON',
|
|
`-DOCC_INCLUDE_DIR=${resolve(occtBuild, 'include/opencascade')}`,
|
|
`-DOCC_LIBRARY=${resolve(occtBuild, 'lin32/clang/lib/libTKernel.a')}`,
|
|
`-DFREECAD_WASM_OCCT_COMPAT_INCLUDE=${resolve(occtSource, 'src/Deprecated/NCollectionAliases')}`,
|
|
`-DEIGEN3_INCLUDE_DIR=${resolve(offlineSysroot, 'include/eigen3')}`,
|
|
`-DBOOST_WASM_ROOT=${boostPrefix}`,
|
|
`-DBoost_DIR=${resolve(root, 'config/cmake/boost')}`,
|
|
'-DBoost_USE_STATIC_LIBS=ON',
|
|
'-DQT_HOST_PATH=/usr',
|
|
'-DQT_HOST_PATH_CMAKE_DIR=/usr/lib/x86_64-linux-gnu/cmake',
|
|
'-DFETCHCONTENT_FULLY_DISCONNECTED=ON',
|
|
`-DCMAKE_TOOLCHAIN_FILE=${resolve(root, 'config/emscripten-freecad-candidate-toolchain.cmake')}`,
|
|
'-DCMAKE_AR=emar', '-DCMAKE_RANLIB=emranlib',
|
|
'-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER', '-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY', '-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY',
|
|
]
|
|
const startedAt = new Date().toISOString()
|
|
let status = 'configured'
|
|
let exitCode = 0
|
|
let output = ''
|
|
try {
|
|
const result = await run(command[0], command.slice(1), { cwd: root, maxBuffer: 16 * 1024 * 1024 })
|
|
output = `${result.stdout}${result.stderr}`
|
|
} catch (error) {
|
|
status = 'blocked'
|
|
exitCode = error.status ?? 1
|
|
output = `${error.stdout ?? ''}${error.stderr ?? ''}`
|
|
}
|
|
const missing = []
|
|
if (status === 'blocked') {
|
|
if (output.includes('Could not find a valid Qt installation') || output.includes('Could NOT find Qt6')) missing.push('Qt6 wasm package configuration')
|
|
if (output.includes('Could NOT find Python3')) missing.push('Emscripten Python3 development target')
|
|
if (output.includes('Could NOT find ICU') || output.includes('Failed to find all ICU components')) missing.push('ICU wasm static libraries')
|
|
if (output.includes('Could NOT find XercesC') || output.includes('Failed to find XercesC')) missing.push('Xerces-C wasm static library')
|
|
if (output.includes('Could NOT find ZLIB')) missing.push('ZLIB wasm static library')
|
|
if (output.includes('Could NOT find OCC') || output.includes('OpenCASCADE not found')) missing.push('OpenCASCADE wasm SDK')
|
|
if (output.includes('Could NOT find Eigen3') || output.includes('Eigen3 not found')) missing.push('Eigen3 headers')
|
|
if (output.includes('Could NOT find Boost') || output.includes('provided by "Boost"')) missing.push('Boost wasm static libraries')
|
|
if (output.includes('Could NOT find yaml-cpp') || output.includes('provided by "yaml-cpp"')) missing.push('yaml-cpp wasm package')
|
|
if (output.includes('Unknown CMake command "qt_add_translation"')) missing.push('Qt translation cross-build adapter')
|
|
if (output.includes('Qt6::Core') && output.includes('mkspecs/wasm-emscripten') && output.includes('non-existent path')) missing.push('Qt6 wasm mkspec installation')
|
|
if (missing.length === 0) missing.push('unclassified CMake configure failure')
|
|
}
|
|
await mkdir(resolve(root, '.cache/toolchains/freecad-naming-sdk'), { recursive: true })
|
|
await writeFile(reportPath, `${JSON.stringify({ schemaVersion: 1, status, exitCode, startedAt, command, missing, buildDir, outputTail: output.slice(-12000), productionPublication: false, boundary: { freecadNamingBuildStatus: 'contract-only', exTsn02: 'in_progress', systemExact: false, workerLinked: false, callbacks: [] } }, null, 2)}\n`)
|
|
console.log(JSON.stringify({ status, exitCode, report: reportPath, missing, productionPublication: false }, null, 2))
|
|
if (status !== 'configured') process.exit(exitCode)
|