use std::process::Command;
use std::{env, fs};
use std::io::prelude::*;
use std::io::BufReader;
use std::path::{Path, PathBuf};
const GMP_NAME: &'static str = "libgmp";
const GMP_VERSION: &'static str = "6.0.0";
#[cfg(unix)]
fn check_library(name: &str) -> bool {
if let Ok(po) = Command::new("ldconfig").arg("-p").output() {
let target = env::var("TARGET").unwrap();
let is_64bit = target.contains("x86_64");
let pattern = format!("{}.so (libc6{})", name, if is_64bit { ",x86-64" } else { "" });
if !po.stdout.is_empty() {
let br = BufReader::new(&*po.stdout);
return br.lines().map(|l| l.unwrap())
.any(|l| l.contains(&*pattern))
}
}
for &dir in &["/lib", "/usr/lib", "/usr/local/lib"] {
let p = Path::new(dir).join(format!("{}.so", name));
if p.exists() { return true; }
}
false
}
#[cfg(windows)]
fn check_library(name: &str) -> bool {
false
}
fn main() {
if check_library(GMP_NAME) {
println!("cargo:rustc-link-lib=gmp");
return;
}
let project_src_root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let gmp_src_root = project_src_root.join::<String>([GMP_NAME, "-", GMP_VERSION].concat());
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let gmp_build_dir = out_dir.join("build");
let gmp_out_dir = out_dir.join("out");
let gmp_out_lib_dir = gmp_out_dir.join("lib");
let gmp_out_include_dir = gmp_out_dir.join("include");
if !(gmp_out_lib_dir.exists() && gmp_out_lib_dir.join("libgmp.a").exists() &&
gmp_out_include_dir.exists() && gmp_out_include_dir.join("gmp.h").exists()) {
run_build(&gmp_src_root, &gmp_build_dir,
&gmp_out_dir, &gmp_out_lib_dir, &gmp_out_include_dir);
}
emit_cargo_config(&gmp_out_lib_dir, &gmp_out_include_dir);
}
fn run_build(gmp_src_root: &Path,
gmp_build_dir: &Path,
gmp_out_dir: &Path,
gmp_out_lib_dir: &Path,
gmp_out_include_dir: &Path) {
let target = env::var("TARGET").unwrap();
let mut cflags = env::var("CFLAGS").unwrap_or_else(|_| String::new());
cflags.push_str(" -ffunction-sections -fdata-sections");
if target.contains("i686") {
cflags.push_str(" -m32");
} else if target.contains("x86_64") {
cflags.push_str(" -m64");
}
if !target.contains("i686") {
cflags.push_str(" -fPIC");
}
let _ = fs::remove_dir_all(gmp_build_dir);
let _ = fs::remove_dir_all(gmp_out_dir);
let _ = fs::create_dir_all(gmp_out_lib_dir);
let _ = fs::create_dir_all(gmp_out_include_dir);
fs::create_dir(gmp_build_dir).unwrap();
let config_opts = vec![
"--enable-shared=no".to_string() ];
run(Command::new("sh")
.env("CFLAGS", cflags)
.current_dir(gmp_build_dir)
.arg("-c")
.arg(format!(
"{} {}",
gmp_src_root.join("configure").display(),
config_opts.join(" ")
).replace("C:\\", "/c/").replace("\\", "/")));
run(Command::new(make())
.arg(format!("-j{}", env::var("NUM_JOBS").unwrap()))
.current_dir(gmp_build_dir));
let p1 = gmp_build_dir.join(".libs/libgmp.a");
let p2 = gmp_build_dir.join(".libs/libgmp.lib");
if p1.exists() {
fs::rename(&p1, &gmp_out_lib_dir.join("libgmp.a")).unwrap();
} else {
fs::rename(&p2, &gmp_out_lib_dir.join("libgmp.a")).unwrap();
}
fs::copy(&gmp_build_dir.join("gmp.h"), &gmp_out_include_dir.join("gmp.h")).unwrap();
}
fn emit_cargo_config(lib_dir: &Path, include_dir: &Path) {
println!("cargo:rustc-flags=-L {} -l gmp:static", lib_dir.display());
println!("cargo:libdir={}", lib_dir.display());
println!("cargo:include={}", include_dir.display());
}
fn make() -> &'static str {
if cfg!(target_os = "freebsd") {"gmake"} else {"make"}
}
fn run(cmd: &mut Command) {
use std::process::Stdio;
println!("running: {:?}", cmd);
assert!(cmd.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.status()
.unwrap()
.success());
}