Skip to content

Homebrew bottle: binary install + clean mlx-c dependency handling #139

@Pushkinist

Description

@Pushkinist

Problem

Installing rMLX via Homebrew compiles from source: the formula is
depends_on "rust" => :build + cargo install. So brew install rmlx
pulls the Rust toolchain and builds the whole workspace on the user's Mac
(slow, needs a compiler). The prebuilt binary on the GitHub Release is the
only true binary path, and it's a separate manual download.

We already link mlx-c correctly: the binary records the absolute opt paths

/opt/homebrew/opt/mlx-c/lib/libmlxc.dylib
/opt/homebrew/opt/mlx/lib/libmlx.dylib

and /opt/homebrew is the fixed Homebrew prefix on Apple Silicon, so a
prebuilt binary already resolves mlx-c on any standard arm64 brew machine.
The auto-link is already solved — what's missing is a binary install
channel and a clean "mlx-c not installed" failure.

What to do

Ship a Homebrew bottle (precompiled binary) for the formula.

Then brew install rmlx:

  1. Downloads the prebuilt binary — no Rust toolchain, no source compile.
  2. Resolves depends_on "mlx-c" → brew installs/links mlx-c automatically.
  3. If mlx-c cannot be provided, brew fails cleanly at install (dependency
    error), instead of a cryptic dyld crash at first run.
  4. The binary's absolute opt path resolves because brew placed mlx-c at
    exactly /opt/homebrew/opt/mlx-c.

Scope:

  • Build the bottle locally (brew bottle) — arm64 only, per supported
    macOS major. (Hosted CI can't build rMLX: no Metal — see
    docs/RELEASING.md. Bottle is built + uploaded as part of the local
    release flow, like the existing tarball.)
  • Add the bottle do … sha256 … end block to
    packaging/homebrew/rmlx.rb and sync to the tap.
  • Host bottle artifacts (GitHub Release assets or a bottle root) and
    point the formula at them.
  • Add the bottle build + upload steps to docs/RELEASING.md.
  • Verify: on a clean machine, brew install rmlx pulls the binary (no
    compile) and runs; uninstall mlx-c first → install fails cleanly.

Why

  • "Just install rMLX" → one brew install rmlx, binary download, no
    compiler. Removes the from-source step that's the current install pain.
  • "Fail if no mlx-c" → routed through brew's dependency engine (clean error
    at install time) instead of a load-time dyld crash that can't be caught as
    a Rust panic (dyld fails before main() runs).

Rejected alternatives

  • Static link — no .a shipped by mlx-c/mlx kegs (dylib-only), and
    mlx.metallib is ~150 MB loaded at runtime by libmlx. Bundling/static
    would have to ship + place 150 MB → violates the single-binary tenet.
  • Weak-link + startup NULL-check — gives a pretty error on the bare
    tarball path, but makes every mlx symbol weak-bound (fragile) for marginal
    value once the bottle exists.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions