use cmake;
use cmake::Config;
use curl::easy::Easy;
use flate2::read::GzDecoder;
use lazy_static::lazy_static;
use log::*;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::{Path, PathBuf};
use std::{env, fs};
use tar::Archive;
const VERSION: &str = "v3.0.0-alpha.2";
lazy_static! {
static ref SOURCE_URL: String = format!(
"https://github.com/GMLC-TDC/HELICS/releases/download/{ver}/Helics-{ver}-source.tar.gz",
ver = VERSION,
);
}
#[derive(Clone, Debug, PartialEq)]
enum Error {
DownloadFailure { response_code: u32, url: String },
UrlFailure,
IOError,
}
impl From<std::io::Error> for Error {
fn from(_: std::io::Error) -> Error {
Error::IOError
}
}
impl From<curl::Error> for Error {
fn from(_: curl::Error) -> Error {
Error::UrlFailure
}
}
fn download_and_install() -> Result<(), Error> {
let crate_dir = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap());
let target_dir = crate_dir.join("target");
debug!("target_dir = {:?}", &target_dir);
if !target_dir.exists() {
fs::create_dir(&target_dir).unwrap();
}
let download_dir = target_dir.join(format!("helics-{}-source", VERSION));
debug!("download_dir = {:?}", &download_dir);
if !download_dir.exists() {
fs::create_dir(&download_dir).unwrap();
}
let tarball_path = download_dir.join("helics.tar.gz");
debug!("tarball_path = {:?}", &tarball_path);
let binary_url = &SOURCE_URL;
download_tarball(&tarball_path, &binary_url)?;
extract_tarball(tarball_path, &download_dir);
let debug: bool = env::var("DEBUG").unwrap().parse().unwrap();
debug!("debug build? {}", debug);
let mut config = Config::new(download_dir);
if let Ok(s) = env::var("HELICS_CMAKE_GENERATOR") {
config.generator(s);
}
let build = config.build();
let out_dir = env::var("OUT_DIR").unwrap();
println!("cargo:rustc-link-search=native={}/lib", build.display());
if cfg!(debug_assertions) {
println!("cargo:rustc-link-lib=dylib=helicsd");
} else {
println!("cargo:rustc-link-lib=dylib=helics");
};
println!("cargo:include={}/include", build.display());
println!("cargo:include={}/include/helics", build.display());
println!(
"cargo:include={}/include/helics/shared_api_library",
build.display()
);
println!("cargo:outdir={}", out_dir);
dbg!(build.display());
let bindings = bindgen::Builder::default()
.clang_arg(format!("-I{}/include/", build.display()))
.clang_arg(format!("-I{}/include/helics/", build.display()))
.clang_arg(format!(
"-I{}/include/helics/shared_api_library/",
build.display()
))
.rustified_enum("*")
.header(format!(
"{}/include/helics/shared_api_library/helics.h",
build.display()
))
.generate()
.expect("Unable to generate bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings");
Ok(())
}
fn download_tarball(tarball_path: &Path, binary_url: &str) -> Result<(), Error> {
if !tarball_path.exists() {
info!("Tarball doesn't exist, downloading...");
let f = File::create(tarball_path).unwrap();
let mut writer = BufWriter::new(f);
let mut easy = Easy::new();
easy.follow_location(true)?;
easy.url(binary_url).unwrap();
easy.write_function(move |data| Ok(writer.write(data).unwrap()))
.unwrap();
easy.perform().unwrap();
let response_code = easy.response_code().unwrap();
if response_code != 200 {
return Err(Error::DownloadFailure {
response_code,
url: binary_url.to_string(),
});
} else {
info!("Download successful!");
}
}
Ok(())
}
fn extract_tarball<P: AsRef<Path> + std::fmt::Debug, P2: AsRef<Path> + std::fmt::Debug>(
archive_path: P,
extract_to: P2,
) {
info!(
"Extracting tarball {:?} to {:?}",
&archive_path, &extract_to
);
let file = File::open(archive_path).unwrap();
let mut a = Archive::new(GzDecoder::new(file));
a.unpack(extract_to).unwrap();
}
fn main() {
println!("cargo:rerun-if-changed=build.rs");
download_and_install().unwrap();
}