Skip to content

fix: fall back to musl binary when gnu prebuild fails to load #18

fix: fall back to musl binary when gnu prebuild fails to load

fix: fall back to musl binary when gnu prebuild fails to load #18

Workflow file for this run

name: CI
on:
pull_request:
workflow_call:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
test:
name: ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
cache: yarn
# Rust (stable + clippy) is preinstalled on the hosted runner images.
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- run: yarn install --immutable
- run: yarn build
- run: yarn test
- run: cargo test --release
- run: cargo clippy --release -- -D warnings
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: rustsec/audit-check@69366f33c96575abad1ee0dba8212993eecbe998 # v2.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
# Build every prebuild target the released package ships. Running this on
# PRs (not just on main) means a broken target is caught before merge; the
# Release workflow reuses these same jobs (via workflow_call) and publishes
# the artifacts they upload.
build:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
# ── macOS: build both arches, lipo to universal ───────────────────
- name: darwin-universal
os: macos-latest
build: |
rustup target add x86_64-apple-darwin
yarn napi build --platform --release --esm --output-dir . --target aarch64-apple-darwin --js binding.js --dts binding.d.ts
yarn napi build --platform --release --esm --output-dir . --target x86_64-apple-darwin --js binding.js --dts binding.d.ts
yarn napi universalize --output-dir .
artifact: index.darwin-universal.node
# ── Windows ───────────────────────────────────────────────────────
- name: win32-x64
os: windows-latest
build: yarn napi build --platform --release --esm --output-dir . --target x86_64-pc-windows-msvc --js binding.js --dts binding.d.ts
artifact: index.win32-x64-msvc.node
- name: win32-arm64
os: windows-latest
build: |
rustup target add aarch64-pc-windows-msvc
yarn napi build --platform --release --esm --output-dir . --target aarch64-pc-windows-msvc --js binding.js --dts binding.d.ts
artifact: index.win32-arm64-msvc.node
# ── Linux glibc (native runners for each arch) ────────────────────
- name: linux-x64-gnu
os: ubuntu-latest
build: yarn napi build --platform --release --esm --output-dir . --target x86_64-unknown-linux-gnu --js binding.js --dts binding.d.ts
artifact: index.linux-x64-gnu.node
- name: linux-arm64-gnu
os: ubuntu-24.04-arm
build: yarn napi build --platform --release --esm --output-dir . --target aarch64-unknown-linux-gnu --js binding.js --dts binding.d.ts
artifact: index.linux-arm64-gnu.node
# ── Linux musl (Alpine via docker run on native-arch runners) ─────
# Job containers can't be used here: the runner refuses to exec JS
# actions (checkout, upload-artifact, ...) inside Alpine containers
# on arm64 hosts (actions/runner#801), so the "Build (docker)" step
# runs the whole alpine build via `docker run` instead. Rust comes
# from a version-pinned, checksum-verified rustup-init.
- name: linux-x64-musl
os: ubuntu-latest
docker: node:22-alpine@sha256:968df39aedcea65eeb078fb336ed7191baf48f972b4479711397108be0966920
rustup_url: https://static.rust-lang.org/rustup/archive/1.29.0/x86_64-unknown-linux-musl/rustup-init
rustup_sha256: 9cd3fda5fd293890e36ab271af6a786ee22084b5f6c2b83fd8323cec6f0992c1
build: |
rustup target add x86_64-unknown-linux-musl
yarn napi build --platform --release --esm --output-dir . --target x86_64-unknown-linux-musl --js binding.js --dts binding.d.ts
artifact: index.linux-x64-musl.node
- name: linux-arm64-musl
os: ubuntu-24.04-arm
docker: node:22-alpine@sha256:968df39aedcea65eeb078fb336ed7191baf48f972b4479711397108be0966920
rustup_url: https://static.rust-lang.org/rustup/archive/1.29.0/aarch64-unknown-linux-musl/rustup-init
rustup_sha256: 88761caacddb92cd79b0b1f939f3990ba1997d701a38b3e8dd6746a562f2a759
build: |
# napi assumes aarch64-musl is cross-compiled and would default the
# linker to aarch64-linux-musl-gcc; here gcc IS the native musl gcc.
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=gcc
rustup target add aarch64-unknown-linux-musl
yarn napi build --platform --release --esm --output-dir . --target aarch64-unknown-linux-musl --js binding.js --dts binding.d.ts
artifact: index.linux-arm64-musl.node
# ── Linux 32-bit (cross-compiled) ─────────────────────────────────
# Old release lines (e.g. Electron's armv7l / linux-ia32 builds) still
# install this package, so keep shipping 32-bit prebuilds. There are no
# native 32-bit runners, so these are cross-compiled and flagged
# `cross: true` to skip the smoke test below (the host's 64-bit node
# can't load a 32-bit .node).
- name: linux-ia32-gnu
os: ubuntu-latest
cross: true
# i686 isn't in @napi-rs/cross-toolchain, but an x86_64 host can target
# it directly with gcc-multilib (gcc -m32), which also builds zlib-ng.
build: |
sudo apt-get update
sudo apt-get install -y gcc-multilib g++-multilib
rustup target add i686-unknown-linux-gnu
yarn napi build --platform --release --esm --output-dir . --target i686-unknown-linux-gnu --js binding.js --dts binding.d.ts
artifact: index.linux-ia32-gnu.node
- name: linux-arm-gnueabihf
os: ubuntu-latest
cross: true
# --use-napi-cross pulls @napi-rs/cross-toolchain and wires up the
# armv7 linker / CC / sysroot (used to cross-compile zlib-ng too).
build: |
rustup target add armv7-unknown-linux-gnueabihf
yarn napi build --platform --release --esm --output-dir . --target armv7-unknown-linux-gnueabihf --use-napi-cross --js binding.js --dts binding.d.ts
artifact: index.linux-arm-gnueabihf.node
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
cache: yarn
package-manager-cache: ${{ github.ref != 'refs/heads/main' }}
# Rust (stable) is preinstalled on the hosted runner images; the alpine
# docker builds install their own pinned rustup in "Build (docker)".
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
key: ${{ matrix.name }}
- run: yarn install --immutable
- name: Build
if: ${{ !matrix.docker }}
shell: bash
run: ${{ matrix.build }}
# Everything that the other entries do across separate steps — alpine
# deps, Rust, yarn install, build, strip, smoke test — has to happen
# inside the container here, since the host can't run musl binaries.
- name: Build (docker)
if: matrix.docker
run: |
docker run --rm -v "$PWD:/build" -w /build "${{ matrix.docker }}" sh -ec '
apk add --no-cache bash curl build-base cmake python3 git
curl --proto "=https" --tlsv1.2 -fsSL -o /tmp/rustup-init "${{ matrix.rustup_url }}"
echo "${{ matrix.rustup_sha256 }} /tmp/rustup-init" | sha256sum -c -
chmod +x /tmp/rustup-init
/tmp/rustup-init -y --profile minimal --default-toolchain stable
export PATH="$HOME/.cargo/bin:$PATH"
yarn install --immutable
${{ matrix.build }}
node scripts/strip-binding-fallbacks.js
yarn test
'
sudo chown -R "$(id -u):$(id -g)" .
- name: Strip binding.js package fallbacks
run: node scripts/strip-binding-fallbacks.js
- name: Smoke test (native targets only)
if: ${{ !matrix.docker && !matrix.cross && (!contains(matrix.name, 'arm64') || contains(matrix.os, 'arm') || matrix.os == 'macos-latest') }}
run: yarn test
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.name }}
path: ${{ matrix.artifact }}
if-no-files-found: error
# binding.js / binding.d.ts are gitignored; ship one canonical copy from
# this job for the release step to pick up.
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: matrix.name == 'linux-x64-gnu'
with:
name: binding
path: |
binding.js
binding.d.ts
if-no-files-found: error