Skip to content

Commit a99140a

Browse files
committed
refactor(build-infra): remove build-exec and use spawn directly
- Replace all exec/execCapture calls with direct spawn usage - Add WIN32 and spawn imports to all affected files - Remove build-exec.mjs dependency from build-infra helpers Files updated: - build-helpers.mjs: 5 exec/execCapture → spawn replacements - cmake-builder.mjs: 3 exec → spawn replacements - emscripten-builder.mjs: imports updated - rust-builder.mjs: imports updated - tool-installer.mjs: imports updated
1 parent 9555ef6 commit a99140a

File tree

9 files changed

+172
-65
lines changed

9 files changed

+172
-65
lines changed

packages/build-infra/lib/build-helpers.mjs

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import path from 'node:path'
1010

1111
import { whichBinSync } from '@socketsecurity/lib/bin'
1212

13-
import { exec, execCapture } from './build-exec.mjs'
13+
import { WIN32 } from '@socketsecurity/lib/constants/platform'
14+
import { spawn } from '@socketsecurity/lib/spawn'
15+
1416
import { printError, printStep, printWarning } from './build-output.mjs'
1517

1618
/**
@@ -24,8 +26,12 @@ export async function checkDiskSpace(dir, requiredGB = 5) {
2426
printStep('Checking disk space')
2527

2628
try {
27-
const { stdout } = await execCapture(`df -k "${dir}"`)
28-
const lines = stdout.trim().split('\n')
29+
const result = await spawn(`df -k "${dir}"`, [], {
30+
shell: WIN32,
31+
stdio: 'pipe',
32+
stdioString: true,
33+
})
34+
const lines = (result.stdout ?? '').trim().split('\n')
2935
if (lines.length < 2) {
3036
printWarning('Could not determine disk space')
3137
return { availableGB: null, sufficient: true }
@@ -83,10 +89,12 @@ export async function checkPythonVersion(minVersion = '3.6') {
8389
printStep('Checking Python version')
8490

8591
try {
86-
const { stdout } = await execCapture(
87-
'python3 -c "import sys; print(f\'{sys.version_info.major}.{sys.version_info.minor}\')"'
92+
const result = await spawn(
93+
'python3 -c "import sys; print(f\'{sys.version_info.major}.{sys.version_info.minor}\')"',
94+
[],
95+
{ shell: WIN32, stdio: 'pipe', stdioString: true }
8896
)
89-
const version = stdout.trim()
97+
const version = (result.stdout ?? '').trim()
9098
const [major, minor] = version.split('.').map(Number)
9199
const [minMajor, minMinor] = minVersion.split('.').map(Number)
92100

@@ -159,9 +167,13 @@ export async function smokeTestBinary(binaryPath, args = ['--version']) {
159167

160168
try {
161169
await fs.access(binaryPath)
162-
const { code } = await execCapture(`${binaryPath} ${args.join(' ')}`)
170+
const result = await spawn(`${binaryPath} ${args.join(' ')}`, [], {
171+
shell: WIN32,
172+
stdio: 'pipe',
173+
stdioString: true,
174+
})
163175

164-
if (code !== 0) {
176+
if ((result.status ?? 0) !== 0) {
165177
printError(`Binary failed smoke test: ${binaryPath}`)
166178
return false
167179
}
@@ -303,11 +315,13 @@ export async function cleanCheckpoint(buildDir) {
303315
export async function checkNetworkConnectivity() {
304316
try {
305317
// Try to reach GitHub (where we clone from).
306-
const result = await execCapture(
307-
'curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 https://github.com'
318+
const result = await spawn(
319+
'curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 https://github.com',
320+
[],
321+
{ shell: WIN32, stdio: 'pipe', stdioString: true }
308322
)
309323

310-
const statusCode = result.stdout.trim()
324+
const statusCode = (result.stdout ?? '').trim()
311325
return {
312326
connected:
313327
statusCode === '200' || statusCode === '301' || statusCode === '302',
@@ -326,12 +340,14 @@ export async function checkNetworkConnectivity() {
326340
*/
327341
export async function verifyGitTag(version) {
328342
try {
329-
const result = await execCapture(
330-
`git ls-remote --tags https://github.com/nodejs/node.git ${version}`
343+
const result = await spawn(
344+
`git ls-remote --tags https://github.com/nodejs/node.git ${version}`,
345+
[],
346+
{ shell: WIN32, stdio: 'pipe', stdioString: true }
331347
)
332348

333349
return {
334-
exists: result.stdout.includes(version),
350+
exists: (result.stdout ?? '').includes(version),
335351
output: result.stdout,
336352
}
337353
} catch {

packages/build-infra/lib/cmake-builder.mjs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
import { cpus } from 'node:os'
88

9-
import { exec } from './build-exec.mjs'
9+
import { WIN32 } from '@socketsecurity/lib/constants/platform'
10+
import { spawn } from '@socketsecurity/lib/spawn'
11+
1012
import { printStep } from './build-output.mjs'
1113

1214
export class CMakeBuilder {
@@ -28,9 +30,10 @@ export class CMakeBuilder {
2830
.map(([key, value]) => `-D${key}=${value}`)
2931
.join(' ')
3032

31-
await exec(
33+
await spawn(
3234
`cmake -S ${this.sourceDir} -B ${this.buildDir} ${cmakeArgs}`,
33-
{ stdio: 'inherit' }
35+
[],
36+
{ shell: WIN32, stdio: 'inherit' }
3437
)
3538
}
3639

@@ -46,9 +49,10 @@ export class CMakeBuilder {
4649
printStep('Building with CMake')
4750

4851
const jobs = parallel ? cpus().length : 1
49-
await exec(
52+
await spawn(
5053
`cmake --build ${this.buildDir} --target ${target} -j ${jobs}`,
51-
{ stdio: 'inherit' }
54+
[],
55+
{ shell: WIN32, stdio: 'inherit' }
5256
)
5357
}
5458

@@ -59,6 +63,10 @@ export class CMakeBuilder {
5963
*/
6064
async clean() {
6165
printStep('Cleaning CMake build')
62-
await exec(`cmake --build ${this.buildDir} --target clean`)
66+
await spawn(
67+
`cmake --build ${this.buildDir} --target clean`,
68+
[],
69+
{ shell: WIN32, stdio: 'inherit' }
70+
)
6371
}
6472
}

packages/build-infra/lib/emscripten-builder.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
import { cpus } from 'node:os'
88
import path from 'node:path'
99

10-
import { exec } from './build-exec.mjs'
10+
import { WIN32 } from '@socketsecurity/lib/constants/platform'
11+
import { spawn } from '@socketsecurity/lib/spawn'
12+
// Removed exec from './build-exec.mjs'
1113
import { printStep } from './build-output.mjs'
1214

1315
/**

packages/build-infra/lib/rust-builder.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
import { cpus } from 'node:os'
88
import path from 'node:path'
99

10-
import { exec } from './build-exec.mjs'
10+
import { WIN32 } from '@socketsecurity/lib/constants/platform'
11+
import { spawn } from '@socketsecurity/lib/spawn'
12+
// Removed exec from './build-exec.mjs'
1113
import { printStep } from './build-output.mjs'
1214

1315
/**

packages/build-infra/lib/tool-installer.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import { WIN32 } from '@socketsecurity/lib/constants/platform'
99
import { whichBinSync } from '@socketsecurity/lib/bin'
1010
import { spawn } from '@socketsecurity/lib/spawn'
1111

12-
import { execCapture } from './build-exec.mjs'
12+
import { WIN32 } from '@socketsecurity/lib/constants/platform'
13+
import { spawn } from '@socketsecurity/lib/spawn'
14+
// Removed execCapture from './build-exec.mjs'
1315
import { printError, printStep, printSubstep, printWarning } from './build-output.mjs'
1416

1517
/**

packages/cli/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@
7575
"wasm:download": "node scripts/wasm.mjs --download"
7676
},
7777
"devDependencies": {
78+
"@babel/generator": "^7.28.5",
79+
"@babel/parser": "7.28.4",
80+
"@babel/traverse": "7.28.4",
81+
"@babel/types": "^7.28.5",
7882
"@rollup/plugin-babel": "6.0.4",
7983
"@rollup/plugin-commonjs": "28.0.6",
8084
"@rollup/plugin-json": "6.1.0",

packages/cli/scripts/extract-yoga-wasm.mjs

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ const outputPath = path.join(rootPath, 'build/yoga-sync.mjs')
2424

2525
// Source files from custom yoga-layout package.
2626
const yogaPackageRoot = path.join(rootPath, '../yoga-layout')
27-
const yogaWasmFile = path.join(yogaPackageRoot, 'build/yoga.wasm')
28-
const yogaJsFile = path.join(yogaPackageRoot, 'build/yoga.js')
27+
const yogaWasmFile = path.join(yogaPackageRoot, 'build/wasm/yoga.wasm')
28+
const yogaJsFile = path.join(yogaPackageRoot, 'build/wasm/yoga.js')
2929

30-
// Check if extraction needed (hash ALL source files).
30+
// Check if extraction needed (hash both files).
3131
if (!await shouldExtract({
3232
sourcePaths: [yogaWasmFile, yogaJsFile],
3333
outputPath,
@@ -42,29 +42,51 @@ if (!await shouldExtract({
4242
const wasmBinary = readFileSync(yogaWasmFile)
4343
const base64Data = wasmBinary.toString('base64')
4444

45-
// Compute source hash for cache validation (hashes all source files).
46-
const sourceHashComment = await generateHashComment([
47-
yogaWasmFile,
48-
yogaJsFile,
49-
])
45+
// Read our custom Emscripten loader (generated by our build).
46+
const yogaJsContent = readFileSync(yogaJsFile, 'utf-8')
47+
48+
// Compute source hash for cache validation.
49+
const sourceHashComment = await generateHashComment([yogaWasmFile, yogaJsFile])
5050

5151
logger.log(
5252
`✓ Extracted ${wasmBinary.length} bytes of WASM data from custom yoga-layout`,
5353
)
5454

55-
// For now, just create a stub that will be replaced when yoga-layout is properly rebuilt with sync mode.
56-
// TODO: Once yoga-layout is rebuilt with WASM_ASYNC_COMPILATION=0, inline the synchronous loader.
55+
// Generate yoga-sync.mjs using OUR custom loader with OUR custom WASM.
5756
const yogaSyncContent = `/**
58-
* Synchronous yoga-layout stub.
57+
* Synchronous yoga-layout with embedded WASM binary.
5958
*
6059
* This file is AUTO-GENERATED by scripts/extract-yoga-wasm.mjs
6160
* DO NOT EDIT MANUALLY - changes will be overwritten on next build.
6261
*
62+
* Uses custom-built yoga-layout with Emscripten loader.
63+
* Built with WASM_ASYNC_COMPILATION=0 for synchronous instantiation.
64+
*
6365
* ${sourceHashComment}
6466
*/
6567
66-
// Stub - will be replaced with actual synchronous WASM wrapper once yoga-layout is rebuilt.
67-
export default {}
68+
// Inlined base64 WASM from custom yoga-layout (extracted at build time).
69+
const base64Wasm = '${base64Data}'
70+
71+
// Decode base64 to Uint8Array.
72+
const wasmBinary = Uint8Array.from(atob(base64Wasm), c => c.charCodeAt(0))
73+
74+
// Inlined Emscripten loader from custom yoga-layout build (no export statement).
75+
${yogaJsContent}
76+
77+
// Synchronously initialize yoga with embedded WASM.
78+
const yoga = Module({
79+
wasmBinary,
80+
instantiateWasm(imports, successCallback) {
81+
// Synchronously instantiate WASM module.
82+
const module = new WebAssembly.Module(wasmBinary)
83+
const instance = new WebAssembly.Instance(module, imports)
84+
successCallback(instance, module)
85+
return instance.exports
86+
}
87+
})
88+
89+
export default yoga
6890
`
6991

7092
ensureOutputDir(outputPath)

packages/yoga-layout/scripts/build.mjs

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -131,21 +131,21 @@ async function configure() {
131131
]
132132

133133
const linkerFlags = [
134-
'--closure 1', // Google Closure Compiler (aggressive minification).
134+
'--closure=1', // Google Closure Compiler (aggressive minification).
135135
'--gc-sections', // Garbage collect unused sections.
136136
'-flto=thin',
137137
'-Oz',
138-
'-s ALLOW_MEMORY_GROWTH=1', // Dynamic memory.
139-
'-s ASSERTIONS=0', // No runtime assertions (smaller, faster).
140-
'-s EXPORT_ES6=1', // ES6 module export.
141-
'-s FILESYSTEM=0', // No filesystem support (smaller).
142-
'-s INITIAL_MEMORY=64KB', // Minimal initial memory.
143-
'-s MALLOC=emmalloc', // Smaller allocator.
144-
'-s MODULARIZE=1', // Modular output.
145-
'-s NO_EXIT_RUNTIME=1', // Keep runtime alive (needed for WASM).
146-
'-s STACK_SIZE=16KB', // Small stack.
147-
'-s SUPPORT_LONGJMP=0', // No longjmp (smaller).
148-
'-s WASM_ASYNC_COMPILATION=0', // CRITICAL: Synchronous instantiation for bundling.
138+
'-sALLOW_MEMORY_GROWTH=1', // Dynamic memory.
139+
'-sASSERTIONS=0', // No runtime assertions (smaller, faster).
140+
'-sEXPORT_ES6=1', // ES6 module export.
141+
'-sFILESYSTEM=0', // No filesystem support (smaller).
142+
'-sINITIAL_MEMORY=64KB', // Minimal initial memory.
143+
'-sMALLOC=emmalloc', // Smaller allocator.
144+
'-sMODULARIZE=1', // Modular output.
145+
'-sNO_EXIT_RUNTIME=1', // Keep runtime alive (needed for WASM).
146+
'-sSTACK_SIZE=16KB', // Small stack.
147+
'-sSUPPORT_LONGJMP=0', // No longjmp (smaller).
148+
'-sWASM_ASYNC_COMPILATION=0', // CRITICAL: Synchronous instantiation for bundling.
149149
]
150150

151151
const cmakeArgs = [
@@ -210,20 +210,20 @@ async function build() {
210210
]
211211

212212
const linkerFlags = [
213-
'--closure 1',
213+
'--closure=1',
214214
'-Wl,--gc-sections',
215215
'-flto=thin',
216216
'-Oz',
217-
'-s ALLOW_MEMORY_GROWTH=1',
218-
'-s ASSERTIONS=0',
219-
'-s EXPORT_ES6=1',
220-
'-s FILESYSTEM=0',
221-
'-s INITIAL_MEMORY=64KB',
222-
'-s MALLOC=emmalloc',
223-
'-s MODULARIZE=1',
224-
'-s NO_EXIT_RUNTIME=1',
225-
'-s STACK_SIZE=16KB',
226-
'-s SUPPORT_LONGJMP=0',
217+
'-sALLOW_MEMORY_GROWTH=1',
218+
'-sASSERTIONS=0',
219+
'-sEXPORT_ES6=1',
220+
'-sFILESYSTEM=0',
221+
'-sINITIAL_MEMORY=64KB',
222+
'-sMALLOC=emmalloc',
223+
'-sMODULARIZE=1',
224+
'-sNO_EXIT_RUNTIME=1',
225+
'-sSTACK_SIZE=16KB',
226+
'-sSUPPORT_LONGJMP=0',
227227
'--bind',
228228
]
229229

@@ -369,9 +369,12 @@ async function exportWasm() {
369369
// Copy WASM file.
370370
await fs.copyFile(wasmFile, outputWasm)
371371

372-
// Copy JS glue code if exists.
372+
// Copy JS glue code and strip export statement.
373373
if (await fs.access(jsFile).then(() => true).catch(() => false)) {
374-
await fs.copyFile(jsFile, outputJs)
374+
const jsContent = await fs.readFile(jsFile, 'utf-8')
375+
// Strip the export statement at the end of the file.
376+
const withoutExport = jsContent.replace(/;?\s*export\s+default\s+\w+\s*;\s*$/, '')
377+
await fs.writeFile(outputJs, withoutExport, 'utf-8')
375378
printStep(`JS: ${outputJs}`)
376379
}
377380

0 commit comments

Comments
 (0)