zyxdb 0.1.28

Rust bindings for the ZYX embedded graph database
use std::{
    env, fs,
    path::{Path, PathBuf},
};

fn main() {
    println!("cargo:rerun-if-env-changed=ZYX_LIB_DIR");

    let lib_dir = env::var_os("DEP_ZYX_LIB_DIR")
        .map(PathBuf::from)
        .or_else(|| env::var_os("ZYX_LIB_DIR").map(PathBuf::from))
        .or_else(discover_repo_lib_dir);
    if let Some(lib_dir) = lib_dir {
        emit_runtime_path(&lib_dir);
    }

    if cfg!(target_os = "windows") {
        if let Some(bin_dir) = env::var_os("DEP_ZYX_BIN_DIR").map(PathBuf::from) {
            copy_windows_runtime_dll(&bin_dir);
        }
    }
}

fn emit_runtime_path(lib_dir: &Path) {
    if cfg!(target_os = "macos") || cfg!(target_os = "linux") {
        println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_dir.display());
    }
}

fn copy_windows_runtime_dll(bin_dir: &Path) {
    let dll = bin_dir.join("zyx.dll");
    if !dll.exists() {
        return;
    }

    for dir in cargo_target_runtime_dirs() {
        if fs::create_dir_all(&dir).is_ok() {
            let _ = fs::copy(&dll, dir.join("zyx.dll"));
        }
    }
}

fn cargo_target_runtime_dirs() -> Vec<PathBuf> {
    let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"));
    let Some(profile_dir) = out_dir.ancestors().nth(3) else {
        return Vec::new();
    };
    vec![profile_dir.to_path_buf(), profile_dir.join("deps")]
}

fn discover_repo_lib_dir() -> Option<PathBuf> {
    let manifest_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR")?);
    let repo_root = manifest_dir.ancestors().nth(3)?;

    [
        "buildDir",
        "build",
        "cmake-build-debug",
        "cmake-build-release",
        "out/build",
    ]
    .into_iter()
    .map(|dir| repo_root.join(dir))
    .find(|dir| has_zyx_library(dir))
}

fn has_zyx_library(dir: &Path) -> bool {
    [
        "libzyx.dylib",
        "libzyx.so",
        "zyx.dll",
        "zyx.lib",
        "Debug/zyx.dll",
        "Debug/zyx.lib",
        "Release/zyx.dll",
        "Release/zyx.lib",
    ]
    .into_iter()
    .any(|name| dir.join(name).is_file())
}