mirtal-sys 0.1.0

Private native bridge for mirtal
use std::{
    env,
    error::Error,
    path::{Path, PathBuf},
};

fn main() -> Result<(), Box<dyn Error>> {
    let manifest =
        PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").ok_or("CARGO_MANIFEST_DIR is unset")?);
    println!("cargo:include={}", manifest.join("native/include").display());
    println!("cargo:rerun-if-env-changed=MLX_PREFIX");
    println!("cargo:rerun-if-changed=src/lib.rs");
    println!("cargo:rerun-if-changed=native/include/mirtal/bridge.h");
    println!("cargo:rerun-if-changed=native/include/mirtal/bridge/attention.h");
    println!("cargo:rerun-if-changed=native/include/mirtal/bridge/ops.h");
    println!("cargo:rerun-if-changed=native/include/mirtal/bridge/aliasing.h");
    println!("cargo:rerun-if-changed=native/include/mirtal/bridge/prepared_metal.h");
    println!("cargo:rerun-if-changed=native/include/mirtal/bridge/quantized.h");
    println!("cargo:rerun-if-changed=native/include/mirtal/bridge/read.h");
    println!("cargo:rerun-if-changed=native/include/mirtal/bridge/rope.h");
    println!("cargo:rerun-if-changed=native/include/mirtal/native.h");
    println!("cargo:rerun-if-changed=native/src/bridge.cpp");
    println!("cargo:rerun-if-changed=native/src/compile.cpp");
    println!("cargo:rerun-if-changed=native/src/metal.cpp");
    println!("cargo:rerun-if-changed=native/src/prepared_metal.cpp");
    println!("cargo:rerun-if-changed=native/src/graph.cpp");
    println!("cargo:rerun-if-changed=native/src/io.cpp");
    println!("cargo:rerun-if-changed=native/src/ops.cpp");
    println!("cargo:rerun-if-changed=native/src/aliasing.cpp");
    println!("cargo:rerun-if-changed=native/src/quantized.cpp");
    println!("cargo:rerun-if-changed=native/src/read.cpp");
    println!("cargo:rerun-if-changed=native/src/rope.cpp");
    let prefix = mlx_prefix()?;
    let include = prefix.join("include");
    let library = prefix.join("lib");
    require(&include.join("mlx/mlx.h"))?;
    require(&library.join("libmlx.dylib"))?;
    require(&library.join("mlx.metallib"))?;
    cxx_build::bridges([
        "src/lib.rs",
        "src/graph.rs",
        "src/io.rs",
        "src/ops.rs",
        "src/aliasing.rs",
        "src/read.rs",
    ])
    .file("native/src/bridge.cpp")
    .file("native/src/attention.cpp")
    .file("native/src/compile.cpp")
    .file("native/src/graph.cpp")
    .file("native/src/io.cpp")
    .file("native/src/metal.cpp")
    .file("native/src/prepared_metal.cpp")
    .file("native/src/ops.cpp")
    .file("native/src/aliasing.cpp")
    .file("native/src/quantized.cpp")
    .file("native/src/read.cpp")
    .file("native/src/rope.cpp")
    .include("native/include")
    .include(&include)
    .include(include.join("metal_cpp"))
    .std("c++20")
    .flag_if_supported("-Wno-deprecated-copy")
    .flag_if_supported("-Wno-unused-parameter")
    .warnings(true)
    .compile("mirtal_bridge");
    println!("cargo:rustc-link-search=native={}", library.display());
    println!("cargo:rustc-link-lib=dylib=mlx");
    println!("cargo:rustc-link-lib=dylib=c++");
    println!("cargo:rustc-link-lib=framework=Foundation");
    println!("cargo:rustc-link-lib=framework=Metal");
    println!("cargo:rustc-link-lib=framework=QuartzCore");
    println!("cargo:rustc-link-arg=-Wl,-rpath,{}", library.display());
    Ok(())
}

fn mlx_prefix() -> Result<PathBuf, Box<dyn Error>> {
    if let Some(prefix) = env::var_os("MLX_PREFIX") {
        return Ok(PathBuf::from(prefix));
    }
    ["/opt/homebrew/opt/mlx", "/usr/local/opt/mlx"]
        .into_iter()
        .map(PathBuf::from)
        .find(|path| path.exists())
        .ok_or_else(|| "MLX was not found; set MLX_PREFIX".into())
}

fn require(path: &Path) -> Result<(), Box<dyn Error>> {
    path.exists()
        .then_some(())
        .ok_or_else(|| format!("required MLX path does not exist: {}", path.display()).into())
}