a121-sys 0.1.2

Raw bindings to the A121 radar sensor C SDK
Documentation
use std::env;
use std::ffi::OsStr;
use std::fs;
use std::path::{Path, PathBuf};

fn main() {
    let acc_rss_libs =
        get_acc_rss_libs_path().expect("Error determining Acconeer static libs path");
    let rss_path = get_rss_path().expect("Error determining rss directory path");

    setup_linking(&acc_rss_libs);
    rerun_if_changed(&rss_path);
    check_headers_existence(&rss_path);

    generate_bindings(&rss_path).expect("Unable to generate bindings");
}

fn get_acc_rss_libs_path() -> Result<PathBuf, String> {
    let acc_rss_libs = env::var("ACC_RSS_LIBS").unwrap_or_else(|_| ".".to_string());
    PathBuf::from(acc_rss_libs)
        .canonicalize()
        .map_err(|_| "Error pointing to Acconeer static libs path.".to_string())
}

fn get_rss_path() -> Result<PathBuf, String> {
    PathBuf::from("rss")
        .canonicalize()
        .map_err(|_| "rss directory not found".to_string())
}

fn setup_linking(acc_rss_libs: &Path) {
    println!("cargo:rustc-link-search={}", acc_rss_libs.display());
    println!("cargo:rustc-link-lib=static=acconeer_a121");

    if cfg!(feature = "distance") {
        println!("cargo:rustc-link-lib=static=acc_detector_distance_a121");
    }
    if cfg!(feature = "presence") {
        println!("cargo:rustc-link-lib=static=acc_detector_presence_a121");
    }

    eprintln!("ACC_RSS_LIBS: {}", acc_rss_libs.to_str().unwrap());
}

fn rerun_if_changed(rss_path: &Path) {
    println!(
        "cargo:rerun-if-changed={}",
        rss_path.join("include").display()
    );
}

fn check_headers_existence(rss_path: &Path) {
    let headers = rss_path.join("include");
    if !headers.exists() {
        panic!("headers not found");
    }
}

fn generate_bindings(rss_path: &Path) -> Result<(), String> {
    let headers = rss_path.join("include");
    let mut bindings = bindgen::Builder::default()
        .use_core()
        .clang_arg(format!("-I{}", headers.display()))
        .layout_tests(false)
        .generate_cstr(true);

    for entry in
        fs::read_dir(&headers).map_err(|_| "Unable to read headers directory".to_string())?
    {
        let entry = entry.map_err(|_| "Error iterating headers directory".to_string())?;
        let path = entry.path();
        if path.is_file() && path.extension() == Some(OsStr::new("h")) {
            let filename = path.file_name().unwrap().to_str().unwrap();
            let is_distance = filename.contains("distance") && cfg!(feature = "distance");
            let is_presence = filename.contains("presence") && cfg!(feature = "presence");
            let is_other = !filename.contains("distance") && !filename.contains("presence");

            if is_distance || is_presence || is_other {
                bindings = bindings.header(path.to_str().unwrap());
            }
        }
    }
    bindings = c_log_wrapper(bindings);

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .generate()
        .map_err(|_| "Unable to generate bindings".to_string())?
        .write_to_file(out_path.join("bindings.rs"))
        .map_err(|_| "Unable to write bindings to file".to_string())
        .expect("Unable to write bindings to file");
    Ok(())
}

fn c_log_wrapper(mut bindings: bindgen::Builder) -> bindgen::Builder {
    cc::Build::new()
        .file("c_src/logging.c")
        .include("c_src")
        .warnings_into_errors(true)
        .extra_warnings(true)
        .compile("log");
    println!("cargo:rerun-if-changed=c_src/logging.c");
    println!("cargo:rustc-link-lib=static=log");
    bindings = bindings.header("c_src/logging.h");
    bindings
}