digilent-waveforms 0.0.16

Bindings for Digilent Waveforms API
Documentation
extern crate bindgen;

use std::env;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::io::BufWriter;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;

use regex::Regex;

fn main() {
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

    if cfg!(feature = "link-with-stub") {
        let stubs_dir = out_path.join("stubs");
        let current_dir = env::current_dir()
            .expect("Can't get current directory");

        if stubs_dir.exists() {
            std::fs::remove_dir_all(&stubs_dir)
                .expect("Can't remove stubs directory");
        }
        std::fs::create_dir_all(&stubs_dir)
            .expect("Can't create stubs directory");

        std::fs::copy(current_dir.join("dwf.h"), stubs_dir.join("dwf.h"))
            .expect("Can't copy dwf.h to stubs directory");

        println!("cargo:rustc-link-search=native={}", stubs_dir.to_string_lossy());

        let stub_c = stubs_dir.join("dwf.c");
        let mut out = BufWriter::new(File::create(&stub_c)
            .expect(r###"Can't create "dwf.c""###));
        writeln!(out, r###"#include "dwf.h""###).unwrap();
        let fn_def_pattern = Regex::new(r###"DWFAPI BOOL (.*);.*"###).unwrap();
        for line in BufReader::new(File::open("dwf.h")
            .expect(r###"Can't open "dwf.h""###)).lines() {
            if let Some(captures) = fn_def_pattern.captures(&line.unwrap()) {
                let signature = captures.get(1).unwrap().as_str();
                writeln!(out, "BOOL {} {{ return 0; }}", signature).unwrap();
            }
        }
        drop(out);

        let so_name = if cfg!(target_os = "linux") {
            "libdwf.so"
        } else if cfg!(target_os = "windows") {
            "dwf.dll"
        } else if cfg!(target_os = "macos") {
            "libdwf.dylib"
        } else {
            unimplemented!("Only Linux, Mac OS and Windows are supported");
        };
        let stub_so = stubs_dir.join(so_name);


        let mut cc_args = vec!["-shared"];
        if !cfg!(target_os = "windows") {
            cc_args.push("-fPIC");
        }
        cc_args.extend_from_slice(&["-x", "c++", "-o", stub_so.to_str().unwrap(), stub_c.to_str().unwrap()]);
        let cc_out = Command::new("clang")
            .args(&cc_args)
            .output()
            .expect("Failed to compile stub library");

        if !cc_out.status.success() {
            eprintln!("cc output: {:?}", cc_out);
        }
    }

    println!("cargo:rustc-link-lib=dwf");

    let bindings = bindgen::Builder::default()
        .header("wrapper.h")
        .generate()
        .expect("Unable to generate bindings");

    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}