use std::env;
use std::path::Path;
use lazy_static::lazy_static;
use raw_cpuid::CpuId;
lazy_static! {
static ref CPUID: CpuId = CpuId::new();
}
fn has_aesni() -> bool {
cfg!(feature = "native")
&& CPUID
.get_feature_info()
.map_or(false, |features| features.has_aesni())
}
fn has_sse41() -> bool {
cfg!(feature = "native")
&& CPUID
.get_feature_info()
.map_or(false, |features| features.has_sse41())
}
fn has_sse42() -> bool {
cfg!(feature = "native")
&& CPUID
.get_feature_info()
.map_or(false, |features| features.has_sse42())
}
fn has_avx() -> bool {
cfg!(feature = "native")
&& CPUID
.get_feature_info()
.map_or(false, |features| features.has_avx())
}
fn has_avx2() -> bool {
cfg!(feature = "native")
&& CPUID
.get_extended_feature_info()
.map_or(false, |features| features.has_avx2())
}
fn support_aesni() -> bool {
cfg!(any(feature = "aes", target_feature = "aes")) || has_aesni()
}
fn support_sse41() -> bool {
cfg!(any(feature = "sse41", target_feature = "sse41")) || has_sse41()
}
fn support_sse42() -> bool {
cfg!(any(feature = "sse42", target_feature = "sse42")) || has_sse42()
}
fn support_avx() -> bool {
cfg!(any(feature = "avx", target_feature = "avx")) || has_avx()
}
fn support_avx2() -> bool {
cfg!(any(feature = "avx2", target_feature = "avx2")) || has_avx2()
}
#[cfg(feature = "gen")]
fn generate_binding(out_file: &Path) {
println!("generate binding file @ {:?}.", out_file);
let _ = bindgen::builder()
.clang_args(&["-x", "c++", "-std=c++11"])
.clang_args(&[
"-Dt1ha_EXPORTS",
"-DXXH_STATIC_LINKING_ONLY",
"-Isrc/highwayhash",
])
.clang_args(if support_aesni() {
&[
"-maes",
"-DT1HA0_RUNTIME_SELECT=1",
"-DT1HA0_AESNI_AVAILABLE=1",
][..]
} else {
&[][..]
})
.clang_args(
vec![
if cfg!(feature = "native") {
Some("-march=native")
} else {
None
},
if support_sse42() {
Some("-msse4.2")
} else {
None
},
if support_avx() { Some("-mavx") } else { None },
if support_avx2() { Some("-mavx2") } else { None },
if cfg!(feature = "city") {
Some("-DCITY_HASH=1")
} else {
None
},
if cfg!(feature = "farm") {
Some("-DFARM_HASH=1")
} else {
None
},
if cfg!(feature = "highway") {
Some("-DHIGHWAY_HASH=1")
} else {
None
},
if cfg!(feature = "lookup3") {
Some("-DLOOKUP3=1")
} else {
None
},
if cfg!(feature = "meow") {
Some("-DMEOW_HASH=1")
} else {
None
},
if cfg!(feature = "metro") {
Some("-DMETRO_HASH=1")
} else {
None
},
if cfg!(feature = "mum") {
Some("-DMUM_HASH=1")
} else {
None
},
if cfg!(feature = "murmur") {
Some("-DMURMUR_HASH=1")
} else {
None
},
if cfg!(feature = "spooky") {
Some("-DSPOOKY_HASH=1")
} else {
None
},
if cfg!(feature = "t1ha") {
Some("-DT1_HASH=1")
} else {
None
},
if cfg!(feature = "wy") {
Some("-DWY_HASH=1")
} else {
None
},
if cfg!(feature = "xx") {
Some("-DXX_HASH=1")
} else {
None
},
]
.into_iter()
.flatten(),
)
.header("src/fasthash.hpp")
.size_t_is_usize(true)
.generate_inline_functions(true)
.disable_name_namespacing()
.allowlist_function("^CityHash.*")
.allowlist_function("^farmhash.*")
.allowlist_function("^lookup3.*")
.allowlist_function("^metrohash.*")
.allowlist_function("^mum_hash.*")
.allowlist_function("^MurmurHash.*")
.allowlist_function("^SpookyHasher.*")
.allowlist_function("^t1ha.*")
.blocklist_function("^t1ha_selfcheck__.*")
.allowlist_function("^XXH.*")
.allowlist_function("^HighwayHash.*")
.allowlist_function("^wyhash.*")
.allowlist_var("^Meow.*")
.allowlist_function("^Meow.*")
.generate()
.unwrap()
.write_to_file(out_file)
.expect("fail to write bindings");
}
#[cfg(not(feature = "gen"))]
fn generate_binding(_out_file: &Path) {
println!("direct include pregenerated binding file.");
}
fn build_fasthash() {
let mut build = cc::Build::new();
build
.cpp(true)
.flag("-std=c++11")
.include("src/highwayhash")
.flag("-Wno-implicit-fallthrough")
.flag("-Wno-unknown-attributes")
.file("src/fasthash.cpp");
if cfg!(feature = "city") {
build.flag("-DCITY_HASH=1").file("src/smhasher/City.cpp");
}
if cfg!(feature = "farm") {
build
.flag("-DFARM_HASH=1")
.file("src/smhasher/farmhash-c.c");
}
if cfg!(feature = "highway") {
build.flag("-DHIGHWAY_HASH=1");
}
if cfg!(feature = "lookup3") {
build.flag("-DLOOKUP3=1").file("src/smhasher/lookup3.cpp");
}
if cfg!(feature = "meow") {
build.flag("-DMEOW_HASH=1");
}
if cfg!(feature = "t1ha") {
build.flag("-DT1_HASH=1");
}
if cfg!(feature = "metro") {
build
.flag("-DMETRO_HASH=1")
.file("src/smhasher/metrohash/metrohash64.cpp")
.file("src/smhasher/metrohash/metrohash128.cpp");
if support_sse42() {
build
.file("src/smhasher/metrohash/metrohash64crc.cpp")
.file("src/smhasher/metrohash/metrohash128crc.cpp");
}
}
if cfg!(feature = "mum") {
build.flag("-DMUM_HASH=1").file("src/smhasher/mum.cc");
}
if cfg!(feature = "murmur") {
build
.flag("-DMURMUR_HASH=1")
.file("src/smhasher/MurmurHash1.cpp")
.file("src/smhasher/MurmurHash2.cpp")
.file("src/smhasher/MurmurHash3.cpp");
}
if cfg!(feature = "spooky") {
build
.flag("-DSPOOKY_HASH=1")
.file("src/smhasher/Spooky.cpp");
}
if cfg!(feature = "wy") {
build.flag("-DWY_HASH=1");
}
if cfg!(feature = "xx") {
build.flag("-DXX_HASH=1").file("src/xxHash/xxhash.c");
}
if cfg!(feature = "native") {
build.flag("-march=native");
} else {
if cfg!(target_feature = "aes") {
build.flag("-maes");
}
if cfg!(target_feature = "sse41") {
build.flag("-msse41");
}
if cfg!(target_feature = "sse42") {
build.flag("-msse4.2");
}
if cfg!(target_feature = "avx") {
build.flag("-mavx");
}
if cfg!(target_feature = "avx2") {
build.flag("-mavx2");
}
}
build.static_flag(true).compile("fasthash");
}
fn build_t1() {
let mut build = cc::Build::new();
build
.file("src/t1ha/src/t1ha0.c")
.file("src/t1ha/src/t1ha1.c")
.file("src/t1ha/src/t1ha2.c");
#[cfg(target_env = "musl")]
build.define("T1HA_USE_INDIRECT_FUNCTIONS", Some("0"));
if support_aesni() {
build
.define("T1HA0_RUNTIME_SELECT", Some("1"))
.define("T1HA0_AESNI_AVAILABLE", Some("1"))
.flag("-maes")
.file("src/t1ha/src/t1ha0_ia32aes_noavx.c")
.file("src/t1ha/src/t1ha0_ia32aes_avx.c")
.file("src/t1ha/src/t1ha0_ia32aes_avx2.c");
if support_avx() {
build.flag("-mavx");
}
if support_avx2() {
build.flag("-mavx2");
}
}
build.static_flag(true).compile("t1ha");
}
fn build_highway() {
let mut build = cc::Build::new();
build
.cpp(true)
.flag("-std=c++11")
.include("src/highwayhash")
.file("src/highwayhash/highwayhash/arch_specific.cc")
.file("src/highwayhash/highwayhash/instruction_sets.cc")
.file("src/highwayhash/highwayhash/os_specific.cc")
.file("src/highwayhash/highwayhash/hh_portable.cc")
.file("src/highwayhash/highwayhash/c_bindings.cc");
if cfg!(any(target_arch = "x86", target_arch = "x86_64")) {
if support_sse41() {
build
.flag("-msse4.1")
.file("src/highwayhash/highwayhash/hh_sse41.cc");
}
if support_avx2() {
build
.flag("-mavx2")
.file("src/highwayhash/highwayhash/hh_avx2.cc");
}
} else if cfg!(target_arch = "aarch64") {
build.file("src/highwayhash/highwayhash/hh_neon.cc");
} else if cfg!(target_arch = "powerpc64") {
build.file("src/highwayhash/highwayhash/hh_vsx.cc");
}
build.static_flag(true).compile("highwayhash");
}
fn main() {
if has_aesni() {
println!(r#"cargo:rustc-cfg=feature="aes""#);
}
if has_sse41() {
println!(r#"cargo:rustc-cfg=feature="sse41""#);
}
if has_sse42() {
println!(r#"cargo:rustc-cfg=feature="sse42""#);
}
if has_avx() {
println!(r#"cargo:rustc-cfg=feature="avx""#);
}
if has_avx2() {
println!(r#"cargo:rustc-cfg=feature="avx2""#);
}
build_fasthash();
if cfg!(feature = "t1ha") {
build_t1();
}
if cfg!(feature = "highway") {
build_highway();
}
let out_dir = env::var("OUT_DIR").unwrap();
let out_file = Path::new(&out_dir).join("fasthash.rs");
println!("cargo:rerun-if-changed=src/fasthash.hpp");
println!("cargo:rerun-if-changed=src/fasthash.cpp");
generate_binding(&out_file);
}