Skip to content

Commit

Permalink
Fix linux arm musl build (#5176)
Browse files Browse the repository at this point in the history
* Replace native loader with hand-crafted code

* Add back Linux arm64 for debugging

* Take some inspiration from SWC

* more tests

* more tests

* more tests

* more tests

* more tests

* more tests

* more tests

* more tests

* more tests

* more tests

* more tests

* more tests

* more tests

* more tests
  • Loading branch information
lukastaegert committed Oct 6, 2023
1 parent 4611d81 commit 10eb5e8
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 267 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ module.exports = {
'coverage',
'_tmp',
'cache',
'native*.*',
'native.d.ts',
'/test/*/samples/**/*.*',
'!/test/*/samples/**/_config.js',
'!/test/*/samples/**/rollup.config.js',
Expand Down
21 changes: 11 additions & 10 deletions .github/workflows/build-and-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ jobs:
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64
build: |-
set -e &&
export JEMALLOC_SYS_WITH_LG_PAGE=16 &&
rustup default nightly &&
rustup target add aarch64-unknown-linux-gnu &&
npm run build:napi -- --release --target aarch64-unknown-linux-gnu &&
Expand All @@ -131,16 +132,16 @@ jobs:
build: |
npm run build:napi -- --release --target armv7-linux-androideabi
${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip *.node
# TODO SWC this does not work yet, also add back in package.json
# - host: ubuntu-latest
# target: aarch64-unknown-linux-musl
# docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
# build: |-
# set -e &&
# rustup default nightly &&
# rustup target add aarch64-unknown-linux-musl &&
# npm run build:napi -- --release --target aarch64-unknown-linux-musl &&
# /aarch64-linux-musl-cross/bin/aarch64-linux-musl-strip *.node
- host: ubuntu-latest
target: aarch64-unknown-linux-musl
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
build: >-
set -e &&
export JEMALLOC_SYS_WITH_LG_PAGE=16 &&
rustup default nightly &&
rustup target add aarch64-unknown-linux-musl &&
RUSTFLAGS='-C target-feature=-crt-static -C linker=aarch64-linux-musl-gcc' npm run build:napi -- --release --target aarch64-unknown-linux-musl &&
/aarch64-linux-musl-cross/bin/aarch64-linux-musl-strip *.node
- host: windows-latest
target: aarch64-pc-windows-msvc
build: npm run build:napi -- --release --target aarch64-pc-windows-msvc
Expand Down
306 changes: 51 additions & 255 deletions native.js
Original file line number Diff line number Diff line change
@@ -1,258 +1,54 @@
/* tslint:disable */
/* eslint-disable */
/* prettier-ignore */

/* auto-generated by NAPI-RS */

const { existsSync, readFileSync } = require('fs')
const { join } = require('path')

const { platform, arch } = process

let nativeBinding = null
let localFileExisted = false
let loadError = null

function isMusl() {
// For Node 10
if (!process.report || typeof process.report.getReport !== 'function') {
try {
const lddPath = require('child_process').execSync('which ldd').toString().trim()
return readFileSync(lddPath, 'utf8').includes('musl')
} catch (e) {
return true
}
} else {
const { glibcVersionRuntime } = process.report.getReport().header
return !glibcVersionRuntime
}
}

switch (platform) {
case 'android':
switch (arch) {
case 'arm64':
localFileExisted = existsSync(join(__dirname, 'rollup.android-arm64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./rollup.android-arm64.node')
} else {
nativeBinding = require('@rollup/rollup-android-arm64')
}
} catch (e) {
loadError = e
}
break
case 'arm':
localFileExisted = existsSync(join(__dirname, 'rollup.android-arm-eabi.node'))
try {
if (localFileExisted) {
nativeBinding = require('./rollup.android-arm-eabi.node')
} else {
nativeBinding = require('@rollup/rollup-android-arm-eabi')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Android ${arch}`)
}
break
case 'win32':
switch (arch) {
case 'x64':
localFileExisted = existsSync(
join(__dirname, 'rollup.win32-x64-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./rollup.win32-x64-msvc.node')
} else {
nativeBinding = require('@rollup/rollup-win32-x64-msvc')
}
} catch (e) {
loadError = e
}
break
case 'ia32':
localFileExisted = existsSync(
join(__dirname, 'rollup.win32-ia32-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./rollup.win32-ia32-msvc.node')
} else {
nativeBinding = require('@rollup/rollup-win32-ia32-msvc')
}
} catch (e) {
loadError = e
}
break
case 'arm64':
localFileExisted = existsSync(
join(__dirname, 'rollup.win32-arm64-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./rollup.win32-arm64-msvc.node')
} else {
nativeBinding = require('@rollup/rollup-win32-arm64-msvc')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Windows: ${arch}`)
}
break
case 'darwin':
localFileExisted = existsSync(join(__dirname, 'rollup.darwin-universal.node'))
try {
if (localFileExisted) {
nativeBinding = require('./rollup.darwin-universal.node')
} else {
nativeBinding = require('@rollup/rollup-darwin-universal')
}
break
} catch {}
switch (arch) {
case 'x64':
localFileExisted = existsSync(join(__dirname, 'rollup.darwin-x64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./rollup.darwin-x64.node')
} else {
nativeBinding = require('@rollup/rollup-darwin-x64')
}
} catch (e) {
loadError = e
}
break
case 'arm64':
localFileExisted = existsSync(
join(__dirname, 'rollup.darwin-arm64.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./rollup.darwin-arm64.node')
} else {
nativeBinding = require('@rollup/rollup-darwin-arm64')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on macOS: ${arch}`)
}
break
case 'freebsd':
if (arch !== 'x64') {
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
}
localFileExisted = existsSync(join(__dirname, 'rollup.freebsd-x64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./rollup.freebsd-x64.node')
} else {
nativeBinding = require('@rollup/rollup-freebsd-x64')
}
} catch (e) {
loadError = e
}
break
case 'linux':
switch (arch) {
case 'x64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'rollup.linux-x64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./rollup.linux-x64-musl.node')
} else {
nativeBinding = require('@rollup/rollup-linux-x64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'rollup.linux-x64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./rollup.linux-x64-gnu.node')
} else {
nativeBinding = require('@rollup/rollup-linux-x64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 'arm64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'rollup.linux-arm64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./rollup.linux-arm64-musl.node')
} else {
nativeBinding = require('@rollup/rollup-linux-arm64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'rollup.linux-arm64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./rollup.linux-arm64-gnu.node')
} else {
nativeBinding = require('@rollup/rollup-linux-arm64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 'arm':
localFileExisted = existsSync(
join(__dirname, 'rollup.linux-arm-gnueabihf.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./rollup.linux-arm-gnueabihf.node')
} else {
nativeBinding = require('@rollup/rollup-linux-arm-gnueabihf')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Linux: ${arch}`)
}
break
default:
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
}

if (!nativeBinding) {
if (loadError) {
throw loadError
}
throw new Error(`Failed to load native binding`)
const { existsSync } = require('node:fs');
const { join } = require('node:path');
const { platform, arch, report } = require('node:process');

const isMusl = () => !report.getReport().header.glibcVersionRuntime;

const bindingsByPlatformAndArch = {
android: {
arm: { base: 'android-arm-eabi' },
arm64: { base: 'android-arm64' }
},
darwin: {
arm64: { base: 'darwin-arm64' },
x64: { base: 'darwin-x64' }
},
linux: {
arm: { base: 'linux-arm-gnueabihf' },
arm64: { base: 'linux-arm64-gnu', musl: 'linux-arm64-musl' },
x64: { base: 'linux-x64-gnu', musl: 'linux-x64-musl' }
},
win32: {
arm64: { base: 'win32-arm64-msvc' },
ia32: { base: 'win32-ia32-msvc' },
x64: { base: 'win32-x64-msvc' }
}
};

const imported = bindingsByPlatformAndArch[platform]?.[arch];
if (!imported) {
throw new Error(
`Your current platform "${platform}" and architecture "${arch}" combination is not yet supported by the native Rollup build. Please use the WASM build "@rollup/wasm-node" instead.
The following platform-architecture combinations are supported:
${Object.entries(bindingsByPlatformAndArch)
.flatMap(([platformName, architectures]) =>
Object.entries(architectures).flatMap(([architectureName, { musl }]) => {
const name = `${platformName}-${architectureName}`;
return musl ? [name, `${name} (musl)`] : [name];
})
)
.join('\n')}
If this is important to you, please consider supporting Rollup to make a native build for your platform and architecture available.`
);
}

const { parse, xxhashBase64Url } = nativeBinding
const packageBase = imported.musl && isMusl() ? imported.musl : imported.base;
const localName = `./rollup.${packageBase}.node`;
const { parse, xxhashBase64Url } = require(
existsSync(join(__dirname, localName)) ? localName : `@rollup/rollup-${packageBase}`
);

module.exports.parse = parse
module.exports.xxhashBase64Url = xxhashBase64Url
module.exports.parse = parse;
module.exports.xxhashBase64Url = xxhashBase64Url;
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"aarch64-linux-android",
"aarch64-pc-windows-msvc",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl",
"armv7-linux-androideabi",
"armv7-unknown-linux-gnueabihf",
"i686-pc-windows-msvc",
Expand All @@ -33,7 +34,7 @@
"scripts": {
"build": "npm run build:wasm && concurrently -c green,blue \"npm run build:napi -- --release\" \"npm:build:js\" && npm run build:copy-native",
"build:quick": "concurrently -c green,blue 'npm:build:napi' 'npm:build:cjs' && npm run build:copy-native",
"build:napi": "napi build --platform --dts native.d.ts --js native.js --cargo-cwd rust -p bindings_napi --cargo-name bindings_napi",
"build:napi": "napi build --platform --dts native.d.ts --js false --cargo-cwd rust -p bindings_napi --cargo-name bindings_napi",
"build:wasm": "wasm-pack build rust/bindings_wasm --out-dir ../../wasm --target web --no-pack && shx rm wasm/.gitignore",
"build:wasm:node": "wasm-pack build rust/bindings_wasm --out-dir ../../wasm-node --target nodejs --no-pack && shx rm wasm-node/.gitignore",
"update:napi": "npm run build:napi && npm run build:copy-native",
Expand Down

0 comments on commit 10eb5e8

Please sign in to comment.