From 1aa315cddf6e0f33377a9d7417d41616c9626d42 Mon Sep 17 00:00:00 2001 From: roberto Date: Tue, 3 Mar 2026 23:26:41 +0100 Subject: [PATCH] fix --- forge.config.ts | 58 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/forge.config.ts b/forge.config.ts index 76c2ae7..6491c9d 100644 --- a/forge.config.ts +++ b/forge.config.ts @@ -79,27 +79,57 @@ const config: ForgeConfig = { fs.readFileSync(path.resolve(__dirname, 'node_modules', 'electron', 'package.json'), 'utf-8'), ).version; - // Clean stale build artifacts before rebuilding — a leftover - // build/Release/*.node for the host platform must not survive. + // Rebuild native modules for target platform using prebuild-install. + // prebuild-install supports cross-platform via --platform/--arch, + // unlike @electron/rebuild which only supports --arch. + // This is FATAL — a Linux .node in a Windows package is always broken. const nativeModules = ['better-sqlite3']; for (const mod of nativeModules) { - const buildRelease = path.join(buildPath, 'node_modules', mod, 'build', 'Release'); + const modDir = path.join(buildPath, 'node_modules', mod); + if (!fs.existsSync(modDir)) continue; + + // Clean stale build artifacts — a leftover build/Release/*.node + // for the host platform must not survive. + const buildRelease = path.join(modDir, 'build', 'Release'); if (fs.existsSync(buildRelease)) { fs.rmSync(buildRelease, { recursive: true, force: true }); console.log(`[forge] Cleaned stale build/Release for ${mod}`); } - } - // Rebuild native modules for target platform using @electron/rebuild. - // This is fatal — a Linux .node in a Windows package is always broken. - console.log(`[forge] Rebuilding native modules for ${targetKey} (Electron ${electronVersion})...`); - execSync( - `npx --yes @electron/rebuild --platform ${platform} --arch ${arch} ` + - `--module-dir "${path.join(buildPath, 'node_modules')}" ` + - `--electron-version ${electronVersion} ` + - `--only better-sqlite3`, - { cwd: buildPath, stdio: 'inherit' }, - ); + console.log(`[forge] Downloading ${mod} prebuilt for ${targetKey} (Electron ${electronVersion})...`); + execSync( + `npx --yes prebuild-install -r electron -t ${electronVersion} ` + + `--platform ${platform} --arch ${arch} --tag-prefix v --verbose`, + { cwd: modDir, stdio: 'inherit' }, + ); + + // Verify the downloaded binary is NOT an ELF (Linux) file. + // node-gyp-build loads from prebuilds/ first, then build/Release/. + const prebuildsTarget = path.join(modDir, 'prebuilds', targetKey); + if (fs.existsSync(prebuildsTarget)) { + for (const f of fs.readdirSync(prebuildsTarget)) { + if (f.endsWith('.node')) { + const buf = Buffer.alloc(4); + const fd = fs.openSync(path.join(prebuildsTarget, f), 'r'); + fs.readSync(fd, buf, 0, 4, 0); + fs.closeSync(fd); + // ELF magic: 0x7f 'E' 'L' 'F' + if (buf[0] === 0x7f && buf[1] === 0x45 && buf[2] === 0x4c && buf[3] === 0x46) { + throw new Error( + `[forge] FATAL: ${mod} prebuilt for ${targetKey} is an ELF binary! ` + + `Cross-compilation failed — refusing to package a Linux .node for Windows.`, + ); + } + console.log(`[forge] Verified ${f} is not ELF ✓`); + } + } + } else { + throw new Error( + `[forge] FATAL: No prebuilds/${targetKey}/ directory found for ${mod} after prebuild-install. ` + + `The native module would fall back to a Linux binary at runtime.`, + ); + } + } } // vectordb uses platform-specific optional deps (@lancedb/vectordb---*).