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

feat: Added visionOS support for Apple Vision Pro #63

Merged
merged 6 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions example/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ fn main() {
// Ensure this matches the versions set in your `Package.swift` file.
SwiftLinker::new("10.15")
.with_ios("11")
.with_visionos("1")
.with_package("swift-lib", "./swift-lib/")
.link();
}
69 changes: 57 additions & 12 deletions src-rs/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,17 @@ struct SwiftEnv {
}

impl SwiftEnv {
fn new(minimum_macos_version: &str, minimum_ios_version: Option<&str>) -> Self {
fn new(
minimum_macos_version: &str,
minimum_ios_version: Option<&str>,
minimum_visionos_version: Option<&str>,
) -> Self {
let rust_target = RustTarget::from_env();
let target = rust_target.swift_target_triple(minimum_macos_version, minimum_ios_version);
let target = rust_target.swift_target_triple(
minimum_macos_version,
minimum_ios_version,
minimum_visionos_version,
);

let swift_target_info_str = Command::new("swift")
.args(["-target", &target, "-print-target-info"])
Expand All @@ -47,13 +55,15 @@ impl SwiftEnv {
enum RustTargetOS {
MacOS,
IOS,
VisionOS,
}

impl RustTargetOS {
fn from_env() -> Self {
match env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() {
"macos" => RustTargetOS::MacOS,
"ios" => RustTargetOS::IOS,
"visionos" => RustTargetOS::VisionOS,
_ => panic!("unexpected target operating system"),
}
}
Expand All @@ -62,6 +72,7 @@ impl RustTargetOS {
match self {
Self::MacOS => "macosx",
Self::IOS => "ios",
Self::VisionOS => "xros",
}
}
}
Expand All @@ -71,6 +82,7 @@ impl Display for RustTargetOS {
match self {
Self::MacOS => write!(f, "macos"),
Self::IOS => write!(f, "ios"),
Self::VisionOS => write!(f, "visionos"),
}
}
}
Expand All @@ -80,18 +92,23 @@ enum SwiftSDK {
MacOS,
IOS,
IOSSimulator,
VisionOS,
VisionOSSimulator,
}

impl SwiftSDK {
fn from_os(os: &RustTargetOS) -> Self {
let target = env::var("TARGET").unwrap();
let simulator = target.ends_with("ios-sim")
|| target.ends_with("visionos-sim")
|| (target.starts_with("x86_64") && target.ends_with("ios"));

match os {
RustTargetOS::MacOS => Self::MacOS,
RustTargetOS::IOS if simulator => Self::IOSSimulator,
RustTargetOS::IOS => Self::IOS,
RustTargetOS::VisionOS if simulator => Self::VisionOSSimulator,
RustTargetOS::VisionOS => Self::VisionOS,
}
}

Expand All @@ -100,6 +117,8 @@ impl SwiftSDK {
Self::MacOS => "osx",
Self::IOS => "ios",
Self::IOSSimulator => "iossim",
Self::VisionOS => "xros",
Self::VisionOSSimulator => "xrsimulator",
}
}
}
Expand All @@ -110,6 +129,8 @@ impl Display for SwiftSDK {
Self::MacOS => write!(f, "macosx"),
Self::IOSSimulator => write!(f, "iphonesimulator"),
Self::IOS => write!(f, "iphoneos"),
Self::VisionOSSimulator => write!(f, "xrsimulator"),
Self::VisionOS => write!(f, "xros"),
}
}
}
Expand All @@ -133,19 +154,23 @@ impl RustTarget {
&self,
minimum_macos_version: &str,
minimum_ios_version: Option<&str>,
minimum_visionos_version: Option<&str>,
) -> String {
let unversioned = self.unversioned_swift_target_triple();
format!(
"{unversioned}{}{}",
match (&self.os, minimum_ios_version) {
(RustTargetOS::MacOS, _) => minimum_macos_version,
(RustTargetOS::IOS, Some(version)) => version,
_ => "",
match &self.os {
RustTargetOS::MacOS => minimum_macos_version,
RustTargetOS::IOS => minimum_ios_version.unwrap(),
RustTargetOS::VisionOS => minimum_visionos_version.unwrap(),
},
// simulator suffix
matches!(self.sdk, SwiftSDK::IOSSimulator)
.then(|| "-simulator".to_string())
.unwrap_or_default()
matches!(
self.sdk,
SwiftSDK::IOSSimulator | SwiftSDK::VisionOSSimulator
)
.then(|| "-simulator".to_string())
.unwrap_or_default()
)
}

Expand All @@ -172,6 +197,7 @@ pub struct SwiftLinker {
packages: Vec<SwiftPackage>,
macos_min_version: String,
ios_min_version: Option<String>,
visionos_min_version: Option<String>,
}

impl SwiftLinker {
Expand All @@ -183,6 +209,7 @@ impl SwiftLinker {
packages: vec![],
macos_min_version: macos_min_version.to_string(),
ios_min_version: None,
visionos_min_version: None,
}
}

Expand All @@ -195,6 +222,15 @@ impl SwiftLinker {
self
}

/// Instructs the [`SwiftLinker`] to also compile for visionOS
/// using the specified minimum visionOS version.
///
/// Minimum visionOS version must be at least 11.
pub fn with_visionos(mut self, min_version: &str) -> Self {
self.visionos_min_version = Some(min_version.to_string());
self
}

/// Adds a package to be linked against.
/// `name` should match the `name` field in your `Package.swift`,
/// and `path` should point to the root of your Swift package relative
Expand All @@ -212,7 +248,11 @@ impl SwiftLinker {
/// This does not (yet) automatically rebuild your Swift files when they are modified,
/// you'll need to modify/save your `build.rs` file for that.
pub fn link(self) {
let swift_env = SwiftEnv::new(&self.macos_min_version, self.ios_min_version.as_deref());
let swift_env = SwiftEnv::new(
&self.macos_min_version,
self.ios_min_version.as_deref(),
self.visionos_min_version.as_deref(),
);

#[allow(clippy::uninlined_format_args)]
for path in swift_env.paths.runtime_library_paths {
Expand Down Expand Up @@ -253,8 +293,11 @@ impl SwiftLinker {
arch => arch,
};

let swift_target_triple = rust_target
.swift_target_triple(&self.macos_min_version, self.ios_min_version.as_deref());
let swift_target_triple = rust_target.swift_target_triple(
&self.macos_min_version,
self.ios_min_version.as_deref(),
self.visionos_min_version.as_deref(),
);

command
// Build the package (duh)
Expand All @@ -277,6 +320,8 @@ impl SwiftLinker {
.args(["-Xcc", &format!("--target={swift_target_triple}")])
.args(["-Xcxx", &format!("--target={swift_target_triple}")]);

println!("Command `{command:?}`");

if !command.status().unwrap().success() {
panic!("Failed to compile swift package {}", package.name);
}
Expand Down
1 change: 1 addition & 0 deletions src-rs/test-build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ fn main() {

SwiftLinker::new("10.15")
.with_ios("11")
.with_visionos("1")
.with_package("test-swift", "tests/swift-pkg")
.link();
}
Expand Down