use once_cell::sync::Lazy;
use parking_lot::Mutex;
use std::collections::HashMap;
use std::{
env, io,
path::{Path, PathBuf},
process::Command,
};
pub fn get_apple_sdk_root(sdk_name: &str) -> Result<PathBuf, String> {
static SDK_PATH: Lazy<Mutex<HashMap<String, PathBuf>>> = Lazy::new(Default::default);
let mut lock = SDK_PATH.lock();
if let Some(path) = lock.get(sdk_name) {
return Ok(path.clone());
}
match find_apple_sdk_root(sdk_name) {
Ok(sdk_root) => Ok(lock.entry(sdk_name.into()).or_insert(sdk_root).clone()),
Err(e) => Err(e),
}
}
fn find_apple_sdk_root(sdk_name: &str) -> Result<PathBuf, String> {
if let Ok(sdkroot) = env::var("SDKROOT") {
let p = PathBuf::from(&sdkroot);
match sdk_name {
"appletvos"
if sdkroot.contains("TVSimulator.platform")
|| sdkroot.contains("MacOSX.platform") => {}
"appletvsimulator"
if sdkroot.contains("TVOS.platform") || sdkroot.contains("MacOSX.platform") => {}
"iphoneos"
if sdkroot.contains("iPhoneSimulator.platform")
|| sdkroot.contains("MacOSX.platform") => {}
"iphonesimulator"
if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("MacOSX.platform") => {
}
"macosx10.15"
if sdkroot.contains("iPhoneOS.platform")
|| sdkroot.contains("iPhoneSimulator.platform") => {}
"watchos"
if sdkroot.contains("WatchSimulator.platform")
|| sdkroot.contains("MacOSX.platform") => {}
"watchsimulator"
if sdkroot.contains("WatchOS.platform") || sdkroot.contains("MacOSX.platform") => {}
_ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {}
_ => return Ok(p),
}
}
let res = Command::new("xcrun")
.arg("--show-sdk-path")
.arg("-sdk")
.arg(sdk_name)
.output()
.and_then(|output| {
if output.status.success() {
Ok(String::from_utf8(output.stdout).unwrap())
} else {
let error = String::from_utf8(output.stderr);
let error = format!("process exit with error: {}", error.unwrap());
Err(io::Error::new(io::ErrorKind::Other, &error[..]))
}
});
match res {
Ok(output) => Ok(PathBuf::from(output.trim())),
Err(e) => Err(format!("failed to get SDK path: {}", e)),
}
}