cp2k-spla-sys 0.3.1

Static SpLA build for cp2k-rs
//! Builds static SpLA 1.6.1 (Specialized Parallel Linear Algebra) from source
//! and exports its install prefix via `cargo:root` (DEP_CP2K_SPLA_ROOT).
//!
//! SpLA is a distributed GEMM library used by SIRIUS. It requires MPI and a
//! host BLAS (the workspace's static OpenBLAS).

use cp2k_build_utils as bu;
use std::path::PathBuf;
use std::process::Command;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-env-changed=CP2K_TARGET_ARCH");

    let arch = bu::target_arch();
    let stable_dir = bu::stable_dir("spla");
    let src_dir = stable_dir.join("src");
    let build_dir = stable_dir.join("build");
    let install_dir = stable_dir.join("install");

    // Static OpenBLAS location (host BLAS for local GEMM). SpLA 1.6.1 discovers
    // BLAS via CMake's FindBLAS (BLA_VENDOR), searching CMAKE_LIBRARY_PATH.
    let openblas_lib_dir = PathBuf::from(
        std::env::var("DEP_OPENBLAS_LIBRARY")
            .expect("DEP_OPENBLAS_LIBRARY not set – openblas-src must be a dependency"),
    );

    if install_dir.join("lib").join("libspla.a").exists() {
        println!(
            "cargo:warning=SpLA already installed at {}",
            install_dir.display()
        );
        bu::emit_root(&install_dir);
        return;
    }

    if !src_dir.exists() {
        println!("cargo:warning=Downloading SpLA 1.6.1...");
        let tarball = stable_dir.join("SpLA-1.6.1.tar.gz");
        // Stable mirror maintained by the CP2K project (matches the toolchain).
        bu::download(
            "https://www.cp2k.org/static/downloads/SpLA-1.6.1.tar.gz",
            &tarball,
        );
        bu::verify_sha256(
            &tarball,
            "62b51e6ce05c41cfc1c6f6600410f9549a209c50f0331e1db41047f94493e02f",
        );
        std::fs::create_dir_all(&src_dir).expect("Failed to create spla src dir");
        bu::run(
            Command::new("tar").args([
                "-xzf",
                tarball.to_str().unwrap(),
                "--strip-components=1",
                "-C",
                src_dir.to_str().unwrap(),
            ]),
            "SpLA extract",
        );
    }

    std::fs::create_dir_all(&build_dir).expect("Failed to create SpLA build dir");
    let num_jobs = bu::num_jobs();

    let mpi_bin = bu::mpi_bin_dir();
    let mpi_cc = mpi_bin.join("mpicc").display().to_string();
    let mpi_cxx = mpi_bin.join("mpicxx").display().to_string();
    let mpi_fc = mpi_bin.join("mpif90").display().to_string();

    println!("cargo:warning=Configuring SpLA with CMake...");
    bu::run(
        Command::new("cmake")
            .args([
                "-S",
                src_dir.to_str().unwrap(),
                "-B",
                build_dir.to_str().unwrap(),
                &format!("-DCMAKE_INSTALL_PREFIX={}", install_dir.display()),
                "-DCMAKE_INSTALL_LIBDIR=lib",
                &format!("-DCMAKE_C_COMPILER={mpi_cc}"),
                &format!("-DCMAKE_CXX_COMPILER={mpi_cxx}"),
                &format!("-DCMAKE_Fortran_COMPILER={mpi_fc}"),
                "-DCMAKE_BUILD_TYPE=RelWithDebInfo",
                "-DCMAKE_POSITION_INDEPENDENT_CODE=ON",
                "-DBUILD_SHARED_LIBS=OFF",
                "-DSPLA_FORTRAN=ON",
                "-DSPLA_STATIC=ON",
                "-DSPLA_INSTALL=ON",
                "-DSPLA_BUILD_TESTS=OFF",
                "-DSPLA_BUILD_EXAMPLES=OFF",
                // BLAS: static OpenBLAS via FindBLAS (BLA_VENDOR + library path).
                "-DBLA_VENDOR=OpenBLAS",
                "-DBLA_STATIC=ON",
                &format!("-DCMAKE_LIBRARY_PATH={}", openblas_lib_dir.display()),
                &format!("-DCMAKE_C_FLAGS={}", bu::march_flag(&arch)),
                &format!("-DCMAKE_CXX_FLAGS={}", bu::march_flag(&arch)),
                &format!("-DCMAKE_Fortran_FLAGS={}", bu::march_flag(&arch)),
                &format!("-DCMAKE_BUILD_PARALLEL_LEVEL={num_jobs}"),
            ])
            .current_dir(&build_dir),
        "SpLA configure",
    );

    println!("cargo:warning=Building SpLA...");
    bu::run(
        Command::new("cmake")
            .args(["--build", build_dir.to_str().unwrap(), "-j", &num_jobs])
            .current_dir(&build_dir),
        "SpLA build",
    );

    println!("cargo:warning=Installing SpLA...");
    bu::run(
        Command::new("cmake")
            .args(["--install", build_dir.to_str().unwrap()])
            .current_dir(&build_dir),
        "SpLA install",
    );

    println!("cargo:warning=SpLA installed to {}", install_dir.display());
    bu::emit_root(&install_dir);
}