Downloads and caches pre-built Apple MLX + EMLX NIF static archives so
iOS Mob apps can ship EMLX.Backend as an Nx backend without
cross-compiling MLX themselves.
Mirrors the MobDev.OtpDownloader / MobDev.PythonAppleSupport pattern:
hashed URL + cached download at ~/.mob/cache/mlx-<version>-<target>/,
validated against the expected layout. Reused across projects.
Used by MobDev.NativeBuild when the project's deps include :emlx or
mob.exs declares mlx_enabled: true. The build template sources
MLX_DIR from dir/1 and links libmlx.a + libemlx.a from there.
Scope (v1)
CPU-only MLX. Metal-on-iOS is gated behind a separate tarball variant
(libmlx-<ver>-ios-device-metal.tar.gz) that requires the iOS-Metal
CMakeLists patch and the Xcode Metal Toolchain installed at build
time. v1 ships CPU + Accelerate framework — already
~10-50x faster than Nx.BinaryBackend for typical Nx workloads.
Local-build override
Set MOB_MLX_LOCAL_TARBALL_DIR=/path/to/dir to bypass the GitHub
download and use locally-built tarballs (named exactly as
tarball_name/1 returns). Useful when iterating on the cross-compile
scripts in mob_dev/scripts/release/mlx/.
Summary
Functions
Checks a project's resolved EMLX version against the bundle's
libemlx.a. Returns {:error, message} with the migration steps when
they don't match, because the app would link but EMLX.NIF would fail
to load at runtime. nil (version couldn't be determined) passes.
Cached MLX root directory for target. May not exist if ensure/1
hasn't been called.
Download URL for the target tarball.
The :emlx dependency requirement this bundle's libemlx.a matches
(e.g. "~> 0.2.0").
Ensure the MLX bundle for target is cached and extracted.
Returns {:ok, path} where path is the unpacked root containing
lib/libmlx.a, lib/libemlx.a, include/mlx/..., VERSION.
Convenience for iOS device.
Convenience for iOS simulator.
Path to mlx.metallib if this bundle ships Metal GPU kernels, or
nil if it's a CPU-only bundle.
Pinned MLX upstream version (e.g. 0.25.1).
Bundle name (no extension, no path) for target — libmlx-0.25.1-ios-device etc.
GitHub release tag this downloader targets.
Tarball file name for target (e.g. libmlx-0.25.1-ios-device.tar.gz).
Returns true if the cache directory has the expected layout
(lib/libmlx.a, lib/libemlx.a, include/mlx/, VERSION).
Types
Functions
Checks a project's resolved EMLX version against the bundle's
libemlx.a. Returns {:error, message} with the migration steps when
they don't match, because the app would link but EMLX.NIF would fail
to load at runtime. nil (version couldn't be determined) passes.
Cached MLX root directory for target. May not exist if ensure/1
hasn't been called.
Download URL for the target tarball.
@spec emlx_requirement() :: String.t()
The :emlx dependency requirement this bundle's libemlx.a matches
(e.g. "~> 0.2.0").
Ensure the MLX bundle for target is cached and extracted.
Returns {:ok, path} where path is the unpacked root containing
lib/libmlx.a, lib/libemlx.a, include/mlx/..., VERSION.
Convenience for iOS device.
Convenience for iOS simulator.
Path to mlx.metallib if this bundle ships Metal GPU kernels, or
nil if it's a CPU-only bundle.
The CPU build (scripts/release/mlx/ios_device.sh) doesn't produce
a metallib. The Metal build (ios_device_metal.sh) puts one at
lib/mlx.metallib alongside the static archives. Callers use this
to decide whether to copy the metallib into the iOS .app bundle so
EMLX's runtime device: :gpu path can find it (via MLX's
load_colocated_library).
@spec mlx_version() :: String.t()
Pinned MLX upstream version (e.g. 0.25.1).
Bundle name (no extension, no path) for target — libmlx-0.25.1-ios-device etc.
@spec release_tag() :: String.t()
GitHub release tag this downloader targets.
Tarball file name for target (e.g. libmlx-0.25.1-ios-device.tar.gz).
Returns true if the cache directory has the expected layout
(lib/libmlx.a, lib/libemlx.a, include/mlx/, VERSION).
Public for testing and so NativeBuild can cheaply probe for a partial
cache without parsing the VERSION file.