From 5a1128c69242eb69b62c287e86680f5091ee7157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Fri, 12 Jun 2026 09:11:55 +0200 Subject: [PATCH] feat(watchos): target arm64 (aarch64-apple-watchos) for device builds arm64_32 cannot host Perry's NaN-boxed values (48-bit pointer tags need 64-bit usize), so real-watch builds never linked. watchOS 26 moved S9+ watches to full arm64, making the device target viable: swap the device triple to aarch64-apple-watchos, Swift/linker triples to arm64-apple-watchos26.0, and raise the watch bundle MinimumOSVersion accordingly (simulator keeps 10.0). Note: App Store submissions additionally require MinimumOSVersion >= 27.0 for arm64-only watch apps (arm64_32 slice mandatory below that). --- crates/perry-codegen/src/codegen/helpers.rs | 4 ++-- crates/perry/src/commands/compile/app_metadata.rs | 2 +- crates/perry/src/commands/compile/bundle_apple.rs | 10 +++++++++- crates/perry/src/commands/compile/link/mod.rs | 6 ++++-- crates/perry/src/commands/compile/link/platform_cmd.rs | 4 +++- crates/perry/src/commands/compile/targets.rs | 4 +++- 6 files changed, 22 insertions(+), 8 deletions(-) diff --git a/crates/perry-codegen/src/codegen/helpers.rs b/crates/perry-codegen/src/codegen/helpers.rs index c968929ae7..9b436f006f 100644 --- a/crates/perry-codegen/src/codegen/helpers.rs +++ b/crates/perry-codegen/src/codegen/helpers.rs @@ -379,7 +379,7 @@ pub(crate) fn default_target_triple() -> String { /// Supported: /// * `ios`, `ios-simulator` → aarch64-apple-ios /// * `visionos`, `visionos-simulator` → arm64-apple-xros1.0{,-simulator} -/// * `watchos` → arm64_32-apple-watchos (ILP32) +/// * `watchos` → aarch64-apple-watchos (arm64, S9+ / watchOS 26) /// * `watchos-simulator` → arm64-apple-watchos10.0-simulator /// * `tvos`, `tvos-simulator` → aarch64-apple-tvos /// * `android` → aarch64-unknown-linux-android @@ -397,7 +397,7 @@ pub fn resolve_target_triple(name: &str) -> Option { "ios-simulator" => Some("arm64-apple-ios17.0-simulator".to_string()), "visionos" => Some("arm64-apple-xros1.0".to_string()), "visionos-simulator" => Some("arm64-apple-xros1.0-simulator".to_string()), - "watchos" => Some("arm64_32-apple-watchos".to_string()), + "watchos" => Some("aarch64-apple-watchos".to_string()), "watchos-simulator" => Some("arm64-apple-watchos10.0-simulator".to_string()), "tvos" => Some("aarch64-apple-tvos".to_string()), "tvos-simulator" => Some("arm64-apple-tvos17.0-simulator".to_string()), diff --git a/crates/perry/src/commands/compile/app_metadata.rs b/crates/perry/src/commands/compile/app_metadata.rs index 9381422f4d..d4cc9634dd 100644 --- a/crates/perry/src/commands/compile/app_metadata.rs +++ b/crates/perry/src/commands/compile/app_metadata.rs @@ -158,7 +158,7 @@ pub(super) fn rust_target_triple(target: Option<&str>) -> Option<&'static str> { Some("visionos-simulator") => Some("aarch64-apple-visionos-sim"), Some("visionos") => Some("aarch64-apple-visionos"), Some("watchos-simulator") => Some("aarch64-apple-watchos-sim"), - Some("watchos") => Some("arm64_32-apple-watchos"), + Some("watchos") => Some("aarch64-apple-watchos"), Some("tvos-simulator") => Some("aarch64-apple-tvos-sim"), Some("tvos") => Some("aarch64-apple-tvos"), Some("harmonyos") => Some("aarch64-unknown-linux-ohos"), diff --git a/crates/perry/src/commands/compile/bundle_apple.rs b/crates/perry/src/commands/compile/bundle_apple.rs index c6d065b598..a2f215c146 100644 --- a/crates/perry/src/commands/compile/bundle_apple.rs +++ b/crates/perry/src/commands/compile/bundle_apple.rs @@ -173,6 +173,14 @@ pub(super) fn bundle_for_watchos( // #4849: read version/build_number from perry.toml (was hardcoded "1.0"). let (app_version, app_build_number) = read_apple_app_version(input); + // Device builds are arm64-only, which requires watchOS 26 (S9+); the + // simulator target keeps the lower floor. + let min_os = if target == Some("watchos-simulator") { + "10.0" + } else { + "26.0" + }; + let info_plist = format!( r#" @@ -189,7 +197,7 @@ pub(super) fn bundle_for_watchos( CFBundleShortVersionString {app_version} MinimumOSVersion - 10.0 + {min_os} UIDeviceFamily 4 diff --git a/crates/perry/src/commands/compile/link/mod.rs b/crates/perry/src/commands/compile/link/mod.rs index a23adfa739..08617f2dbb 100644 --- a/crates/perry/src/commands/compile/link/mod.rs +++ b/crates/perry/src/commands/compile/link/mod.rs @@ -1247,7 +1247,7 @@ pub(super) fn build_and_run_link( let (lib_name, build_cmd) = if is_watchos { ( "libperry_ui_watchos.a", - "cargo build --release -p perry-ui-watchos --target arm64_32-apple-watchos", + "cargo +nightly build -Z build-std=std,panic_abort --release -p perry-ui-watchos --target aarch64-apple-watchos (or --target aarch64-apple-watchos-sim for the simulator)", ) } else if is_tvos { ( @@ -1755,7 +1755,9 @@ pub(super) fn build_and_run_link( let swift_triple = if target == Some("watchos-simulator") { "arm64-apple-watchos10.0-simulator" } else { - "arm64_32-apple-watchos10.0" + // Device builds are arm64-only (S9+ / watchOS 26): Perry's + // NaN-boxed values need 64-bit pointers, which arm64_32 lacks. + "arm64-apple-watchos26.0" }; let swift_sysroot = String::from_utf8( Command::new("xcrun") diff --git a/crates/perry/src/commands/compile/link/platform_cmd.rs b/crates/perry/src/commands/compile/link/platform_cmd.rs index 2755ce2899..545dbdee40 100644 --- a/crates/perry/src/commands/compile/link/platform_cmd.rs +++ b/crates/perry/src/commands/compile/link/platform_cmd.rs @@ -56,7 +56,9 @@ pub fn select_linker_command( let triple = if target == Some("watchos-simulator") { "arm64-apple-watchos10.0-simulator" } else { - "arm64_32-apple-watchos10.0" + // Device builds are arm64-only (S9+ / watchOS 26): Perry's + // NaN-boxed values need 64-bit pointers, which arm64_32 lacks. + "arm64-apple-watchos26.0" }; // Find the entry object whose stem matches the user's input file stem diff --git a/crates/perry/src/commands/compile/targets.rs b/crates/perry/src/commands/compile/targets.rs index 3a3e0f7f69..a83b9161ee 100644 --- a/crates/perry/src/commands/compile/targets.rs +++ b/crates/perry/src/commands/compile/targets.rs @@ -554,7 +554,9 @@ pub(super) fn compile_for_watchos_widget( let target_triple = if is_simulator { "arm64-apple-watchos10.0-simulator" } else { - "arm64_32-apple-watchos10.0" + // Device builds are arm64-only (S9+ / watchOS 26), matching the app + // target: Perry's NaN-boxed values need 64-bit pointers. + "arm64-apple-watchos26.0" }; let mut frameworks = vec!["WidgetKit", "SwiftUI"]; if uses_app_intents {