-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added support for armv7 which also fixes #4.
- Loading branch information
Showing
7 changed files
with
241 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
var fs = require('fs') | ||
var path = require('path') | ||
var os = require('os') | ||
|
||
// Workaround to fix webpack's build warnings: 'the request of a dependency is an expression' | ||
var runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require // eslint-disable-line | ||
|
||
var vars = (process.config && process.config.variables) || {} | ||
var prebuildsOnly = !!process.env.PREBUILDS_ONLY | ||
var abi = process.versions.modules // TODO: support old node where this is undef | ||
var runtime = isElectron() ? 'electron' : (isNwjs() ? 'node-webkit' : 'node') | ||
|
||
var arch = process.env.npm_config_arch || os.arch() | ||
var platform = process.env.npm_config_platform || os.platform() | ||
var libc = process.env.LIBC || (isAlpine(platform) ? 'musl' : 'glibc') | ||
// ARMv7 detection patched to avoid arm_version === "default" on other arm systems than arm64 ones | ||
var armv = process.env.ARM_VERSION || (arch === 'arm64' ? '8' : (arch === 'arm' ? (vars.arm_version === 'default' ? '7' : vars.arm_version) : '')) || '' | ||
var uv = (process.versions.uv || '').split('.')[0] | ||
|
||
module.exports = load | ||
|
||
function load (dir) { | ||
return runtimeRequire(load.path(dir)) | ||
} | ||
|
||
load.path = function (dir) { | ||
dir = path.resolve(dir || '.') | ||
|
||
try { | ||
var name = runtimeRequire(path.join(dir, 'package.json')).name.toUpperCase().replace(/-/g, '_') | ||
if (process.env[name + '_PREBUILD']) dir = process.env[name + '_PREBUILD'] | ||
} catch (err) {} | ||
|
||
if (!prebuildsOnly) { | ||
var release = getFirst(path.join(dir, 'build/Release'), matchBuild) | ||
if (release) return release | ||
|
||
var debug = getFirst(path.join(dir, 'build/Debug'), matchBuild) | ||
if (debug) return debug | ||
} | ||
|
||
var prebuild = resolve(dir) | ||
if (prebuild) return prebuild | ||
|
||
var nearby = resolve(path.dirname(process.execPath)) | ||
if (nearby) return nearby | ||
|
||
var target = [ | ||
'platform=' + platform, | ||
'arch=' + arch, | ||
'runtime=' + runtime, | ||
'abi=' + abi, | ||
'uv=' + uv, | ||
armv ? 'armv=' + armv : '', | ||
'libc=' + libc, | ||
'node=' + process.versions.node, | ||
process.versions.electron ? 'electron=' + process.versions.electron : '', | ||
typeof __webpack_require__ === 'function' ? 'webpack=true' : '' // eslint-disable-line | ||
].filter(Boolean).join(' ') | ||
|
||
throw new Error('No native build was found for ' + target + '\n loaded from: ' + dir + '\n') | ||
|
||
function resolve (dir) { | ||
// Find matching "prebuilds/<platform>-<arch>" directory | ||
var tuples = readdirSync(path.join(dir, 'prebuilds')).map(parseTuple) | ||
var tuple = tuples.filter(matchTuple(platform, arch)).sort(compareTuples)[0] | ||
if (!tuple) return | ||
|
||
// Find most specific flavor first | ||
var prebuilds = path.join(dir, 'prebuilds', tuple.name) | ||
var parsed = readdirSync(prebuilds).map(parseTags) | ||
var candidates = parsed.filter(matchTags(runtime, abi)) | ||
var winner = candidates.sort(compareTags(runtime))[0] | ||
if (winner) return path.join(prebuilds, winner.file) | ||
} | ||
} | ||
|
||
function readdirSync (dir) { | ||
try { | ||
return fs.readdirSync(dir) | ||
} catch (err) { | ||
return [] | ||
} | ||
} | ||
|
||
function getFirst (dir, filter) { | ||
var files = readdirSync(dir).filter(filter) | ||
return files[0] && path.join(dir, files[0]) | ||
} | ||
|
||
function matchBuild (name) { | ||
return /\.node$/.test(name) | ||
} | ||
|
||
function parseTuple (name) { | ||
// Example: darwin-x64+arm64 | ||
var arr = name.split('-') | ||
if (arr.length !== 2) return | ||
|
||
var platform = arr[0] | ||
var architectures = arr[1].split('+') | ||
|
||
if (!platform) return | ||
if (!architectures.length) return | ||
if (!architectures.every(Boolean)) return | ||
|
||
return { name, platform, architectures } | ||
} | ||
|
||
function matchTuple (platform, arch) { | ||
return function (tuple) { | ||
if (tuple == null) return false | ||
if (tuple.platform !== platform) return false | ||
return tuple.architectures.includes(arch) | ||
} | ||
} | ||
|
||
function compareTuples (a, b) { | ||
// Prefer single-arch prebuilds over multi-arch | ||
return a.architectures.length - b.architectures.length | ||
} | ||
|
||
function parseTags (file) { | ||
var arr = file.split('.') | ||
var extension = arr.pop() | ||
var tags = { file: file, specificity: 0 } | ||
|
||
if (extension !== 'node') return | ||
|
||
for (var i = 0; i < arr.length; i++) { | ||
var tag = arr[i] | ||
|
||
if (tag === 'node' || tag === 'electron' || tag === 'node-webkit') { | ||
tags.runtime = tag | ||
} else if (tag === 'napi') { | ||
tags.napi = true | ||
} else if (tag.slice(0, 3) === 'abi') { | ||
tags.abi = tag.slice(3) | ||
} else if (tag.slice(0, 2) === 'uv') { | ||
tags.uv = tag.slice(2) | ||
} else if (tag.slice(0, 4) === 'armv') { | ||
tags.armv = tag.slice(4) | ||
} else if (tag === 'glibc' || tag === 'musl') { | ||
tags.libc = tag | ||
} else { | ||
continue | ||
} | ||
|
||
tags.specificity++ | ||
} | ||
|
||
return tags | ||
} | ||
|
||
function matchTags (runtime, abi) { | ||
return function (tags) { | ||
if (tags == null) return false | ||
if (tags.runtime !== runtime && !runtimeAgnostic(tags)) return false | ||
if (tags.abi !== abi && !tags.napi) return false | ||
if (tags.uv && tags.uv !== uv) return false | ||
if (tags.armv && tags.armv !== armv) return false | ||
if (tags.libc && tags.libc !== libc) return false | ||
|
||
return true | ||
} | ||
} | ||
|
||
function runtimeAgnostic (tags) { | ||
return tags.runtime === 'node' && tags.napi | ||
} | ||
|
||
function compareTags (runtime) { | ||
// Precedence: non-agnostic runtime, abi over napi, then by specificity. | ||
return function (a, b) { | ||
if (a.runtime !== b.runtime) { | ||
return a.runtime === runtime ? -1 : 1 | ||
} else if (a.abi !== b.abi) { | ||
return a.abi ? -1 : 1 | ||
} else if (a.specificity !== b.specificity) { | ||
return a.specificity > b.specificity ? -1 : 1 | ||
} else { | ||
return 0 | ||
} | ||
} | ||
} | ||
|
||
function isNwjs () { | ||
return !!(process.versions && process.versions.nw) | ||
} | ||
|
||
function isElectron () { | ||
if (process.versions && process.versions.electron) return true | ||
if (process.env.ELECTRON_RUN_AS_NODE) return true | ||
return typeof window !== 'undefined' && window.process && window.process.type === 'renderer' | ||
} | ||
|
||
function isAlpine (platform) { | ||
return platform === 'linux' && fs.existsSync('/etc/alpine-release') | ||
} | ||
|
||
// Exposed for unit tests | ||
// TODO: move to lib | ||
load.parseTags = parseTags | ||
load.matchTags = matchTags | ||
load.compareTags = compareTags | ||
load.parseTuple = parseTuple | ||
load.matchTuple = matchTuple | ||
load.compareTuples = compareTuples |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters