use std::env;
type Version = Option<String>;
#[allow(clippy::upper_case_acronyms)]
enum AppleRuntime {
MacOS(Version),
IOS(Version),
TvOS(Version),
WatchOS(Version),
}
use AppleRuntime::*;
enum Runtime {
Apple(AppleRuntime),
GNUStep(u8, u8),
WinObjC,
#[allow(dead_code)]
ObjFW(Option<String>),
}
use Runtime::*;
fn get_env(env: &str) -> Option<String> {
println!("cargo:rerun-if-env-changed={}", env);
match env::var(env) {
Ok(var) => Some(var),
Err(env::VarError::NotPresent) => None,
Err(env::VarError::NotUnicode(var)) => panic!("Invalid unicode for {}: {:?}", env, var),
}
}
fn main() {
println!("cargo:rerun-if-changed=build.rs");
if env::var("TARGET").unwrap().ends_with("macabi") {
println!("cargo:rustc-cfg=target_abi_macabi");
}
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
let mut apple = env::var_os("CARGO_FEATURE_APPLE").is_some();
let gnustep = env::var_os("CARGO_FEATURE_GNUSTEP_1_7").is_some();
let objfw = env::var_os("CARGO_FEATURE_OBJFW").is_some();
if let (false, false, false) = (apple, gnustep, objfw) {
if let "macos" | "ios" | "tvos" | "watchos" = &*target_os {
apple = true;
println!("cargo:rustc-cfg=feature=\"apple\"");
}
}
let runtime = match (apple, gnustep, objfw) {
(true, false, false) => {
Apple(match &*target_os {
"macos" => MacOS(Some(
get_env("MACOSX_DEPLOYMENT_TARGET").unwrap_or_else(|| "10.7".into()),
)),
"ios" => IOS(Some(
get_env("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or_else(|| "7.0".into()),
)),
"tvos" => TvOS(get_env("TVOS_DEPLOYMENT_TARGET")),
"watchos" => WatchOS(get_env("WATCHOS_DEPLOYMENT_TARGET")),
_ => MacOS(None),
})
}
(false, true, false) => {
if env::var_os("CARGO_FEATURE_WINOBJC").is_some() {
WinObjC
} else if env::var_os("CARGO_FEATURE_GNUSTEP_2_1").is_some() {
GNUStep(2, 1)
} else if env::var_os("CARGO_FEATURE_GNUSTEP_2_0").is_some() {
GNUStep(2, 0)
} else if env::var_os("CARGO_FEATURE_GNUSTEP_1_9").is_some() {
GNUStep(1, 9)
} else if env::var_os("CARGO_FEATURE_GNUSTEP_1_8").is_some() {
GNUStep(1, 8)
} else {
GNUStep(1, 7)
}
}
(false, false, true) => {
unimplemented!()
}
(false, false, false) => {
if std::env::var("DOCS_RS").is_ok() {
if target_os == "windows" {
WinObjC
} else {
GNUStep(1, 7)
}
} else {
panic!("Must specify the desired runtime (using features) on non-apple platforms.")
}
}
_ => {
panic!("Invalid feature combination; only one runtime may be selected!")
}
};
let runtime_cfg = match runtime {
Apple(_) => "apple",
GNUStep(_, _) | WinObjC => "gnustep",
ObjFW(_) => "objfw",
};
println!("cargo:rustc-cfg={}", runtime_cfg);
println!("cargo:runtime={}", runtime_cfg);
let clang_runtime = match &runtime {
Apple(runtime) => {
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
let clang_runtime_str = match (runtime, &*target_arch) {
(MacOS(_), "x86") => "macosx-fragile",
(MacOS(_), _) => "macosx",
(IOS(_), _) => "ios",
(WatchOS(_), _) => "watchos",
(TvOS(_), _) => "ios",
};
match runtime {
MacOS(version) | IOS(version) | WatchOS(version) | TvOS(version) => {
if let Some(version) = version {
format!("{}-{}", clang_runtime_str, version)
} else {
clang_runtime_str.into()
}
}
}
}
GNUStep(major, minor) => format!("gnustep-{}.{}", major, minor),
WinObjC => "gnustep-1.8".into(),
ObjFW(version) => {
let _version = version.as_deref().unwrap_or("0.8");
todo!()
}
};
println!(
"cargo:cc_args=-fobjc-arc -fobjc-arc-exceptions -fobjc-exceptions -fobjc-runtime={}",
clang_runtime
);
println!("cargo:rustc-link-lib=dylib=objc");
}