use std::env;
use std::io;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use flate2::read::GzDecoder;
use std::fs::File;
use tar::Archive;
use bindgen::builder;
use lazy_static::lazy_static;
const LIBMARPA_VERSION: &str = "8.6.2";
lazy_static! {
static ref CRATE_ROOT: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into();
static ref OUT_DIR: PathBuf = env::var("OUT_DIR").unwrap().into();
}
fn main() {
let path = extract_libmarpa(LIBMARPA_VERSION).unwrap();
build_libmarpa(&path).unwrap();
run_bindgen(&path).unwrap();
}
// extract a tarball at `path` into `out_dir`
//
// borrowed from the rust cookbook: https://rust-lang-nursery.github.io/rust-cookbook/compression/tar.html
fn extract_tar_gz
(path: P, out_dir: Q) -> io::Result<()>
where
P: AsRef,
Q: AsRef,
{
let tar_gz = File::open(path)?;
let tar = GzDecoder::new(tar_gz);
let mut archive = Archive::new(tar);
Ok(archive.unpack(out_dir)?)
}
// extract a libmarpa tarball with the provided version. Returns the extracted
// libmarpa directory.
//
// Assumes that there's a libmarpa-VERSION.tar.gz in the crate root
fn extract_libmarpa(version: &'static str) -> io::Result {
let libmarpa_name: String = format!("libmarpa-{}", version);
let libmarpa_tarball = CRATE_ROOT.join(format!("{}.tar.gz", libmarpa_name));
println!("cargo:rerun-if-changed={}", libmarpa_tarball.display());
extract_tar_gz(libmarpa_tarball, &*OUT_DIR)?;
Ok(OUT_DIR.join(libmarpa_name))
}
// build the extracted libmarpa at the given path
fn build_libmarpa(path: P) -> io::Result<()>
where
P: AsRef,
{
let configure_status = Command::new(path.as_ref().join("configure"))
.current_dir(&path)
.env("CFLAGS", "-fPIC")
.status()?;
if !configure_status.success() {
return Err(io::Error::new(io::ErrorKind::Other, "configure failed"));
}
let make_status = Command::new("make").current_dir(&path).status()?;
if !make_status.success() {
return Err(io::Error::new(io::ErrorKind::Other, "make failed"));
}
println!("cargo:rustc-link-search=native={}/.libs", path.as_ref().display());
println!("cargo:rustc-link-lib=static=marpa");
Ok(())
}
// run bindgen on the extracted libmarpa at the given path
//
// assumes that there's a 'marpa.h' in the provided directory
fn run_bindgen(path: P) -> io::Result<()>
where
P: AsRef,
{
let bindings = builder()
.header(format!("{}", path.as_ref().join("marpa.h").display()))
.blacklist_type("max_align_t")
.generate()
.map_err(|_| io::Error::new(io::ErrorKind::Other, "failed to generate bindings"))?;
bindings.write_to_file(OUT_DIR.join("raw.rs"))
}