libsrt-sys 1.4.2

Bindings for libsrt
Documentation
use std::{env, error::Error, process::Command, path::PathBuf};

#[cfg(windows)]
use std::{path::Path, fs::{self, DirEntry}};

#[cfg(windows)]
const MIN_VS_VERSION: u32 = 2017;

fn main() -> Result<(), Box<dyn Error>> {
    let mut configure = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not found"));
    configure.push("srt-src");
    configure.push("configure");
    let out_dir = env::var("OUT_DIR")?;
    env::set_current_dir(&out_dir).expect("failed to set current dir to out_dir");
    if cfg!(windows) {
        make_install(configure);
        println!("cargo:rustc-link-search={}\\Release", out_dir);
    } else {
        make_install(configure);
        println!("cargo:rustc-link-search={}", out_dir);
    }
    Ok(())
}

#[cfg(windows)]
fn make_install(configure: PathBuf) {
    let mut tcl_shell = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not found"));
    tcl_shell.push("tclkit");
    tcl_shell.push("tclkit-cli-8_6_10-twapi-4_3_8-x64-max.exe");
    let mut configure_command = Command::new(tcl_shell);
    configure_command
        .arg(configure)
        .arg("--enable-apps=OFF")
        .arg(format!(
            "--pthread-include-dir={}",
            env::var("PTHREAD_INCLUDE_DIR").expect("PTHREAD_INCLUDE_DIR not set")
        ))
        .arg("--prefix=.");
    if let Ok(openssl_include_dir) = env::var("OPENSSL_INCLUDE_DIR") {
        configure_command.arg(format!("--openssl-include-dir={}", openssl_include_dir));
    }
    let output = configure_command.output().expect("failed to configure");
    if !String::from_utf8(output.stdout).expect("malformed configure output")
        .contains("Build files have been written to") {
        panic!("failed to generate build files");
    }
    let mut visual_studios: Vec<DirEntry> = fs::read_dir(Path::new("C:\\Program Files (x86)\\Microsoft Visual Studio"))
        .expect("fail to read Visual Studio dir")
        .filter(|f| f.is_ok()).map(|f| f.unwrap())
        .filter(|f| f.file_type().is_ok() && f.file_type().unwrap().is_dir())
        .filter(|f| {
            if let Ok(name) = f.file_name().into_string() {
                if let Ok(version) = name.parse::<u32>() {
                    return version >= MIN_VS_VERSION;
                }
            }
            false
        }).collect();
    if visual_studios.len() == 0 {
        panic!("Only Visual Studio {} and up is supported", 2017);
    }
    visual_studios.sort_unstable_by_key(|f| f.file_name());
    visual_studios.reverse();
    let mut command_files = Vec::new();
    for entry in visual_studios {
        let mut bat = fs::read_dir(entry.path()).expect("fail to read Visual Studio dir")
            .filter(|f| f.is_ok()).map(|f| f.unwrap())
            .filter(|f| f.file_type().is_ok() && f.file_type().unwrap().is_dir())
            .filter(|f| {
                if let Ok(name) = f.file_name().into_string() {
                    return ["Community", "Professional", "Enterprise"].contains(&name.as_str());
                }
                false
            }).map(|f| {
                let mut p = f.path();
                p.push("VC");
                p.push("Auxiliary");
                p.push("Build");
                p.push("vcvars64.bat");
                p
            }).collect();
        command_files.append(&mut bat);
    }
    for command_file in command_files.iter().filter(|p| p.exists()) {
        if let Ok(output) = Command::new("cmd").arg("/c").arg(command_file).output() {
            if let Ok(out) = String::from_utf8(output.stdout) {
                if out.contains("[vcvarsall.bat] Environment initialized for: 'x64'") {
                    Command::new("cmd")
                        .arg("/c").arg(command_file)
                        .args(&["&&","cmake","--build",".","--config","Release","--target","install"])
                        .output()
                        .expect("failed to run cmake");
                    return;
                }
            }
        }
    }
    panic!("No vcvars64.bat file found");
}

#[cfg(unix)]
fn make_install(configure: PathBuf) {
    let output = Command::new("tclsh")
        .arg(configure)
        .arg("--enable-apps=OFF")
        .arg("--prefix=.")
        .output()
        .expect("failed to run configure in tclsh");
    if !String::from_utf8(output.stdout).expect("malformed configure output")
        .contains("Build files have been written to") {
        panic!("failed to generate build files");
    }
    Command::new("sh")
        .arg("-c")
        .arg("make install")
        .output()
        .expect("failed to run cmake");
}