use build_rs::input::{ profile, out_dir };
use build_rs::output::{
rerun_if_changed,
rustc_link_lib_kind,
rustc_link_search_kind
};
use semver::{ Version, VersionReq };
use std::process::Command;
fn main() {
let version_req = "0.17.0";
let version_req = VersionReq::parse(version_req).unwrap();
if cfg!(docsrs) { return }
let out_dir = out_dir().into_os_string().into_string().unwrap();
let mut out_dir_cache = out_dir.clone();
out_dir_cache.push_str("/cache");
rerun_if_changed("src");
let version = Command::new("zig")
.arg("version")
.output()
.unwrap_or_else(|err| panic!("error fetching version of zig: {err}"));
let version = String::from_utf8(version.stdout).unwrap();
let version = Version::parse(version.trim_ascii()).unwrap();
assert!(version_req.matches(&version), "{version} doesn't satisfy {version_req}");
let status = Command::new("zig")
.arg("build")
.arg("lib")
.arg("install")
.arg(get_opt_level_arg())
.arg("--cache-dir")
.arg(&*out_dir_cache)
.arg("--prefix")
.arg(&*out_dir)
.status()
.unwrap_or_else(|err| panic!("failed to build zig: {err:?}"));
if !status.success() {
panic!("failed to build zig: zig exited with {status}");
};
rustc_link_search_kind("native", &*format!("{out_dir}/lib"));
rustc_link_lib_kind("static:+whole-archive", "zig-std-rs");
}
fn get_opt_level_arg() -> &'static str {
let debug = "-Doptimize=debug";
let fast = "-Doptimize=fast";
let safe = "-Doptimize=safe";
let small = "-Doptimize=small";
macro_rules! declare_features {
{
$($feature:ident $feature_str:literal $zig_str:ident)*
} => {
$(
let $feature = (cfg!(feature = $feature_str), $zig_str);
)*
}
}
declare_features! {
o_debug "o-debug" debug
o_fast "o-fast" fast
o_safe "o-safe" safe
o_small "o-small" small
o_debug_debug "o-debug-debug" debug
o_debug_fast "o-debug-fast" fast
o_debug_safe "o-debug-safe" safe
o_debug_small "o-debug-small" small
o_release_debug "o-release-debug" debug
o_release_fast "o-release-fast" fast
o_release_safe "o-release-safe" safe
o_release_small "o-release-small" small
}
fn count(array: [(bool, &'static str); 4]) -> usize {
array
.into_iter()
.filter(|(b, _)| *b)
.count()
}
fn find(array: [(bool, &'static str); 4]) -> &'static str {
let (_, s) = array
.into_iter()
.find(|(b, _)| *b)
.unwrap();
s
}
let opt = [o_debug, o_fast, o_safe, o_small];
let debug_opt = [o_debug_debug, o_debug_fast, o_debug_safe, o_debug_small];
let release_opt = [o_release_debug, o_release_fast, o_release_safe, o_release_small];
let opt_count = count(opt);
let debug_opt_count = count(debug_opt);
let release_opt_count = count(release_opt);
if opt_count == 1 && debug_opt_count == 0 && release_opt_count == 0 {
return find(opt);
}
let profile = profile();
macro_rules! profile_debug { () => ("debug") }
macro_rules! profile_release { () => ("release") }
if opt_count == 0 && debug_opt_count <= 1 && release_opt_count <= 1 {
match &*profile {
profile_debug!() if debug_opt_count == 1 => { return find(debug_opt) }
profile_debug!() if debug_opt_count == 0 => { return debug }
profile_release!() if release_opt_count == 1 => { return find(release_opt) }
profile_release!() if release_opt_count == 0 => { return fast }
_ => {}
}
}
panic!("invalid combination of optimisation features enabled")
}