Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Apple WatchOS #662

Merged
merged 9 commits into from
Jul 6, 2022
84 changes: 66 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fmt::{self, Display};
use std::fmt::{self, Display, Formatter};
use std::fs;
use std::io::{self, BufRead, BufReader, Read, Write};
use std::path::{Component, Path, PathBuf};
Expand Down Expand Up @@ -168,7 +168,7 @@ impl From<io::Error> for Error {
}

impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}: {}", self.kind, self.message)
}
}
Expand Down Expand Up @@ -1522,7 +1522,7 @@ impl Build {
cmd.push_opt_unless_duplicate("-DANDROID".into());
}

if !target.contains("apple-ios") {
if !target.contains("apple-ios") && !target.contains("apple-watchos") {
cmd.push_cc_arg("-ffunction-sections".into());
cmd.push_cc_arg("-fdata-sections".into());
}
Expand Down Expand Up @@ -1590,6 +1590,20 @@ impl Build {
.into(),
);
}
} else if target.contains("watchos-sim") {
if let Some(arch) =
map_darwin_target_from_rust_to_compiler_architecture(target)
{
let deployment_target = env::var("WATCHOS_DEPLOYMENT_TARGET")
.unwrap_or_else(|_| "5.0".into());
cmd.args.push(
format!(
"--target={}-apple-watchos{}-simulator",
arch, deployment_target
)
.into(),
);
}
} else if target.starts_with("riscv64gc-") {
cmd.args.push(
format!("--target={}", target.replace("riscv64gc", "riscv64")).into(),
Expand Down Expand Up @@ -1849,8 +1863,8 @@ impl Build {
}
}

if target.contains("apple-ios") {
self.ios_flags(cmd)?;
if target.contains("apple-ios") || target.contains("apple-watchos") {
self.ios_watchos_flags(cmd)?;
}

if self.static_flag.unwrap_or(false) {
Expand Down Expand Up @@ -2043,18 +2057,37 @@ impl Build {
Ok(())
}

fn ios_flags(&self, cmd: &mut Tool) -> Result<(), Error> {
fn ios_watchos_flags(&self, cmd: &mut Tool) -> Result<(), Error> {
enum ArchSpec {
Device(&'static str),
Simulator(&'static str),
Catalyst(&'static str),
}

enum Os {
Ios,
WatchOs,
}
impl Display for Os {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Os::Ios => f.write_str("iOS"),
Os::WatchOs => f.write_str("WatchOS"),
}
}
}

let target = self.get_target()?;
let os = if target.contains("-watchos") {
Os::WatchOs
} else {
Os::Ios
};

let arch = target.split('-').nth(0).ok_or_else(|| {
Error::new(
ErrorKind::ArchitectureInvalid,
"Unknown architecture for iOS target.",
format!("Unknown architecture for {} target.", os).as_str(),
)
})?;

Expand Down Expand Up @@ -2083,6 +2116,7 @@ impl Build {
} else if is_sim {
match arch {
"arm64" | "aarch64" => ArchSpec::Simulator("-arch arm64"),
"x86_64" => ArchSpec::Simulator("-m64"),
_ => {
return Err(Error::new(
ErrorKind::ArchitectureInvalid,
Expand All @@ -2093,42 +2127,54 @@ impl Build {
} else {
match arch {
"arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"),
"armv7k" => ArchSpec::Device("armv7k"),
"armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"),
"arm64e" => ArchSpec::Device("arm64e"),
"arm64" | "aarch64" => ArchSpec::Device("arm64"),
"arm64_32" => ArchSpec::Device("arm64_32"),
"i386" | "i686" => ArchSpec::Simulator("-m32"),
"x86_64" => ArchSpec::Simulator("-m64"),
_ => {
return Err(Error::new(
ErrorKind::ArchitectureInvalid,
"Unknown architecture for iOS target.",
format!("Unknown architecture for {} target.", os).as_str(),
));
}
}
};

let min_version =
std::env::var("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or_else(|_| "7.0".into());
let (sdk_prefix, sim_prefix, min_version) = match os {
Os::Ios => (
"iphone",
"ios-",
std::env::var("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or_else(|_| "7.0".into()),
),
Os::WatchOs => (
"watch",
"watch",
std::env::var("WATCHOS_DEPLOYMENT_TARGET").unwrap_or_else(|_| "2.0".into()),
),
};

let sdk = match arch {
ArchSpec::Device(arch) => {
cmd.args.push("-arch".into());
cmd.args.push(arch.into());
cmd.args
.push(format!("-miphoneos-version-min={}", min_version).into());
"iphoneos"
.push(format!("-m{}os-version-min={}", sdk_prefix, min_version).into());
format!("{}os", sdk_prefix)
}
ArchSpec::Simulator(arch) => {
cmd.args.push(arch.into());
cmd.args
.push(format!("-mios-simulator-version-min={}", min_version).into());
"iphonesimulator"
.push(format!("-m{}simulator-version-min={}", sim_prefix, min_version).into());
format!("{}simulator", sdk_prefix)
}
ArchSpec::Catalyst(_) => "macosx",
ArchSpec::Catalyst(_) => "macosx".to_owned(),
};

self.print(&format!("Detecting iOS SDK path for {}", sdk));
let sdk_path = self.apple_sdk_root(sdk)?;
self.print(&format!("Detecting {} SDK path for {}", os, sdk));
let sdk_path = self.apple_sdk_root(sdk.as_str())?;
cmd.args.push("-isysroot".into());
cmd.args.push(sdk_path);
cmd.args.push("-fembed-bitcode".into());
Expand Down Expand Up @@ -2230,6 +2276,8 @@ impl Build {
}
} else if target.contains("apple-ios") {
clang.to_string()
} else if target.contains("apple-watchos") {
clang.to_string()
} else if target.contains("android") {
autodetect_android_compiler(&target, &host, gnu, clang)
} else if target.contains("cloudabi") {
Expand Down Expand Up @@ -2806,7 +2854,7 @@ impl Build {
Err(_) => {
return Err(Error::new(
ErrorKind::IOError,
"Unable to determine iOS SDK path.",
"Unable to determine Apple SDK path.",
));
}
};
Expand Down