Rust bindings for Apple's MLX framework.
Platform: Apple Silicon (macOS) only.
cargo add mlxcoreuse mlxcore::{Array, Stream};
fn main() -> mlxcore::Result<()> {
let s = Stream::default();
// The `f32` suffix matters — see the note further down.
let x = Array::from_slice(&[1.0f32, 4.0, 9.0], &[3]);
println!("{:?}", x.sqrt(&s)?.to_vec::<f32>()); // [1.0, 2.0, 3.0]
println!("{:?}", (&x * 2.0f32).to_vec::<f32>()); // [2.0, 8.0, 18.0]
Ok(())
}The bindings are layered, the same way as MLX Swift:
mlxcore (safe, idiomatic Rust API) <- crates/mlxcore
mlxcore-sys (raw unsafe FFI bindings) <- crates/mlxcore-sys, generated by bindgen
mlx-c (Apple's C API for MLX) <- crates/mlxcore-sys/third_party/mlx-c (git submodule)
mlx (Apple's C++ framework) <- fetched by mlx-c's CMake build
MLX itself is C++, which Rust cannot bind to directly. We bind against
mlx-c, Apple's official C API, whose
CMake build pulls in MLX via FetchContent.
The mlx-c submodule sits inside mlxcore-sys rather than at the repository root
because cargo package only ships files under the crate directory — from the
root it would be missing from the published crate.
git submodule update --init --recursive
make build
make testRequirements: a recent Rust toolchain, make, cmake, and Xcode command-line tools.
The first build compiles MLX from source and takes several minutes.
Runnable examples live in crates/mlxcore/examples:
cargo run --example hello # arrays, shapes, streams
cargo run --example relu # y = relu(x @ W + b) with random weightsUnsuffixed float literals are f64 in Rust, and Apple GPUs have no float64
support. Since the default stream is the GPU, &[1.0, 2.0] builds an array that
fails on every operation. Write &[1.0f32, 2.0], and &a * 2.0f32 for scalars.
float64 still works on an explicit Stream::cpu().
metal(default) — GPU backend via Metal.accelerate(default) — CPU BLAS via Apple's Accelerate framework.