123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- 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')
- var armv = process.env.ARM_VERSION || (arch === 'arm64' ? '8' : vars.arm_version) || ''
- var uv = (process.versions.uv || '').split('.')[0]
- module.exports = load
- function load (dir) {
- return runtimeRequire(load.resolve(dir))
- }
- load.resolve = 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 && tags.runtime !== runtime && !runtimeAgnostic(tags)) return false
- if (tags.abi && 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
|