deno_audio icon indicating copy to clipboard operation
deno_audio copied to clipboard

[FEATURE REQUEST] Support for Apple Silicon (M1)

Open silvioprog opened this issue 2 years ago • 3 comments

When we try to run the module in a macOS running in arm64 architecture:

deno run --allow-all --unstable index.ts
error: Uncaught (in promise) Error: Could not open library: Could not open library: dlopen(~/Library/Caches/deno/plug/https/github.com/f53f000ac09e54195c49f3ca7d32b3dcff62ed2a62e213f36a5a4e02875d7d7c.dylib, 0x0005): tried: '~/Library/Caches/deno/plug/https/github.com/f53f000ac09e54195c49f3ca7d32b3dcff62ed2a62e213f36a5a4e02875d7d7c.dylib'
(mach-o file, but is an incompatible architecture (have (x86_64), need (arm64e)))
  return Deno.dlopen(file, symbols);
              ^
    at new DynamicLibrary (deno:ext/ffi/00_ffi.js:274:39)
    at Object.dlopen (deno:ext/ffi/00_ffi.js:368:12)
    at prepare (https://deno.land/x/[email protected]/plug.ts:106:15)
    at async https://deno.land/x/[email protected]/bindings/bindings.ts:28:14

Notice the error part: mach-o file, but is an incompatible architecture (have (x86_64), need (arm64e))

silvioprog avatar Dec 09 '22 03:12 silvioprog

Running deno_bindgen --release in my laptop, it generated the following binding (using the library locally, from ../target/release):

// Auto-generated with deno_bindgen
import { CachePolicy, prepare } from "https://deno.land/x/[email protected]/plug.ts"

function encode(v: string | Uint8Array): Uint8Array {
  if (typeof v !== "string") return v
  return new TextEncoder().encode(v)
}

function decode(v: Uint8Array): string {
  return new TextDecoder().decode(v)
}

function readPointer(v: any): Uint8Array {
  const ptr = new Deno.UnsafePointerView(v as bigint)
  const lengthBe = new Uint8Array(4)
  const view = new DataView(lengthBe.buffer)
  ptr.copyInto(lengthBe, 0)
  const buf = new Uint8Array(view.getUint32(0))
  ptr.copyInto(buf, 4)
  return buf
}

const url = new URL("../target/release", import.meta.url)
let uri = url.toString()
if (!uri.endsWith("/")) uri += "/"

let darwin: string | { aarch64: string; x86_64: string } = uri
  + "libdeno_audio.dylib"

if (url.protocol !== "file:") {
  // Assume that remote assets follow naming scheme
  // for each macOS artifact.
  darwin = {
    aarch64: uri + "libdeno_audio_arm64.dylib",
    x86_64: uri + "libdeno_audio.dylib",
  }
}

const opts = {
  name: "deno_audio",
  urls: {
    darwin,
    windows: uri + "deno_audio.dll",
    linux: uri + "libdeno_audio.so",
  },
  policy: undefined,
}
const _lib = await prepare(opts, {
  play: { parameters: ["pointer", "usize"], result: "void", nonblocking: true },
})

export function play(a0: string) {
  const a0_buf = encode(a0)
  const a0_ptr = Deno.UnsafePointer.of(a0_buf)
  let rawResult = _lib.symbols.play(a0_ptr, a0_buf.byteLength)
  const result = rawResult
  return result
}

...and this library below:

libdeno_audio.dylib.zip

...that worked like a charm.

Anyway, it would be nice to provide arm64 binary at littledivy/deno_audio/releases too.

silvioprog avatar Dec 09 '22 03:12 silvioprog

Good news from GitHub blog:

GitHub Actions: Self-hosted runners now support Apple M1 hardware

  • https://github.blog/changelog/2022-08-09-github-actions-self-hosted-runners-now-support-apple-m1-hardware
  • https://github.com/actions/runner/blob/main/docs/start/envosx.md
  • https://github.com/github/roadmap/issues/528

silvioprog avatar Dec 09 '22 03:12 silvioprog

Running deno_bindgen --release in my laptop, it generated the following binding (using the library locally, from ../target/release):

// Auto-generated with deno_bindgen
import { CachePolicy, prepare } from "https://deno.land/x/[email protected]/plug.ts"

function encode(v: string | Uint8Array): Uint8Array {
  if (typeof v !== "string") return v
  return new TextEncoder().encode(v)
}

function decode(v: Uint8Array): string {
  return new TextDecoder().decode(v)
}

function readPointer(v: any): Uint8Array {
  const ptr = new Deno.UnsafePointerView(v as bigint)
  const lengthBe = new Uint8Array(4)
  const view = new DataView(lengthBe.buffer)
  ptr.copyInto(lengthBe, 0)
  const buf = new Uint8Array(view.getUint32(0))
  ptr.copyInto(buf, 4)
  return buf
}

const url = new URL("../target/release", import.meta.url)
let uri = url.toString()
if (!uri.endsWith("/")) uri += "/"

let darwin: string | { aarch64: string; x86_64: string } = uri
  + "libdeno_audio.dylib"

if (url.protocol !== "file:") {
  // Assume that remote assets follow naming scheme
  // for each macOS artifact.
  darwin = {
    aarch64: uri + "libdeno_audio_arm64.dylib",
    x86_64: uri + "libdeno_audio.dylib",
  }
}

const opts = {
  name: "deno_audio",
  urls: {
    darwin,
    windows: uri + "deno_audio.dll",
    linux: uri + "libdeno_audio.so",
  },
  policy: undefined,
}
const _lib = await prepare(opts, {
  play: { parameters: ["pointer", "usize"], result: "void", nonblocking: true },
})

export function play(a0: string) {
  const a0_buf = encode(a0)
  const a0_ptr = Deno.UnsafePointer.of(a0_buf)
  let rawResult = _lib.symbols.play(a0_ptr, a0_buf.byteLength)
  const result = rawResult
  return result
}

...and this library below:

libdeno_audio.dylib.zip

...that worked like a charm.

Anyway, it would be nice to provide arm64 binary at littledivy/deno_audio/releases too.

How would I use your .dylib to use the play function in my code?

Alixxx-please avatar May 19 '23 15:05 Alixxx-please