Skip to content

Commit f4a8781

Browse files
fix: add 32-bit Linux (ia32 + armv7l) prebuilds (#7)
* ci: add 32-bit Linux (ia32 + armv7l) prebuilds Old release lines (notably Electron's armv7l builds) still install @electron-internal/extract-zip, but no 32-bit prebuild was being shipped, so it failed to load on 32-bit Linux. Add cross-compiled prebuilds for both 32-bit Linux targets: - i686-unknown-linux-gnu (linux/ia32) via gcc-multilib - armv7-unknown-linux-gnueabihf (linux/arm) via napi's --use-napi-cross Both run in the shared CI build matrix (reused by the Release workflow via workflow_call) and are flagged `cross: true` so the smoke-test step is skipped — there are no native 32-bit runners and the host's 64-bit node can't load a 32-bit .node. napi's generated loader has no `process.arch === 'ia32'` branch under Linux, so strip-binding-fallbacks.js now also splices that branch in; otherwise the ia32 prebuild would be unreachable. package.json targets and the check-prebuilds publish gate are updated to match. * ci: generate linux/ia32 loader branch via @napi-rs/cli patch Address review feedback: instead of splicing the missing 32-bit x86 Linux branch into the generated binding.js from strip-binding-fallbacks.js, patch @napi-rs/cli's loader template directly (via Yarn's patch protocol) so napi emits the `process.arch === 'ia32'` branch natively, consistent with every other arch (including its @electron-internal fallback, which the existing strip step then removes). strip-binding-fallbacks.js is reverted to its original single responsibility. --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent d3f1eaf commit f4a8781

5 files changed

Lines changed: 104 additions & 5 deletions

File tree

.github/workflows/ci.yml

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,34 @@ jobs:
122122
yarn napi build --platform --release --esm --output-dir . --target aarch64-unknown-linux-musl --js binding.js --dts binding.d.ts
123123
artifact: index.linux-arm64-musl.node
124124

125+
# ── Linux 32-bit (cross-compiled) ─────────────────────────────────
126+
# Old release lines (e.g. Electron's armv7l / linux-ia32 builds) still
127+
# install this package, so keep shipping 32-bit prebuilds. There are no
128+
# native 32-bit runners, so these are cross-compiled and flagged
129+
# `cross: true` to skip the smoke test below (the host's 64-bit node
130+
# can't load a 32-bit .node).
131+
- name: linux-ia32-gnu
132+
os: ubuntu-latest
133+
cross: true
134+
# i686 isn't in @napi-rs/cross-toolchain, but an x86_64 host can target
135+
# it directly with gcc-multilib (gcc -m32), which also builds zlib-ng.
136+
build: |
137+
sudo apt-get update
138+
sudo apt-get install -y gcc-multilib g++-multilib
139+
rustup target add i686-unknown-linux-gnu
140+
yarn napi build --platform --release --esm --output-dir . --target i686-unknown-linux-gnu --js binding.js --dts binding.d.ts
141+
artifact: index.linux-ia32-gnu.node
142+
143+
- name: linux-arm-gnueabihf
144+
os: ubuntu-latest
145+
cross: true
146+
# --use-napi-cross pulls @napi-rs/cross-toolchain and wires up the
147+
# armv7 linker / CC / sysroot (used to cross-compile zlib-ng too).
148+
build: |
149+
rustup target add armv7-unknown-linux-gnueabihf
150+
yarn napi build --platform --release --esm --output-dir . --target armv7-unknown-linux-gnueabihf --use-napi-cross --js binding.js --dts binding.d.ts
151+
artifact: index.linux-arm-gnueabihf.node
152+
125153
steps:
126154
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
127155
with:
@@ -170,7 +198,7 @@ jobs:
170198
run: node scripts/strip-binding-fallbacks.js
171199

172200
- name: Smoke test (native targets only)
173-
if: ${{ !matrix.docker && (!contains(matrix.name, 'arm64') || contains(matrix.os, 'arm') || matrix.os == 'macos-latest') }}
201+
if: ${{ !matrix.docker && !matrix.cross && (!contains(matrix.name, 'arm64') || contains(matrix.os, 'arm') || matrix.os == 'macos-latest') }}
174202
run: yarn test
175203

176204
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
diff --git a/dist/cli.js b/dist/cli.js
2+
index 5787d8d0398b48987f9e59a628770259cf9c830c..260f2a7f742c3a14fbabb7b67c6121311a99a703 100755
3+
--- a/dist/cli.js
4+
+++ b/dist/cli.js
5+
@@ -802,6 +802,8 @@ function requireNative() {
6+
${requireTuple("linux-ppc64-gnu")}
7+
} else if (process.arch === 's390x') {
8+
${requireTuple("linux-s390x-gnu")}
9+
+ } else if (process.arch === 'ia32') {
10+
+ ${requireTuple("linux-ia32-gnu")}
11+
} else {
12+
loadErrors.push(new Error(\`Unsupported architecture on Linux: \${process.arch}\`))
13+
}
14+
diff --git a/dist/index.cjs b/dist/index.cjs
15+
index 8f467564ab9b95d009c562cb9a78aa513b6d2bb2..291d75aca1095ce67e80ced2de16b5cd59c161c0 100644
16+
--- a/dist/index.cjs
17+
+++ b/dist/index.cjs
18+
@@ -827,6 +827,8 @@ function requireNative() {
19+
${requireTuple("linux-ppc64-gnu")}
20+
} else if (process.arch === 's390x') {
21+
${requireTuple("linux-s390x-gnu")}
22+
+ } else if (process.arch === 'ia32') {
23+
+ ${requireTuple("linux-ia32-gnu")}
24+
} else {
25+
loadErrors.push(new Error(\`Unsupported architecture on Linux: \${process.arch}\`))
26+
}
27+
diff --git a/dist/index.js b/dist/index.js
28+
index e2bfc6368247a58ea3a712bb156e15b440bf139a..f74f13e7189be927cedbd4fd5ba9dd4ca335e6f9 100644
29+
--- a/dist/index.js
30+
+++ b/dist/index.js
31+
@@ -801,6 +801,8 @@ function requireNative() {
32+
${requireTuple("linux-ppc64-gnu")}
33+
} else if (process.arch === 's390x') {
34+
${requireTuple("linux-s390x-gnu")}
35+
+ } else if (process.arch === 'ia32') {
36+
+ ${requireTuple("linux-ia32-gnu")}
37+
} else {
38+
loadErrors.push(new Error(\`Unsupported architecture on Linux: \${process.arch}\`))
39+
}

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
"x86_64-unknown-linux-gnu",
2929
"aarch64-unknown-linux-gnu",
3030
"x86_64-unknown-linux-musl",
31-
"aarch64-unknown-linux-musl"
31+
"aarch64-unknown-linux-musl",
32+
"i686-unknown-linux-gnu",
33+
"armv7-unknown-linux-gnueabihf"
3234
]
3335
},
3436
"scripts": {
@@ -60,7 +62,7 @@
6062
"url": "https://github.com/electron/extract-zip"
6163
},
6264
"devDependencies": {
63-
"@napi-rs/cli": "^3.6.2",
65+
"@napi-rs/cli": "patch:@napi-rs/cli@npm%3A3.6.2#~/.yarn/patches/@napi-rs-cli-npm-3.6.2-b710c59d43.patch",
6466
"extract-zip": "2.0.1",
6567
"yazl": "3.3.1"
6668
}

scripts/check-prebuilds.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ const EXPECTED = {
1515
'aarch64-unknown-linux-gnu': 'index.linux-arm64-gnu.node',
1616
'x86_64-unknown-linux-musl': 'index.linux-x64-musl.node',
1717
'aarch64-unknown-linux-musl': 'index.linux-arm64-musl.node',
18+
'i686-unknown-linux-gnu': 'index.linux-ia32-gnu.node',
19+
'armv7-unknown-linux-gnueabihf': 'index.linux-arm-gnueabihf.node',
1820
};
1921

2022
const dir = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');

yarn.lock

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ __metadata:
99
version: 0.0.0-use.local
1010
resolution: "@electron-internal/extract-zip@workspace:."
1111
dependencies:
12-
"@napi-rs/cli": "npm:^3.6.2"
12+
"@napi-rs/cli": "patch:@napi-rs/cli@npm%3A3.6.2#~/.yarn/patches/@napi-rs-cli-npm-3.6.2-b710c59d43.patch"
1313
extract-zip: "npm:2.0.1"
1414
yazl: "npm:3.3.1"
1515
languageName: unknown
@@ -256,7 +256,7 @@ __metadata:
256256
languageName: node
257257
linkType: hard
258258

259-
"@napi-rs/cli@npm:^3.6.2":
259+
"@napi-rs/cli@npm:3.6.2":
260260
version: 3.6.2
261261
resolution: "@napi-rs/cli@npm:3.6.2"
262262
dependencies:
@@ -284,6 +284,34 @@ __metadata:
284284
languageName: node
285285
linkType: hard
286286

287+
"@napi-rs/cli@patch:@napi-rs/cli@npm%3A3.6.2#~/.yarn/patches/@napi-rs-cli-npm-3.6.2-b710c59d43.patch":
288+
version: 3.6.2
289+
resolution: "@napi-rs/cli@patch:@napi-rs/cli@npm%3A3.6.2#~/.yarn/patches/@napi-rs-cli-npm-3.6.2-b710c59d43.patch::version=3.6.2&hash=058488"
290+
dependencies:
291+
"@inquirer/prompts": "npm:^8.0.0"
292+
"@napi-rs/cross-toolchain": "npm:^1.0.3"
293+
"@napi-rs/wasm-tools": "npm:^1.0.1"
294+
"@octokit/rest": "npm:^22.0.1"
295+
clipanion: "npm:^4.0.0-rc.4"
296+
colorette: "npm:^2.0.20"
297+
emnapi: "npm:^1.9.1"
298+
es-toolkit: "npm:^1.41.0"
299+
js-yaml: "npm:^4.1.0"
300+
obug: "npm:^2.0.0"
301+
semver: "npm:^7.7.3"
302+
typanion: "npm:^3.14.0"
303+
peerDependencies:
304+
"@emnapi/runtime": ^1.7.1
305+
peerDependenciesMeta:
306+
"@emnapi/runtime":
307+
optional: true
308+
bin:
309+
napi: dist/cli.js
310+
napi-raw: cli.mjs
311+
checksum: 10c0/73681d26ce5100769c231f12494ef4af673455e073b72507d0404a8e927342dcfd49df8e612dc517e263add37acab4832203fd6965825e7e871ea93796f9e003
312+
languageName: node
313+
linkType: hard
314+
287315
"@napi-rs/cross-toolchain@npm:^1.0.3":
288316
version: 1.0.3
289317
resolution: "@napi-rs/cross-toolchain@npm:1.0.3"

0 commit comments

Comments
 (0)