hasty 0.2.5

A Rust interface to system BLAS libraries for fast linear algebra operations
Documentation
use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

#[cfg(feature = "blas")]
#[allow(unreachable_code)]
fn cmake_blas_args() -> Option<(String, String)> {
    #[cfg(feature = "build_openblas")]
    {
        use std::io::Write;

        println!("cargo:warning=Compiling the C library. This might take a few minutes...");
        std::io::stdout().flush().unwrap();

        return Some((
            String::from("HASTY_IMPL_BUILD_OPENBLAS"),
            String::from("ON"),
        ));
    }

    #[cfg(feature = "prebuilt_openblas")]
    {
        use std::io::Write;

        println!("cargo:warning=Using prebuilt OpenBLAS library");
        std::io::stdout().flush().unwrap();

        return Some((String::from("HASTY_IMPL_GET_BLAS"), String::from("ON")));
    }

    #[cfg(feature = "blas_acml")]
    {
        return Some((String::from("HASTY_IMPL_ACML"), String::from("ON")));
    }

    #[cfg(feature = "blas_accelerate")]
    {
        return Some((String::from("HASTY_IMPL_ACCELERATE"), String::from("ON")));
    }

    #[cfg(feature = "blas_arm")]
    {
        return Some((String::from("HASTY_IMPL_ARM"), String::from("ON")));
    }

    #[cfg(feature = "blas_atlas")]
    {
        return Some((String::from("HASTY_IMPL_atlas"), String::from("ON")));
    }

    #[cfg(feature = "blas_blis")]
    {
        return Some((String::from("HASTY_IMPL_BLIS"), String::from("ON")));
    }

    #[cfg(feature = "blas_openblas")]
    {
        return Some((String::from("HASTY_IMPL_OPENBLAS"), String::from("ON")));
    }

    #[cfg(feature = "mkl")]
    {
        return Some((String::from("HASTY_IMPL_MKL"), String::from("ON")));
    }

    None
}

fn main() {
    let mut cmaker = cmake::Config::new("hasty_impl");

    #[cfg(feature = "blas")]
    {
        cmaker.define("HASTY_USE_BLAS", "ON");

        if let Ok(path) = env::var("HASTY_BLAS_PATH") {
            cmaker.define("HASTY_BLAS_PATH", path);
        }

        // Define CMake arguments based on features
        if let Some((key, value)) = cmake_blas_args() {
            println!("Key: {key}, Value: {value}");
            cmaker.define(key, value);
        }
    }

    #[cfg(feature = "opencl")]
    {
        cmaker.define("HASTY_USE_OPENCL", "ON");
    }

    let dst = cmaker.build();

    println!("cargo:rustc-link-search=native={}/lib", dst.display());
    println!("cargo:rustc-link-lib=static=hasty_impl");

    // Open the file
    let file = File::open(format!("{}/build/library_config.txt", dst.display()))
        .expect("Failed to open library_config.txt");

    // Create a buffered reader
    let reader = BufReader::new(file);

    println!("cargo:rustc-link-lib=c++");
    // Iterate over each line in the file
    for line in reader.lines() {
        let line = line
            .expect("Could not read line from file")
            .trim()
            .to_string();

        match line.as_str() {
            "accelerate" => {
                println!("cargo:rustc-link-lib=framework=Accelerate");
            }
            "opencl" => {
                println!("cargo:rustc-link-lib=framework=OpenCL");
            }
            _ => {
                // Get path and filename
                let path = PathBuf::from(line);
                let filename = path.file_name().unwrap().to_str().unwrap();

                // Strip 'lib' prefix and any extension
                let filename = filename.strip_prefix("lib").unwrap_or(filename);
                let filename = filename.split(".").next().unwrap_or(filename);

                println!(
                    "cargo:rustc-link-search=native={}",
                    path.parent().unwrap().display()
                );
                println!("cargo:rustc-link-lib=static={}", filename);
            }
        }
    }

    let mut builder = bindgen::Builder::default();

    #[cfg(feature = "blas")]
    {
        builder = builder.header("./hasty_impl/include/helper/define_blas.h");
    }

    #[cfg(feature = "opencl")]
    {
        builder = builder.header("./hasty_impl/include/helper/define_opencl.h");
    }

    builder = builder
        .header("./hasty_impl/include/level2/gemv.h")
        .header("./hasty_impl/include/level3/gemm.h")
        .header("./hasty_impl/include/opencl/opencl_error_types.h")
        .header("./hasty_impl/include/opencl/opencl_configure.h")
        .header("./hasty_impl/include/opencl/opencl_memory_impl.h")
        .header("./hasty_impl/include/opencl/opencl_kernel_impl.h");

    let bindings = builder
        .generate()
        .expect("Unable to generate bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}