Files
FreeCADWasmDev/tools/build_ifcopenshell_native.mjs
wangdequan 72152ef356 Save verified native IFC import and user validation evidence
Real IFC2X3/IFC4 import tested. Full BIM authoring/export remains out of scope; 349-second building import performance remains to optimize.
2026-09-16 04:27:37 +08:00

48 lines
3.4 KiB
JavaScript

import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { spawn } from 'node:child_process';
import { createHash } from 'node:crypto';
const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
const dependencies=path.join(root,'freecad-source/build-web');
const source=process.env.FREECAD_IFC_SOURCE;
if(!source||!fs.existsSync(path.join(source,'cmake/CMakeLists.txt')))throw Error('Set FREECAD_IFC_SOURCE to a real IfcOpenShell source tree');
const build=path.resolve(process.env.FREECAD_IFC_BUILD??path.join(dependencies,'ifcopenshell-native/build'));
const output=path.join(root,'docs/current/user-tests-20260915',`ifc-build-${new Date().toISOString().replace(/[:.]/g,'-')}`);
fs.mkdirSync(output,{recursive:true});
const stages=[];
async function run(stage,command,args,timeout=1800000){
const started=performance.now(),log=fs.openSync(path.join(output,`${stage}.log`),'w');
const child=spawn(command,args,{cwd:root,stdio:['ignore',log,log],detached:true});
let timedOut=false;
const timer=setTimeout(()=>{timedOut=true;process.kill(-child.pid,'SIGTERM');},timeout);
const code=await new Promise(resolve=>{child.once('close',resolve);child.once('error',()=>resolve(-1));});
clearTimeout(timer);fs.closeSync(log);
stages.push({stage,command,args,exitCode:code,timedOut,seconds:(performance.now()-started)/1000});
fs.writeFileSync(path.join(output,'results.json'),JSON.stringify({source,build,stages},null,2)+'\n');
console.log(JSON.stringify(stages.at(-1)));
if(code!==0)throw Error(`${stage} failed; see ${output}`);
}
await run('configure','cmake',['-S',path.join(source,'cmake'),'-B',build,'-G','Ninja',
'-DCMAKE_TOOLCHAIN_FILE=/usr/share/emscripten/cmake/Modules/Platform/Emscripten.cmake',
'-DCMAKE_BUILD_TYPE=Release','-DCMAKE_CXX_FLAGS=-pthread -fexceptions','-DCMAKE_C_FLAGS=-pthread',
'-DCMAKE_CXX_FLAGS_RELEASE=-O1 -DNDEBUG','-DWASM_BUILD=ON','-DBUILD_SHARED_LIBS=OFF',
'-DBUILD_IFCPYTHON=OFF','-DBUILD_CONVERT=OFF','-DBUILD_GEOMSERVER=OFF','-DBUILD_IFCGEOM=ON',
'-DWITH_OPENCASCADE=ON','-DWITH_CGAL=OFF','-DCOLLADA_SUPPORT=OFF','-DHDF5_SUPPORT=OFF','-DIFCXML_SUPPORT=OFF',
'-DSCHEMA_VERSIONS=2x3;4','-DUSE_CCACHE=OFF','-DNO_WARN=ON',
`-DOCC_INCLUDE_DIR=${dependencies}/occt-pthread-install/include/opencascade`,
`-DOCC_LIBRARY_DIR=${dependencies}/occt-pthread-install/lib`,
`-DBOOST_ROOT=${dependencies}/boost-pthread-install`,'-DBoost_NO_SYSTEM_PATHS=ON',
'-DEigen3_DIR=/usr/share/eigen3/cmake','-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=NEVER',
'-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=NEVER','-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=NEVER']);
await run('compile','cmake',['--build',build,'--target','IfcParse','IfcGeom','geometry_kernel_opencascade','-j2']);
const artifacts=['ifcparse/libIfcParse.a','ifcgeom/libIfcGeom.a','ifcgeom/kernels/libgeometry_kernel_opencascade.a'].map(name=>{
const file=path.join(build,name);return {file,size:fs.statSync(file).size,sha256:createHash('sha256').update(fs.readFileSync(file)).digest('hex')};
});
fs.writeFileSync(path.join(output,'artifacts.json'),JSON.stringify(artifacts,null,2)+'\n');
await run('host-configure','cmake',['-S','freecad-source','-B',path.join(dependencies,'configure'),
`-DFREECAD_WEB_IFCOPENSHELL_SOURCE=${path.resolve(source)}`,`-DFREECAD_WEB_IFCOPENSHELL_BUILD=${build}`]);
await run('host-link','python3',['tools/build_web_module_artifacts.py','--target','FreeCADWebPartBoxProbe','--jobs','2','--timeout','600']);
console.log(output);