cp2k-costa-sys 0.3.1

Static COSTA build for cp2k-rs
//! Builds static COSTA 2.3.2 from source and exports its install prefix via
//! `cargo:root` (DEP_CP2K_COSTA_ROOT).
//!
//! COSTA provides communication-optimal matrix redistribution and is a required
//! dependency of SIRIUS (find_package(costa CONFIG REQUIRED)). It is built
//! without the ScaLAPACK wrapper layer (COSTA_SCALAPACK=OFF), which keeps the
//! build self-contained; SIRIUS is configured with SCALAPACK off to match.

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 scalapack_root = PathBuf::from(
        std::env::var("DEP_CP2K_SCALAPACK_ROOT").expect("DEP_CP2K_SCALAPACK_ROOT not set"),
    );
    let stable_dir = bu::stable_dir("costa");
    let src_dir = stable_dir.join("src");
    let build_dir = stable_dir.join("build");
    let install_dir = stable_dir.join("install");

    if install_dir.join("lib").join("libcosta.a").exists()
        && !bu::dep_marker_stale(&stable_dir, ".version", "2.3.2")
    {
        println!(
            "cargo:warning=COSTA already installed at {}",
            install_dir.display()
        );
        bu::emit_root(&install_dir);
        return;
    }
    if install_dir.join("lib").join("libcosta.a").exists() {
        println!("cargo:warning=Cached COSTA is a different version – rebuilding...");
        for d in [&install_dir, &build_dir, &src_dir] {
            let _ = std::fs::remove_dir_all(d);
        }
    }

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

    std::fs::create_dir_all(&build_dir).expect("Failed to create COSTA 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();

    println!("cargo:warning=Configuring COSTA 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}"),
                "-DCMAKE_BUILD_TYPE=RelWithDebInfo",
                "-DCMAKE_POSITION_INDEPENDENT_CODE=ON",
                "-DBUILD_SHARED_LIBS=OFF",
                // Build the ScaLAPACK layer against our static ScaLAPACK (matches
                // the CP2K toolchain's COSTA build).
                "-DCOSTA_SCALAPACK=CUSTOM",
                "-DCOSTA_WITH_TESTS=OFF",
                "-DCOSTA_WITH_APPS=OFF",
                "-DCOSTA_WITH_BENCHMARKS=OFF",
                "-DCOSTA_WITH_PROFILING=OFF",
                &format!("-DCMAKE_C_FLAGS={}", bu::march_flag(&arch)),
                &format!("-DCMAKE_CXX_FLAGS={}", bu::march_flag(&arch)),
                &format!("-DCMAKE_BUILD_PARALLEL_LEVEL={num_jobs}"),
            ])
            // COSTA's FindSCALAPACK (CUSTOM) locates libscalapack.a via these.
            .env("SCALAPACKROOT", scalapack_root.display().to_string())
            .env("SCALAPACK_ROOT", scalapack_root.display().to_string())
            .current_dir(&build_dir),
        "COSTA configure",
    );

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

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

    println!("cargo:warning=COSTA installed to {}", install_dir.display());
    bu::write_dep_marker(&stable_dir, ".version", "2.3.2");
    bu::emit_root(&install_dir);
}