libunwind-sys 0.5.1

Low-level bindings for the libunwind library
Documentation
extern crate bindgen;
extern crate fs_extra;
extern crate autotools;

use autotools::Config;
use std::env;
use std::path::PathBuf;
use std::process::Command;

fn main() {
    let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
    let mut libunwind_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    libunwind_path.push("libunwind");
    let project_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let _e = fs_extra::dir::create(libunwind_path.clone(),true);
    let options = fs_extra::dir::CopyOptions::new();
    fs_extra::dir::copy(project_dir.join("libunwind"), out_dir.clone(), &options).unwrap();

    let target = env::var("TARGET").unwrap();
    let host  = env::var("HOST").unwrap();

    // Choose build.
    let link_lib_arch = match target.as_str() {
        "x86_64-unknown-linux-gnu"| "x86_64-unknown-linux-musl" => "x86_64",
        "i686-unknown-linux-gnu"|"i586-unknown-linux-gnu"  => "x86",
        "arm-unknown-linux-gnueabihf" => "arm",
        _ => ""
    };
    if link_lib_arch.is_empty() {
        println!("cargo:warning=target {} is unsupported",target);
        return;
    }

    // Build native C library only for x86 and arm targets on x86_64 host.
    if link_lib_arch == "x86" || link_lib_arch == "arm " {

        // Build libunwind.
        let _autogen = Command::new("sh").current_dir(&libunwind_path)
                                     .arg("-c")
                                     .arg(format!("autoreconf --force --install --verbose {}",&libunwind_path.to_str().unwrap()))
                                     .output()
                                     .expect("failed to run autoreconf, do you have the autotools installed?");

        // Configure. Check if we compile for  x86 target on x86_64 host.
        let mut dst = Config::new(&libunwind_path);
        if !env::var_os("CARGO_FEATURE_PTRACE").is_some() {
            dst.disable("ptrace", None);
        } else {
            println!("cargo:warning=ptrace-on");
            dst.enable("ptrace", None);
        }

        if link_lib_arch == "x86" && host.contains("x86_64") {
            dst.cflag("-m32")
            .target(&target)
            .host(&target)
            .disable("documentation", None)
            .disable("tests", None)
            .enable_shared();

        // Configure. Check if we compile for  arm target on x86_64 host
        } else  if link_lib_arch == "arm" && host.contains("x86_64") {

            dst.env("CC","arm-linux-gnueabihf-gcc")
            .target(&target)
            .host(&target)
            .disable("documentation", None)
            .disable("tests", None)
            .enable_shared();
        }
        else {
        dst.disable("documentation", None).disable("tests", None).enable_shared().enable_static();
        }
        let dst = dst.build();
        println!("cargo:rustc-link-search={}/lib", dst.display());
    }

    if target.contains("musl") {
        println!("cargo:rustc-link-search=/usr/lib/x86_64-linux-gnu");
        println!("cargo:rustc-link-lib=static=lzma");
        println!("cargo:rustc-link-lib=static=unwind-{}",link_lib_arch);
        println!("cargo:rustc-link-lib=static=unwind");
        println!("cargo:rustc-link-lib=static=unwind-coredump");

        if env::var_os("CARGO_FEATURE_PTRACE").is_some() {
            println!("cargo:rustc-link-lib=static=unwind-ptrace");
        }
    } else {
        println!("cargo:rustc-link-lib=unwind-{}",link_lib_arch);
        println!("cargo:rustc-link-lib=unwind");
        println!("cargo:rustc-link-lib=unwind-coredump");

        if env::var_os("CARGO_FEATURE_PTRACE").is_some() {
            println!("cargo:rustc-link-lib=unwind-ptrace");
        }
    }

    // Choose header.
    let wrapper =  if link_lib_arch == "arm" && host.contains("x86_64") {
        "wrapper-arm.h"
    } else {
        "wrapper.h"
    };
    let bindings = match link_lib_arch {
        "x86" => {
            bindgen::Builder::default()
                .header(project_dir.join(wrapper).to_str().unwrap())
                .clang_arg("-Ilibunwind/include")
                .blacklist_function("_Ux86_.*")
        },
        "arm" => {
            bindgen::Builder::default()
                .header(project_dir.join(wrapper).to_str().unwrap())
                .clang_arg("-Ilibunwind/include")
                .blacklist_function("_Uarm_.*")
        },
        _=> {
            bindgen::Builder::default()
                .header(project_dir.join(wrapper).to_str().unwrap())
                .clang_arg("-Ilibunwind/include")
                .blacklist_function("_Ux86_64_.*")
        }
    };

    let bindings = if !env::var_os("CARGO_FEATURE_PTRACE").is_some() {
                bindings.blacklist_function("_UPT_.*").blacklist_item("_UPT_.*")
    } else {
                bindings
    };
    let bindings = bindings.generate().expect("Unable to generate bindings");
    bindings
        .write_to_file(out_dir.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}