Skip to content

Commit

Permalink
Support multi-arch prebuilds for M1 (Apple silicon) (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
vweevers authored Sep 12, 2021
1 parent d512533 commit d9c2118
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 1 deletion.
38 changes: 37 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,13 @@ load.path = function (dir) {
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', platform + '-' + arch)
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]
Expand All @@ -85,6 +90,34 @@ 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()
Expand Down Expand Up @@ -164,3 +197,6 @@ function isAlpine (platform) {
load.parseTags = parseTags
load.matchTags = matchTags
load.compareTags = compareTags
load.parseTuple = parseTuple
load.matchTuple = matchTuple
load.compareTuples = compareTuples
50 changes: 50 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ var shuffle = require('array-shuffle')
var parseTags = require('.').parseTags
var matchTags = require('.').matchTags
var compareTags = require('.').compareTags
var parseTuple = require('.').parseTuple
var matchTuple = require('.').matchTuple
var compareTuples = require('.').compareTuples

test('parse tags', function (t) {
t.is(parseTags('ignored'), undefined)
Expand Down Expand Up @@ -119,6 +122,53 @@ test('match and sort tags', function (t) {
t.end()
})

test('parse tuples', function (t) {
t.same(parseTuple('linux-arm64'), {
name: 'linux-arm64',
platform: 'linux',
architectures: ['arm64']
})

t.same(parseTuple('darwin-x64+arm64'), {
name: 'darwin-x64+arm64',
platform: 'darwin',
architectures: ['x64', 'arm64']
})

// Should skip invalid tuples
t.is(parseTuple(''), undefined)
t.is(parseTuple('linux-'), undefined)
t.is(parseTuple('-arm64'), undefined)
t.is(parseTuple('linux-arm64+'), undefined)
t.is(parseTuple('linux-arm64++x64'), undefined)
t.is(parseTuple('linux-+arm64'), undefined)

t.end()
})

test('sort tuples', function (t) {
var tuples = ['darwin-arm64+x64+ia32', 'darwin-x64', 'darwin-x64+arm64']
var sorted = tuples.map(parseTuple).sort(compareTuples).map(getTupleName)

t.same(sorted, ['darwin-x64', 'darwin-x64+arm64', 'darwin-arm64+x64+ia32'])
t.end()
})

test('match tuples', function (t) {
var tuples = ['linux-arm64', 'darwin-x64+arm64', 'darwin-x64'].map(parseTuple)

t.is(tuples.filter(matchTuple('darwin', 'x64')).sort(compareTuples)[0].name, 'darwin-x64')
t.is(tuples.filter(matchTuple('darwin', 'arm64')).sort(compareTuples)[0].name, 'darwin-x64+arm64')
t.is(tuples.filter(matchTuple('linux', 'arm64')).sort(compareTuples)[0].name, 'linux-arm64')
t.is(tuples.some(matchTuple('linux', 'other')), false)
t.is(tuples.some(matchTuple('other', 'arm64')), false)
t.end()
})

function getTupleName (tuple) {
return tuple.name
}

function getFile (tags) {
return tags.file
}

0 comments on commit d9c2118

Please sign in to comment.