diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f32ddfe..c6a394e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -192,6 +192,8 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] node: [20, 22, 24] include: + - os: ubuntu-24.04-arm + node: 24 - os: windows-11-arm node: 24 diff --git a/.github/workflows/published-install.yml b/.github/workflows/published-install.yml index 34045aa..adf8011 100644 --- a/.github/workflows/published-install.yml +++ b/.github/workflows/published-install.yml @@ -62,16 +62,21 @@ jobs: linux: name: ${{ matrix.target }} needs: package - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} timeout-minutes: 15 strategy: fail-fast: false matrix: include: - target: linux-x64-glibc + os: ubuntu-latest image: node:24-bookworm - target: linux-x64-musl + os: ubuntu-latest image: node:24-alpine + - target: linux-arm64-glibc + os: ubuntu-24.04-arm + image: node:24-bookworm steps: - name: Install published package diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 05edb7b..093793b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,22 +21,33 @@ permissions: jobs: prebuild-linux: name: Prebuild ${{ matrix.target }} - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} timeout-minutes: 45 strategy: fail-fast: false matrix: include: - target: linux-x64-glibc + os: ubuntu-latest + arch: x64 dockerfile: build-containers/Dockerfile.debian image: webrtc-node-prebuild-debian build_args: --build-arg NODE_VERSION=20 --build-arg DEBIAN_VERSION=bullseye libc: glibc - target: linux-x64-musl + os: ubuntu-latest + arch: x64 dockerfile: build-containers/Dockerfile.alpine image: webrtc-node-prebuild-alpine build_args: --build-arg NODE_VERSION=20 --build-arg ALPINE_VERSION=3.20 libc: musl + - target: linux-arm64-glibc + os: ubuntu-24.04-arm + arch: arm64 + dockerfile: build-containers/Dockerfile.debian + image: webrtc-node-prebuild-debian-arm64 + build_args: --build-arg NODE_VERSION=20 --build-arg DEBIAN_VERSION=bullseye + libc: glibc steps: - uses: actions/checkout@v7 @@ -53,7 +64,7 @@ jobs: -v "$PWD:/usr/app" \ -w /usr/app \ "${{ matrix.image }}" \ - sh -lc "npm ci --ignore-scripts && npm run build -- --CDWEBRTC_NODE_STATIC_OPENSSL=ON && npm run prebuild:package -- --platform=linux --arch=x64 --libc=${{ matrix.libc }} && node -e \"const { RTCPeerConnection } = require('./'); const pc = new RTCPeerConnection(); pc.close();\"" + sh -lc "npm ci --ignore-scripts && npm run build -- --CDWEBRTC_NODE_STATIC_OPENSSL=ON && npm run prebuild:package -- --platform=linux --arch=${{ matrix.arch }} --libc=${{ matrix.libc }} && node -e \"const { RTCPeerConnection } = require('./'); const pc = new RTCPeerConnection(); pc.close();\"" - uses: actions/upload-artifact@v7 with: diff --git a/README.md b/README.md index 74868ea..fd459a6 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ to a `cmake-js` source build. | OS | Prebuild targets | Node 20 | Node 22 | Node 24 | | --- | --- | --- | --- | --- | -| Linux | x64 glibc, x64 musl | ✅ | ✅ | ✅ | +| Linux | x64 glibc, x64 musl, arm64 glibc | ✅ | ✅ | ✅ | | macOS | x64, arm64 | ✅ | ✅ | ✅ | | Windows | x64, arm64 | ✅ | ✅ | ✅ | diff --git a/scripts/check-prebuilds.js b/scripts/check-prebuilds.js index 34af0a6..8017c7b 100644 --- a/scripts/check-prebuilds.js +++ b/scripts/check-prebuilds.js @@ -10,6 +10,7 @@ const prebuildsDir = path.join(root, "prebuild-artifacts"); const requiredTargets = [ "linux-x64-glibc", "linux-x64-musl", + "linux-arm64-glibc", "darwin-x64", "darwin-arm64", "win32-x64", diff --git a/scripts/prebuild-integrity.js b/scripts/prebuild-integrity.js index 6e9a0e6..b0425f4 100644 --- a/scripts/prebuild-integrity.js +++ b/scripts/prebuild-integrity.js @@ -47,6 +47,12 @@ function expectedBinary(platform, arch, libcTag) { } return { format: "ELF", machine: 62, libcTag }; } + if (platform === "linux" && arch === "arm64") { + if (libcTag !== "glibc") { + throw new Error(`unsupported Linux libc target ${libcTag || "unknown"} for arm64`); + } + return { format: "ELF", machine: 183, libcTag }; + } if (platform === "win32" && arch === "x64") { return { format: "PE", machine: 0x8664 }; } diff --git a/test/prebuild-integrity.test.js b/test/prebuild-integrity.test.js index a510b23..2eb3681 100644 --- a/test/prebuild-integrity.test.js +++ b/test/prebuild-integrity.test.js @@ -24,10 +24,10 @@ function peBinary(machine) { return buffer; } -function elfBinary(libcName) { +function elfBinary(libcName, machine = 62) { const buffer = Buffer.alloc(256); Buffer.from([0x7f, 0x45, 0x4c, 0x46, 2, 1]).copy(buffer); - buffer.writeUInt16LE(62, 18); + buffer.writeUInt16LE(machine, 18); buffer.write(libcName, 64, "ascii"); return buffer; } @@ -153,6 +153,29 @@ test("prebuild validator distinguishes glibc and musl binaries", async (t) => { ); }); +test("prebuild validator accepts Linux arm64 glibc and rejects mismatches", async (t) => { + const arm64 = await archiveFixture(t, elfBinary("libc.so.6", 183)); + const addonPath = await validateArchiveFile({ + ...arm64, + platform: "linux", + arch: "arm64", + libcTag: "glibc", + }); + fs.rmSync(path.dirname(addonPath), { recursive: true, force: true }); + + const x64Binary = await archiveFixture(t, elfBinary("libc.so.6", 62)); + await assert.rejects( + validateArchiveFile({ ...x64Binary, platform: "linux", arch: "arm64", libcTag: "glibc" }), + /target mismatch/, + ); + + const musl = await archiveFixture(t, elfBinary("libc.musl-aarch64.so.1", 183)); + await assert.rejects( + validateArchiveFile({ ...musl, platform: "linux", arch: "arm64", libcTag: "musl" }), + /unsupported Linux libc target musl for arm64/, + ); +}); + test("prebuild validator accepts supported macOS architectures", async (t) => { const x64 = await archiveFixture(t, machOBinary(0x01000007)); const x64Addon = await validateArchiveFile({