From 7de8fb4dbdc2c44de477110035e60a516dfc21de Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Wed, 5 Nov 2025 07:44:10 +0800 Subject: [PATCH] Correct wheel naming when targeting iOS. --- Changelog.md | 1 + src/build_context.rs | 56 ++++++++++++++++++++++++++++++++++++++++- src/target/mod.rs | 8 +++++- src/target/pypi_tags.rs | 3 +++ 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index c2d958df0..77ccd48e7 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ ## Unreleased +* Fix iOS wheel naming to be compliant with PEP 730. * Fix generated WHEEL Tag metadata to be spec compliant. * Remove `add_directory()` from ModuleWriter and make it an implementation detail for the specific impl diff --git a/src/build_context.rs b/src/build_context.rs index b091cbefb..8b04e8494 100644 --- a/src/build_context.rs +++ b/src/build_context.rs @@ -620,6 +620,21 @@ impl BuildContext { format!("macosx_{x86_64_tag}_x86_64") } } + // iOS (simulator and device) + (Os::Ios, Arch::X86_64) | (Os::Ios, Arch::Aarch64) => { + let arch = if target.target_arch() == Arch::Aarch64 { + "arm64" + } else { + "x86_64" + }; + let abi = if self.target.target_triple().ends_with("-sim") { + "iphonesimulator" + } else { + "iphoneos" + }; + let (min_sdk_major, min_sdk_minor) = iphoneos_deployment_target(env::var("IPHONEOS_DEPLOYMENT_TARGET").ok().as_deref())?; + format!("ios_{min_sdk_major}_{min_sdk_minor}_{arch}_{abi}") + } // FreeBSD | (Os::FreeBsd, _) => { format!( @@ -1256,6 +1271,23 @@ fn macosx_deployment_target( )) } +/// Get the iOS deployment target version +fn iphoneos_deployment_target(deploy_target: Option<&str>) -> Result<(u16, u16)> { + let (major, minor) = if let Some(deploy_target) = deploy_target { + let err_ctx = "IPHONEOS_DEPLOYMENT_TARGET is invalid"; + let mut parts = deploy_target.split('.'); + let major = parts.next().context(err_ctx)?; + let major: u16 = major.parse().context(err_ctx)?; + let minor = parts.next().context(err_ctx)?; + let minor: u16 = minor.parse().context(err_ctx)?; + (major, minor) + } else { + (13, 0) + }; + + Ok((major, minor)) +} + #[inline] fn python_macosx_target_version(version: (u16, u16)) -> (u16, u16) { let (major, minor) = version; @@ -1360,7 +1392,7 @@ fn emcc_version() -> Result { #[cfg(test)] mod tests { - use super::macosx_deployment_target; + use super::{iphoneos_deployment_target, macosx_deployment_target}; use pretty_assertions::assert_eq; #[test] @@ -1398,4 +1430,26 @@ mod tests { ((11, 0), (11, 0)) ); } + + #[test] + fn test_iphoneos_deployment_target() { + // Use default when no value is provided + assert_eq!(iphoneos_deployment_target(None).unwrap(), (13, 0)); + + // Valid version strings + assert_eq!(iphoneos_deployment_target(Some("13.0")).unwrap(), (13, 0)); + assert_eq!(iphoneos_deployment_target(Some("14.5")).unwrap(), (14, 5)); + assert_eq!(iphoneos_deployment_target(Some("15.0")).unwrap(), (15, 0)); + // Extra parts are ignored + assert_eq!(iphoneos_deployment_target(Some("14.5.1")).unwrap(), (14, 5)); + + // Invalid formats + assert!(iphoneos_deployment_target(Some("invalid")).is_err()); + assert!(iphoneos_deployment_target(Some("13")).is_err()); + assert!(iphoneos_deployment_target(Some("13.")).is_err()); + assert!(iphoneos_deployment_target(Some(".0")).is_err()); + assert!(iphoneos_deployment_target(Some("abc.def")).is_err()); + assert!(iphoneos_deployment_target(Some("13.abc")).is_err()); + assert!(iphoneos_deployment_target(Some("")).is_err()); + } } diff --git a/src/target/mod.rs b/src/target/mod.rs index 5744e03b5..3aa3d5f31 100644 --- a/src/target/mod.rs +++ b/src/target/mod.rs @@ -454,7 +454,7 @@ impl Target { Os::Windows => "windows", Os::Linux => "linux", Os::Macos => "darwin", - Os::Ios => "darwin", + Os::Ios => "ios", Os::FreeBsd => "freebsd", Os::NetBsd => "netbsd", Os::OpenBsd => "openbsd", @@ -604,6 +604,12 @@ impl Target { self.os == Os::Macos } + /// Returns true if the current platform is iOS + #[inline] + pub fn is_ios(&self) -> bool { + self.os == Os::Ios + } + /// Returns true if the current platform is windows #[inline] pub fn is_windows(&self) -> bool { diff --git a/src/target/pypi_tags.rs b/src/target/pypi_tags.rs index db4097e6a..7682cce87 100644 --- a/src/target/pypi_tags.rs +++ b/src/target/pypi_tags.rs @@ -225,6 +225,9 @@ mod tests { ("aarch64-linux-android", true), ("armv7-linux-androideabi", true), ("riscv64gc-unknown-linux-gnu", true), + ("aarch64-apple-ios", true), + ("aarch64-apple-ios-sim", true), + ("x86_64-apple-ios", true), ("x86_64-unknown-freebsd", false), // Now unsupported (no lazy validation) ("powerpc64-unknown-linux-gnu", true), // PPC64 on Linux is supported ("s390x-unknown-linux-gnu", true), // s390x on Linux is supported