#[cfg(feature = "serde")]
use bindgen;
use fs_utils::copy::copy_directory;
use glob::glob;
use std::env;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
const FILES: &[&str] = &[
"kfunc.c",
"kstring.c",
"bcf_sr_sort.c",
"bgzf.c",
"errmod.c",
"faidx.c",
"header.c",
"hfile.c",
"hts.c",
"hts_expr.c",
"hts_os.c",
"md5.c",
"multipart.c",
"probaln.c",
"realn.c",
"regidx.c",
"region.c",
"sam.c",
"sam_mods.c",
"synced_bcf_reader.c",
"vcf_sweep.c",
"tbx.c",
"textutils.c",
"thread_pool.c",
"vcf.c",
"vcfutils.c",
"cram/cram_codecs.c",
"cram/cram_decode.c",
"cram/cram_encode.c",
"cram/cram_external.c",
"cram/cram_index.c",
"cram/cram_io.c",
"cram/cram_stats.c",
"cram/mFILE.c",
"cram/open_trace_file.c",
"cram/pooled_alloc.c",
"cram/string_alloc.c",
"htscodecs/htscodecs/arith_dynamic.c",
"htscodecs/htscodecs/fqzcomp_qual.c",
"htscodecs/htscodecs/htscodecs.c",
"htscodecs/htscodecs/pack.c",
"htscodecs/htscodecs/rANS_static4x16pr.c",
"htscodecs/htscodecs/rANS_static32x16pr_avx2.c",
"htscodecs/htscodecs/rANS_static32x16pr_avx512.c",
"htscodecs/htscodecs/rANS_static32x16pr_sse4.c",
"htscodecs/htscodecs/rANS_static32x16pr_neon.c",
"htscodecs/htscodecs/rANS_static32x16pr.c",
"htscodecs/htscodecs/rANS_static.c",
"htscodecs/htscodecs/rle.c",
"htscodecs/htscodecs/tokenise_name3.c",
"htscodecs/htscodecs/utils.c",
];
fn main() {
let out = PathBuf::from(env::var("OUT_DIR").unwrap());
let htslib_copy = out.join("htslib");
if htslib_copy.exists() {
std::fs::remove_dir_all(htslib_copy).unwrap();
}
copy_directory("htslib", &out).unwrap();
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
let mut cfg = cc::Build::new();
let mut lib_list = "".to_string();
let out_htslib = out.join("htslib");
let htslib = PathBuf::from("htslib");
for f in FILES {
let c_file = out_htslib.join(f);
cfg.file(&c_file);
println!("cargo:rerun-if-changed={}", htslib.join(f).display());
}
cfg.include(out.join("htslib"));
let want_static = cfg!(feature = "static") || env::var("HTS_STATIC").is_ok();
if want_static {
cfg.warnings(false).static_flag(true).pic(true);
} else {
cfg.warnings(false).static_flag(false).pic(true);
}
if let Ok(z_inc) = env::var("DEP_Z_INCLUDE") {
cfg.include(z_inc);
lib_list += " -lz";
}
let mut config_lines = vec![
"/* Default config.h generated by build.rs */",
"#define HAVE_DRAND48 1",
];
let use_bzip2 = env::var("CARGO_FEATURE_BZIP2").is_ok();
if use_bzip2 {
if let Ok(inc) = env::var("DEP_BZIP2_ROOT")
.map(PathBuf::from)
.map(|path| path.join("include"))
{
cfg.include(inc);
lib_list += " -lbz2";
config_lines.push("#define HAVE_LIBBZ2 1");
}
}
let use_libdeflate = env::var("CARGO_FEATURE_LIBDEFLATE").is_ok();
if use_libdeflate {
if let Ok(inc) = env::var("DEP_LIBDEFLATE_INCLUDE").map(PathBuf::from) {
cfg.include(inc);
lib_list += " -ldeflate";
config_lines.push("#define HAVE_LIBDEFLATE 1");
} else {
panic!("no DEP_LIBDEFLATE_INCLUDE");
}
}
let use_lzma = env::var("CARGO_FEATURE_LZMA").is_ok();
if use_lzma {
if let Ok(inc) = env::var("DEP_LZMA_INCLUDE").map(PathBuf::from) {
cfg.include(inc);
lib_list += " -llzma";
config_lines.push("#define HAVE_LIBBZ2 1");
config_lines.push("#ifndef __APPLE__");
config_lines.push("#define HAVE_LZMA_H 1");
config_lines.push("#endif");
}
}
let use_curl = env::var("CARGO_FEATURE_CURL").is_ok();
if use_curl {
if let Ok(inc) = env::var("DEP_CURL_INCLUDE").map(PathBuf::from) {
cfg.include(inc);
lib_list += " -lcurl";
config_lines.push("#define HAVE_LIBCURL 1");
cfg.file("htslib/hfile_libcurl.c");
println!("cargo:rerun-if-changed=htslib/hfile_libcurl.c");
if target_os == "macos" {
config_lines.push("#define HAVE_COMMONCRYPTO 1");
} else if let Ok(inc) = env::var("DEP_OPENSSL_INCLUDE").map(PathBuf::from) {
cfg.include(inc);
config_lines.push("#define HAVE_HMAC 1");
} else {
panic!("No OpenSSL dependency -- need OpenSSL includes");
}
}
}
let use_gcs = env::var("CARGO_FEATURE_GCS").is_ok();
if use_gcs {
config_lines.push("#define ENABLE_GCS 1");
cfg.file("htslib/hfile_gcs.c");
println!("cargo:rerun-if-changed=htslib/hfile_gcs.c");
}
let use_s3 = env::var("CARGO_FEATURE_S3").is_ok();
if use_s3 {
config_lines.push("#define ENABLE_S3 1");
cfg.file("htslib/hfile_s3.c");
println!("cargo:rerun-if-changed=htslib/hfile_s3.c");
cfg.file("htslib/hfile_s3_write.c");
println!("cargo:rerun-if-changed=htslib/hfile_s3_write.c");
}
if let Ok(targets) = env::var("CARGO_CFG_TARGET_FEATURE") {
if targets.contains("avx2") {
cfg.flag("-mavx2");
config_lines.push("#define HAVE_AVX2 1");
}
if targets.contains("sse4.1") {
cfg.flag("-msse4.1");
config_lines.push("#define HAVE_SSE4_1 1");
}
if targets.contains("ssse3") {
cfg.flag("-mssse3");
config_lines.push("#define HAVE_SSSE3 1");
}
if targets.contains("popcnt") {
cfg.flag("-mpopcnt");
config_lines.push("#define HAVE_POPCNT 1");
}
if targets.contains("neon") {
config_lines.push("#define __ARM_NEON 1");
}
}
{
let mut f = std::fs::File::create(out.join("htslib").join("config.h")).unwrap();
for l in config_lines {
writeln!(&mut f, "{}", l).unwrap();
}
}
{
let version = std::process::Command::new(out.join("htslib").join("version.sh"))
.output()
.expect("failed to execute process");
let version_str = std::str::from_utf8(&version.stdout).unwrap().trim();
let mut f = std::fs::File::create(out.join("htslib").join("version.h")).unwrap();
writeln!(&mut f, "#define HTS_VERSION_TEXT \"{}\"", version_str).unwrap();
}
{
let mut f = std::fs::File::create(
out.join("htslib")
.join("htscodecs")
.join("htscodecs")
.join("version.h"),
)
.unwrap();
writeln!(&mut f, "#define HTSCODECS_VERSION_TEXT \"rust-htslib\"").unwrap();
}
{
let tool = cfg.get_compiler();
let mut f = std::fs::File::create(out.join("htslib").join("config_vars.h")).unwrap();
writeln!(&mut f, "#define HTS_CC {:?}", tool.cc_env()).unwrap();
writeln!(&mut f, "#define HTS_CPPFLAGS \"\"").unwrap();
writeln!(&mut f, "#define HTS_CFLAGS {:?}", tool.cflags_env()).unwrap();
writeln!(&mut f, "#define HTS_LDFLAGS \"\"").unwrap();
writeln!(&mut f, "#define HTS_LIBS \"{}\"", lib_list).unwrap();
}
cfg.file("wrapper.c");
cfg.compile("hts");
#[cfg(feature = "bindgen")]
{
bindgen::Builder::default()
.header("wrapper.h")
.generate_comments(false)
.blocklist_function("strtold")
.blocklist_type("max_align_t")
.generate()
.expect("Unable to generate bindings.")
.write_to_file(out.join("bindings.rs"))
.expect("Could not write bindings.");
}
#[cfg(not(feature = "bindgen"))]
if target_os == "macos" {
fs::copy("osx_prebuilt_bindings.rs", out.join("bindings.rs"))
.expect("couldn't copy prebuilt bindings");
println!("cargo:rerun-if-changed=osx_prebuilt_bindings.rs");
} else {
fs::copy("linux_prebuilt_bindings.rs", out.join("bindings.rs"))
.expect("couldn't copy prebuilt bindings");
println!("cargo:rerun-if-changed=linux_prebuilt_bindings.rs");
}
let include = out.join("include");
fs::create_dir_all(&include).unwrap();
if include.join("htslib").exists() {
fs::remove_dir_all(include.join("htslib")).expect("remove exist include dir");
}
copy_directory(out.join("htslib").join("htslib"), &include).unwrap();
println!("cargo:root={}", out.display());
println!("cargo:include={}", include.display());
println!("cargo:libdir={}", out.display());
println!("cargo:rerun-if-changed=wrapper.c");
println!("cargo:rerun-if-changed=wrapper.h");
let globs = std::iter::empty()
.chain(glob("htslib/*.[h]").unwrap())
.chain(glob("htslib/cram/*.[h]").unwrap())
.chain(glob("htslib/htslib/*.h").unwrap())
.chain(glob("htslib/os/*.[h]").unwrap())
.filter_map(Result::ok);
for htsfile in globs {
println!("cargo:rerun-if-changed={}", htsfile.display());
}
}