feat: establish reproducible FreeCAD web compatibility baseline
This commit is contained in:
@@ -1,29 +1,95 @@
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { access, readFile, writeFile } from 'node:fs/promises'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
const root = resolve(new URL('..', import.meta.url).pathname)
|
||||
const toolchain = JSON.parse(await readFile(new URL('../config/freecad-toolchain.json', import.meta.url), 'utf8'))
|
||||
const source = resolve(root, toolchain.sourceCheckout.defaultDirectory)
|
||||
const build = resolve(root, '.cache/freecad/build-native')
|
||||
const install = resolve(root, '.cache/freecad/install-native')
|
||||
const profile = process.env.FREECAD_ORACLE_PROFILE || 'headless'
|
||||
if (!['headless', 'desktop'].includes(profile)) throw new Error(`Unknown FreeCAD oracle profile: ${profile}`)
|
||||
const build = resolve(root, profile === 'desktop' ? '.cache/freecad/build-desktop' : '.cache/freecad/build-native')
|
||||
const install = resolve(root, profile === 'desktop' ? '.cache/freecad/install-desktop' : '.cache/freecad/install-native')
|
||||
const sysroot = resolve(root, '.cache/freecad/sysroot')
|
||||
const bootstrap = resolve(root, 'config/freecad-native-bootstrap.cmake')
|
||||
const revision = execFileSync('git', ['-C', source, 'rev-parse', 'HEAD'], { encoding: 'utf8' }).trim()
|
||||
if (revision !== toolchain.source.commit) throw new Error(`FreeCAD source must be checked out at ${toolchain.source.commit}; received ${revision}.`)
|
||||
|
||||
const desktopModules = ['ADDONMGR', 'ASSEMBLY', 'BIM', 'CAM', 'DRAFT', 'FEM', 'FLAT_MESH', 'HELP', 'IDF', 'IMPORT', 'INSPECTION', 'MATERIAL', 'MEASURE', 'MESH', 'MESH_PART', 'OPENSCAD', 'PART', 'PART_DESIGN', 'PLOT', 'POINTS', 'REVERSEENGINEERING', 'ROBOT', 'SHOW', 'SKETCHER', 'SPREADSHEET', 'START', 'SURFACE', 'TECHDRAW', 'TEST', 'TUX', 'WEB']
|
||||
const disabledModules = ['ADDONMGR', 'ASSEMBLY', 'BIM', 'CAM', 'DRAFT', 'FEM', 'FLAT_MESH', 'HELP', 'IDF', 'IMPORT', 'INSPECTION', 'MATERIAL_EXTERNAL', 'MESH', 'MESH_PART', 'OPENSCAD', 'PART_DESIGN', 'PLOT', 'POINTS', 'REVERSEENGINEERING', 'ROBOT', 'SHOW', 'SKETCHER', 'SPREADSHEET', 'START', 'SURFACE', 'TECHDRAW', 'TEST', 'TUX', 'WEB']
|
||||
const definitions = [
|
||||
`-DCMAKE_BUILD_TYPE=Release`,
|
||||
`-DCMAKE_INSTALL_PREFIX=${install}`,
|
||||
`-DCMAKE_PROJECT_INCLUDE=${bootstrap}`,
|
||||
'-DBUILD_GUI=OFF',
|
||||
'-DBUILD_PART=ON',
|
||||
'-DENABLE_DEVELOPER_TESTS=OFF',
|
||||
'-DFREECAD_USE_FREETYPE=OFF',
|
||||
`-DBUILD_GUI=${profile === 'desktop' ? 'ON' : 'OFF'}`,
|
||||
`-DBUILD_PART=${profile === 'desktop' ? 'ON' : 'ON'}`,
|
||||
`-DFREECAD_USE_FREETYPE=${profile === 'desktop' ? 'ON' : 'OFF'}`,
|
||||
'-DFREECAD_USE_EXTERNAL_FMT=ON',
|
||||
'-DFREECAD_USE_PCH=OFF',
|
||||
'-DINSTALL_TO_SITEPACKAGES=OFF',
|
||||
...disabledModules.map((module) => `-DBUILD_${module}=OFF`),
|
||||
...(profile === 'desktop'
|
||||
? [
|
||||
`-DCMAKE_PREFIX_PATH=${resolve(root, '.cache/freecad/sysroot/usr')}`,
|
||||
`-DCMAKE_LIBRARY_PATH=${resolve(root, '.cache/freecad/sysroot/usr/lib/x86_64-linux-gnu')}`,
|
||||
`-DCMAKE_INCLUDE_PATH=${resolve(root, '.cache/freecad/sysroot/usr/include')}`,
|
||||
'-DFREECAD_CHECK_PIVY=OFF',
|
||||
'-DFREECAD_USE_SHIBOKEN=ON',
|
||||
'-DFREECAD_USE_PYSIDE=ON',
|
||||
'-DFREECAD_USE_EXTERNAL_SMESH=OFF',
|
||||
'-DCOIN3D_VERSION=4.0.3',
|
||||
'-DBUILD_CLOUD=OFF',
|
||||
'-DBUILD_JTREADER=OFF',
|
||||
'-DBUILD_VR=OFF',
|
||||
'-DBUILD_TEMPLATE=OFF',
|
||||
'-DBUILD_SANDBOX=OFF',
|
||||
...desktopModules.map((module) => `-DBUILD_${module}=ON`),
|
||||
]
|
||||
: disabledModules.map((module) => `-DBUILD_${module}=OFF`)),
|
||||
]
|
||||
execFileSync('cmake', ['-S', source, '-B', build, '-G', 'Ninja', '-U', 'CMAKE_PROJECT_TOP_LEVEL_INCLUDES', ...definitions], { cwd: root, stdio: 'inherit' })
|
||||
console.log(`FreeCAD native build configured: ${build}`)
|
||||
const cmakeEnv = profile === 'desktop'
|
||||
? {
|
||||
...process.env,
|
||||
PKG_CONFIG_PATH: `${resolve(root, '.cache/freecad/sysroot/usr/lib/x86_64-linux-gnu/pkgconfig')}${process.env.PKG_CONFIG_PATH ? `:${process.env.PKG_CONFIG_PATH}` : ''}`,
|
||||
PKG_CONFIG_SYSROOT_DIR: resolve(root, '.cache/freecad/sysroot'),
|
||||
PYTHONPATH: `${resolve(root, '.cache/freecad/sysroot/usr/lib/python3/dist-packages')}${process.env.PYTHONPATH ? `:${process.env.PYTHONPATH}` : ''}`,
|
||||
LD_LIBRARY_PATH: `${resolve(root, '.cache/freecad/sysroot/usr/lib/x86_64-linux-gnu')}${process.env.LD_LIBRARY_PATH ? `:${process.env.LD_LIBRARY_PATH}` : ''}`,
|
||||
}
|
||||
: process.env
|
||||
if (profile === 'desktop') {
|
||||
// Debian's extracted Coin/SoQt configs retain their host prefix. Relocate only
|
||||
// the generated local sysroot copies so CMake never depends on /usr artifacts.
|
||||
const sysrootCmakeFiles = [
|
||||
'usr/lib/x86_64-linux-gnu/cmake/Coin-4.0.3/coin-config.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/Coin-4.0.3/coin-export.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/Coin-4.0.3/coin-export-none.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/SoQt-1.6.3/soqt-config.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/SoQt-1.6.3/soqt-export.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/SoQt-1.6.3/soqt-export-none.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/Shiboken6/Shiboken6Config.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/Shiboken6/Shiboken6Config.abi3.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/Shiboken6/Shiboken6Targets.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/Shiboken6/Shiboken6Targets-release.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/PySide6/PySide6Config.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/PySide6/PySide6Config.abi3.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/PySide6/PySide6Targets.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/PySide6/PySide6Targets-release.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/PySide6Tools/PySide6ToolsConfig.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/PySide6Tools/PySide6ToolsTargets.cmake',
|
||||
'usr/lib/x86_64-linux-gnu/cmake/PySide6Tools/PySide6ToolsTargets-release.cmake',
|
||||
]
|
||||
for (const relative of sysrootCmakeFiles) {
|
||||
const file = resolve(sysroot, relative)
|
||||
try {
|
||||
await access(file)
|
||||
const original = await readFile(file, 'utf8')
|
||||
const relocated = original
|
||||
.replaceAll('"/usr/', `"${sysroot}/usr/`)
|
||||
.replaceAll('"/usr"', `"${sysroot}/usr"`)
|
||||
if (relocated !== original) await writeFile(file, relocated)
|
||||
} catch (error) {
|
||||
if (error?.code !== 'ENOENT') throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
execFileSync('cmake', ['-S', source, '-B', build, '-G', 'Ninja', '-U', 'CMAKE_PROJECT_TOP_LEVEL_INCLUDES', ...definitions], { cwd: root, stdio: 'inherit', env: cmakeEnv })
|
||||
console.log(`FreeCAD ${profile} oracle build configured: ${build}`)
|
||||
|
||||
Reference in New Issue
Block a user