librist-sys 0.8.3

Bindgen bindings for librist, used by the librist-rust crate
use std::env;
use std::path::PathBuf;
use std::process::Command;

fn tell_cargo(name: &str, val: &str) {
    println!("cargo:{}={}", name, val);
}

fn main() {
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    let librist_path = out_path.join("librist/build").to_string_lossy().to_string();
    if let Err(e) = run_meson("librist", librist_path.as_ref()) {
        tell_cargo("warning", &format!("meson build of librist failed: {:?}", e));
        // fall-through, since maybe we are just running cargo doc, and if not then linking will
        // fail later anyway
    }
    tell_cargo("rustc-link-lib", "static=rist");
    tell_cargo("rustc-link-search", &format!("native={}", librist_path));

    // Tell cargo to invalidate the built crate whenever the wrapper changes
    tell_cargo("rerun-if-changed", "wrapper.h");

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header("wrapper.h")
        .clang_arg("-Ilibrist/include")
        .clang_arg("-I/usr/include/x86_64-linux-musl")
        .clang_arg(format!("-I{}/include/librist", librist_path))
        .whitelist_type("^rist_.*")
        .whitelist_function("^rist_.*")
        .whitelist_var("^RIST_.*")
        .blacklist_type("FILE")
        .blacklist_type("size_t")
        .blacklist_type("__uint\\d+_t")
        .blacklist_type("__off_t")
        .blacklist_type("__off64_t")
        .blacklist_item("_IO_.*")
        // Tell cargo to invalidate the built crate whenever any of the
        // included header files changed.
        .parse_callbacks(Box::new(bindgen::CargoCallbacks))
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}


fn run_meson(lib: &str, dir: &str) -> Result<(), String>{
    if !is_configured(dir) {
        let cross_file = env::var("MESON_CROSS_FILE");
        let mut args = vec!["--default-library=static", ".", dir];
        if let Ok(ref cross) = cross_file {
            args.push("--cross-file");
            args.push(cross);
        }
        args.push("-Dbuiltin_cjson=true");
        args.push("-Duse_mbedtls=false");
        args.push("-Dbuilt_tools=false");
        if Ok("true".to_string()) == env::var("DEBUG") {
            println!("!DEBUG!");
            env::set_var("ARGS", "-g");
        }
        run_command(lib, "meson", &args[..])?
    }
    run_command(dir, "ninja", &[])
}

fn is_target_musl_libc() -> bool {
    "musl" == env::var("CARGO_CFG_TARGET_ENV").unwrap()
}

fn run_command(dir: &str, name: &str, args: &[&str]) -> Result<(), String> {
    let mut cmd = Command::new(name);
    cmd.current_dir(dir);
    if args.len() > 0 {
        cmd.args(args);
    }
    let status = cmd.status().map_err(|e| format!("{} failed: {:?}", name, e))?;
    if status.success() {
        Ok(())
    } else {
        Err(format!("{} failed: {}", name, status))
    }
}

fn is_configured(dir: &str) -> bool {
    let mut path = PathBuf::from(dir);
    path.push("build.ninja");
    return path.as_path().exists();
}