diff --git a/docs/building-apps/build-properties.md b/docs/building-apps/build-properties.md
index 094b6c8c8cc4..98623c7160e6 100644
--- a/docs/building-apps/build-properties.md
+++ b/docs/building-apps/build-properties.md
@@ -275,6 +275,27 @@ By default we require a provisioning profile if:
Setting this property to `true` or `false` will override the default logic.
+## ComputeInstructionSetForReadyToRun
+
+Controls whether to automatically compute and pass the instruction set to the ReadyToRun (R2R) compiler based on the deployment target.
+
+When `PublishReadyToRun` is `true`, the build system automatically computes the minimum CPU instruction set required based on:
+* The `SupportedOSPlatformVersion` (minimum OS version the app supports)
+* The `RuntimeIdentifier` (target architecture and platform)
+
+This computed instruction set is then passed to crossgen2 via the `--instruction-set` argument, enabling the R2R compiler to generate optimized native code using appropriate CPU instructions.
+
+Set this property to `false` to disable automatic instruction set computation and use crossgen2's default behavior.
+
+Default: `true`
+
+Example:
+```xml
+
+ false
+
+```
+
## CompressBindingResourcePackage
The native references in a binding projects are copied to the output directory during the build process, next to the binding assembly (into something we call a "binding resource package").
diff --git a/dotnet/targets/Microsoft.Sdk.R2R.targets b/dotnet/targets/Microsoft.Sdk.R2R.targets
index d759b7215729..e7ff16a4a2d4 100644
--- a/dotnet/targets/Microsoft.Sdk.R2R.targets
+++ b/dotnet/targets/Microsoft.Sdk.R2R.targets
@@ -1,5 +1,7 @@
+
+
@@ -14,6 +16,31 @@
+
+
+
+
+
+
+
+
+ --instruction-set:$(_ComputedInstructionSet)
+ $(PublishReadyToRunCrossgen2ExtraArgs) --instruction-set:$(_ComputedInstructionSet)
+
+
+
diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeInstructionSet.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeInstructionSet.cs
new file mode 100644
index 000000000000..7f3717a6215b
--- /dev/null
+++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeInstructionSet.cs
@@ -0,0 +1,336 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Build.Framework;
+using Xamarin.Localization.MSBuild;
+using Xamarin.Utils;
+
+#nullable enable
+
+namespace Xamarin.MacDev.Tasks {
+ ///
+ /// Computes the minimum instruction set required for a given OS version and platform.
+ /// This is used to configure the R2R/NAOT compiler (crossgen2) with the appropriate --instruction-set argument.
+ ///
+ public class ComputeInstructionSet : XamarinTask {
+ #region Inputs
+
+ [Required]
+ public string RuntimeIdentifier { get; set; } = "";
+
+ [Required]
+ public string SupportedOSPlatformVersion { get; set; } = "";
+
+ #endregion
+
+ #region Outputs
+
+ [Output]
+ public string InstructionSet { get; set; } = "";
+
+ #endregion
+
+ // Device information structure
+ class DeviceInfo {
+ public string Cpu { get; }
+ public string MaxOSVersion { get; }
+
+ public DeviceInfo (string cpu, string maxOSVersion)
+ {
+ Cpu = cpu;
+ MaxOSVersion = maxOSVersion;
+ }
+ }
+
+ // Device information mapping
+ // This maps each device model to its CPU model and maximum supported OS version.
+ //
+ // Sources for device information:
+ // - iPhone models and chips: https://en.wikipedia.org/wiki/List_of_iPhone_models
+ // - iPad models and chips: https://en.wikipedia.org/wiki/List_of_iPad_models
+ // - Apple TV models and chips: https://en.wikipedia.org/wiki/Apple_TV#Specifications
+ // - Apple's technical specifications pages for each device (e.g., https://support.apple.com/kb/SP714 for iPhone 6s)
+ // - iOS compatibility: https://en.wikipedia.org/wiki/IOS_version_history#Overview
+ // - iPadOS compatibility: https://en.wikipedia.org/wiki/IPadOS_version_history#Overview
+ // - tvOS compatibility: https://en.wikipedia.org/wiki/TvOS_version_history#Overview
+ // - https://support.apple.com/en-us/120256 (iOS and iPadOS compatibility)
+ //
+ // To update: Cross-reference Wikipedia articles with Apple's official tech specs when new devices are released.
+ // Note: For devices that support the latest OS version, use SdkVersions constants instead of hardcoding the version number.
+ static Dictionary GetDeviceInfo ()
+ {
+ // Use SdkVersions for the latest OS versions
+ var latestIOSVersion = SdkVersions.iOS;
+ var latestTVOSVersion = SdkVersions.TVOS;
+
+ return new Dictionary {
+ // iOS devices
+ { "iPhone6s", new DeviceInfo ("A9", "15.8") },
+ { "iPhone6sPlus", new DeviceInfo ("A9", "15.8") },
+ { "iPhoneSE", new DeviceInfo ("A9", "15.8") },
+ { "iPhone7", new DeviceInfo ("A10", "15.8") },
+ { "iPhone7Plus", new DeviceInfo ("A10", "15.8") },
+ { "iPhone8", new DeviceInfo ("A11", "16.7") },
+ { "iPhone8Plus", new DeviceInfo ("A11", "16.7") },
+ { "iPhoneX", new DeviceInfo ("A11", "16.7") },
+ { "iPhoneXR", new DeviceInfo ("A12", latestIOSVersion) },
+ { "iPhoneXS", new DeviceInfo ("A12", latestIOSVersion) },
+ { "iPhoneXSMax", new DeviceInfo ("A12", latestIOSVersion) },
+ { "iPhone11", new DeviceInfo ("A13", latestIOSVersion) },
+ { "iPhone11Pro", new DeviceInfo ("A13", latestIOSVersion) },
+ { "iPhone11ProMax", new DeviceInfo ("A13", latestIOSVersion) },
+ { "iPhoneSE2", new DeviceInfo ("A13", latestIOSVersion) },
+ { "iPhone12mini", new DeviceInfo ("A14", latestIOSVersion) },
+ { "iPhone12", new DeviceInfo ("A14", latestIOSVersion) },
+ { "iPhone12Pro", new DeviceInfo ("A14", latestIOSVersion) },
+ { "iPhone12ProMax", new DeviceInfo ("A14", latestIOSVersion) },
+ { "iPhone13mini", new DeviceInfo ("A15", latestIOSVersion) },
+ { "iPhone13", new DeviceInfo ("A15", latestIOSVersion) },
+ { "iPhone13Pro", new DeviceInfo ("A15", latestIOSVersion) },
+ { "iPhone13ProMax", new DeviceInfo ("A15", latestIOSVersion) },
+ { "iPhoneSE3", new DeviceInfo ("A15", latestIOSVersion) },
+ { "iPhone14", new DeviceInfo ("A15", latestIOSVersion) },
+ { "iPhone14Plus", new DeviceInfo ("A15", latestIOSVersion) },
+ { "iPhone14Pro", new DeviceInfo ("A16", latestIOSVersion) },
+ { "iPhone14ProMax", new DeviceInfo ("A16", latestIOSVersion) },
+ { "iPhone15", new DeviceInfo ("A16", latestIOSVersion) },
+ { "iPhone15Plus", new DeviceInfo ("A16", latestIOSVersion) },
+ { "iPhone15Pro", new DeviceInfo ("A17Pro", latestIOSVersion) },
+ { "iPhone15ProMax", new DeviceInfo ("A17Pro", latestIOSVersion) },
+ { "iPhone16", new DeviceInfo ("A18", latestIOSVersion) },
+ { "iPhone16Plus", new DeviceInfo ("A18", latestIOSVersion) },
+ { "iPhone16Pro", new DeviceInfo ("A18Pro", latestIOSVersion) },
+ { "iPhone16ProMax", new DeviceInfo ("A18Pro", latestIOSVersion) },
+
+ // iPad models
+ { "iPadAir2", new DeviceInfo ("A8X", "15.8") },
+ { "iPadMini4", new DeviceInfo ("A8", "15.8") },
+ { "iPadPro9_7", new DeviceInfo ("A9X", "16.7") },
+ { "iPadPro12_9", new DeviceInfo ("A9X", "16.7") },
+ { "iPad5", new DeviceInfo ("A9", "16.7") },
+ { "iPadPro10_5", new DeviceInfo ("A10X", "16.7") },
+ { "iPadPro12_9_2", new DeviceInfo ("A10X", "16.7") },
+ { "iPad6", new DeviceInfo ("A10", "16.7") },
+ { "iPadAir3", new DeviceInfo ("A12", "17.7") },
+ { "iPadMini5", new DeviceInfo ("A12", "17.7") },
+ { "iPad7", new DeviceInfo ("A10", "17.7") },
+ { "iPadPro11", new DeviceInfo ("A12X", latestIOSVersion) },
+ { "iPadPro12_9_3", new DeviceInfo ("A12X", latestIOSVersion) },
+ { "iPad8", new DeviceInfo ("A12", latestIOSVersion) },
+ { "iPadAir4", new DeviceInfo ("A14", latestIOSVersion) },
+ { "iPad9", new DeviceInfo ("A13", latestIOSVersion) },
+ { "iPadMini6", new DeviceInfo ("A15", latestIOSVersion) },
+ { "iPadAir5", new DeviceInfo ("M1", latestIOSVersion) },
+ { "iPadPro11_3", new DeviceInfo ("M1", latestIOSVersion) },
+ { "iPadPro12_9_5", new DeviceInfo ("M1", latestIOSVersion) },
+ { "iPad10", new DeviceInfo ("A14", latestIOSVersion) },
+ { "iPadPro11_4", new DeviceInfo ("M2", latestIOSVersion) },
+ { "iPadPro12_9_6", new DeviceInfo ("M2", latestIOSVersion) },
+ { "iPadAir6", new DeviceInfo ("M2", latestIOSVersion) },
+ { "iPadPro11_M4", new DeviceInfo ("M4", latestIOSVersion) },
+ { "iPadPro13_M4", new DeviceInfo ("M4", latestIOSVersion) },
+
+ // Apple TV models
+ { "AppleTV4", new DeviceInfo ("A8", "15.6") },
+ { "AppleTV4K", new DeviceInfo ("A10X", latestTVOSVersion) },
+ { "AppleTV4K2", new DeviceInfo ("A12", latestTVOSVersion) },
+ { "AppleTV4K3", new DeviceInfo ("A15", latestTVOSVersion) },
+ };
+ }
+
+ // CPU-to-instruction-set mapping
+ // This maps each CPU model to the instruction set it supports.
+ //
+ // Sources for CPU instruction set architecture information:
+ // - Apple A-series chips: https://en.wikipedia.org/wiki/Apple_silicon#A_series
+ // - Apple M-series chips: https://en.wikipedia.org/wiki/Apple_silicon#M_series
+ // - ARM architecture versions: https://en.wikipedia.org/wiki/ARM_architecture_family#Cores
+ // - Apple's LLVM source and documentation for architecture features
+ // - ARM Architecture Reference Manuals: https://developer.arm.com/documentation/
+ //
+ // Crossgen2 instruction set compatibility:
+ // Run `crossgen2 --help` to see supported instruction sets (current list):
+ // x86-64-v2, x86-64-v3, x86-64-v4, armv8-a, armv8.1-a, armv8.2-a, armv8.3-a, armv8.4-a, armv8.5-a, armv8.6-a, apple-m1
+ //
+ // To update: Verify new Apple chip architectures against ARM documentation and crossgen2 supported instruction sets.
+ static readonly Dictionary CpuToInstructionSet = new Dictionary {
+ // ARM chips
+ { "A8", "armv8-a" }, // ARMv8.0-A (iPhone 6, iPad Air 2, Apple TV 4)
+ { "A8X", "armv8-a" }, // ARMv8.0-A (iPad Air 2)
+ { "A9", "armv8-a" }, // ARMv8.0-A (iPhone 6s, iPad 5, iPad Pro 9.7)
+ { "A9X", "armv8-a" }, // ARMv8.0-A (iPad Pro 12.9 1st gen, iPad Pro 9.7)
+ { "A10", "armv8-a" }, // ARMv8.0-A (iPhone 7)
+ { "A10X", "armv8.1-a" }, // ARMv8.1-A (iPad Pro 10.5, iPad Pro 12.9 2nd gen, Apple TV 4K)
+ { "A11", "armv8.2-a" }, // ARMv8.2-A (iPhone 8, iPhone X)
+ { "A12", "armv8.3-a" }, // ARMv8.3-A (iPhone XS, iPad Air 3, Apple TV 4K 2nd gen)
+ { "A12X", "armv8.3-a" }, // ARMv8.3-A (iPad Pro 11, iPad Pro 12.9 3rd gen)
+ { "A13", "armv8.4-a" }, // ARMv8.4-A (iPhone 11, iPhone SE 2nd gen)
+ { "A14", "armv8.4-a" }, // ARMv8.4-A with additional features (iPhone 12, iPad Air 4)
+ { "A15", "armv8.5-a" }, // ARMv8.5-A (iPhone 13, Apple TV 4K 3rd gen)
+ { "A16", "armv8.6-a" }, // ARMv8.6-A (iPhone 14 Pro)
+ { "A17Pro", "armv8.6-a" }, // ARMv8.6-A+ (iPhone 15 Pro)
+ { "A18", "armv8.6-a" }, // ARMv8.6-A+ (iPhone 16)
+ { "A18Pro", "armv8.6-a" }, // ARMv8.6-A+ (iPhone 16 Pro)
+
+ // Apple Silicon (M-series) for macOS/Mac Catalyst
+ { "M1", "apple-m1" }, // Apple M1 (Mac, iPad Air 5, iPad Pro)
+ { "M2", "apple-m1" }, // Apple M2 (similar to M1 in instruction support for crossgen2)
+ { "M3", "apple-m1" }, // Apple M3 (similar to M1 in instruction support for crossgen2)
+ { "M4", "apple-m1" }, // Apple M4 (similar to M1 in instruction support for crossgen2)
+
+ // Intel chips for macOS
+ { "Intel", "x86-64-v2" }, // Default Intel instruction set
+ };
+
+ // Crossgen2 supported instruction sets (from crossgen2 --help)
+ static readonly HashSet SupportedInstructionSets = new HashSet {
+ "x86-64-v2",
+ "x86-64-v3",
+ "x86-64-v4",
+ "armv8-a",
+ "armv8.1-a",
+ "armv8.2-a",
+ "armv8.3-a",
+ "armv8.4-a",
+ "armv8.5-a",
+ "armv8.6-a",
+ "apple-m1"
+ };
+
+ public override bool Execute ()
+ {
+ try {
+ var instructionSet = ComputeMinimumInstructionSet (Platform, SupportedOSPlatformVersion);
+#if NET
+ if (!string.IsNullOrEmpty (instructionSet)) {
+#else
+ if (!string.IsNullOrEmpty (instructionSet) && instructionSet is not null) {
+#endif
+ InstructionSet = instructionSet;
+ Log.LogMessage (MessageImportance.Low, $"Computed instruction set '{InstructionSet}' for {PlatformName} {SupportedOSPlatformVersion}");
+ } else {
+ Log.LogMessage (MessageImportance.Low, $"No instruction set computed for {PlatformName} {SupportedOSPlatformVersion}");
+ }
+
+ return !Log.HasLoggedErrors;
+ } catch (Exception ex) {
+ Log.LogError ($"Error computing instruction set: {ex.Message}");
+ return false;
+ }
+ }
+
+ string? ComputeMinimumInstructionSet (ApplePlatform platform, string osVersion)
+ {
+ // Parse the OS version
+ if (!Version.TryParse (osVersion, out var targetVersion)) {
+ Log.LogMessage (MessageImportance.Low, $"Could not parse OS version: {osVersion}");
+ return null;
+ }
+
+ // For macOS, Mac Catalyst, and simulators (which run on Mac hardware), we need different logic
+ if (platform == ApplePlatform.MacOSX || platform == ApplePlatform.MacCatalyst || RuntimeIdentifier.Contains ("simulator")) {
+ return ComputeMacInstructionSet (platform, targetVersion);
+ }
+
+ // For iOS and tvOS, find the oldest device that can run this OS version
+ var deviceInfo = GetDeviceInfo ();
+ var devicesToCheck = platform == ApplePlatform.TVOS ?
+ deviceInfo.Where (kv => kv.Key.StartsWith ("AppleTV")) :
+ deviceInfo.Where (kv => !kv.Key.StartsWith ("AppleTV"));
+
+ string? oldestCpu = null;
+ string? oldestInstructionSet = null;
+
+ foreach (var device in devicesToCheck) {
+ var deviceName = device.Key;
+ var info = device.Value;
+ var maxOSString = info.MaxOSVersion;
+
+ if (!Version.TryParse (maxOSString, out var maxOS))
+ continue;
+
+ // Check if this device can run the target OS version
+ // A device can run the target OS if its max OS >= target OS
+ if (maxOS >= targetVersion) {
+ // This device can run the target OS
+ var cpu = info.Cpu;
+ if (CpuToInstructionSet.TryGetValue (cpu, out var instructionSet)) {
+ // Keep track of the oldest instruction set we've seen
+ // We want the minimum instruction set that all compatible devices support
+ if (oldestCpu is null || IsOlderInstructionSet (instructionSet, oldestInstructionSet)) {
+ oldestCpu = cpu;
+ oldestInstructionSet = instructionSet;
+ }
+ }
+ }
+ }
+
+ // Validate that the instruction set is supported by crossgen2
+ if (oldestInstructionSet is not null && !SupportedInstructionSets.Contains (oldestInstructionSet)) {
+ Log.LogMessage (MessageImportance.Low, $"Instruction set '{oldestInstructionSet}' is not supported by crossgen2, skipping");
+ return null;
+ }
+
+ return oldestInstructionSet;
+ }
+
+ string? ComputeMacInstructionSet (ApplePlatform platform, Version targetVersion)
+ {
+ // For macOS and Mac Catalyst, we need to determine the instruction set based on RuntimeIdentifier
+ // RuntimeIdentifier format: - or .-
+ // Examples: "osx-x64", "osx-arm64", "osx.13.0-arm64", "maccatalyst-x64", "maccatalyst-arm64"
+
+ var parts = RuntimeIdentifier.Split ('-');
+ if (parts.Length < 2) {
+ Log.LogMessage (MessageImportance.Low, $"RuntimeIdentifier '{RuntimeIdentifier}' has unexpected format");
+ return null;
+ }
+
+ // The architecture is always the last segment after the last hyphen
+ var arch = parts [parts.Length - 1];
+
+ // Determine instruction set based on architecture
+ if (string.Equals (arch, "x64", StringComparison.OrdinalIgnoreCase)) {
+ // Intel/AMD x64 architecture
+ return "x86-64-v2";
+ } else if (string.Equals (arch, "arm64", StringComparison.OrdinalIgnoreCase)) {
+ // Apple Silicon
+ return "apple-m1";
+ } else {
+ Log.LogMessage (MessageImportance.Low, $"Unknown architecture '{arch}' in RuntimeIdentifier '{RuntimeIdentifier}'");
+ return null;
+ }
+ }
+
+ bool IsOlderInstructionSet (string? instructionSet1, string? instructionSet2)
+ {
+ if (instructionSet2 is null)
+ return true;
+ if (instructionSet1 is null)
+ return false;
+
+ // Order instruction sets from oldest to newest
+ var order = new [] {
+ "armv8-a",
+ "armv8.1-a",
+ "armv8.2-a",
+ "armv8.3-a",
+ "armv8.4-a",
+ "armv8.5-a",
+ "armv8.6-a",
+ "apple-m1",
+ "x86-64-v2",
+ "x86-64-v3",
+ "x86-64-v4"
+ };
+
+ var index1 = Array.IndexOf (order, instructionSet1);
+ var index2 = Array.IndexOf (order, instructionSet2);
+
+ if (index1 == -1 || index2 == -1)
+ return false;
+
+ return index1 < index2;
+ }
+ }
+}
diff --git a/tests/dotnet/UnitTests/expected/iOS-CoreCLR-R2R-size.txt b/tests/dotnet/UnitTests/expected/iOS-CoreCLR-R2R-size.txt
index c8182551db33..b8060946b314 100644
--- a/tests/dotnet/UnitTests/expected/iOS-CoreCLR-R2R-size.txt
+++ b/tests/dotnet/UnitTests/expected/iOS-CoreCLR-R2R-size.txt
@@ -1,29 +1,29 @@
-AppBundleSize: 20,862,389 bytes (20,373.4 KB = 19.9 MB)
+AppBundleSize: 20,862,501 bytes (20,373.5 KB = 19.9 MB)
# The following list of files and their sizes is just informational / for review, and isn't used in the test:
_CodeSignature/CodeResources: 11,701 bytes (11.4 KB = 0.0 MB)
archived-expanded-entitlements.xcent: 384 bytes (0.4 KB = 0.0 MB)
Frameworks/libcoreclr.framework/_CodeSignature/CodeResources: 1,798 bytes (1.8 KB = 0.0 MB)
-Frameworks/libcoreclr.framework/Info.plist: 839 bytes (0.8 KB = 0.0 MB)
-Frameworks/libcoreclr.framework/libcoreclr: 6,641,648 bytes (6,486.0 KB = 6.3 MB)
+Frameworks/libcoreclr.framework/Info.plist: 825 bytes (0.8 KB = 0.0 MB)
+Frameworks/libcoreclr.framework/libcoreclr: 6,641,824 bytes (6,486.2 KB = 6.3 MB)
Frameworks/libSystem.Globalization.Native.framework/_CodeSignature/CodeResources: 1,798 bytes (1.8 KB = 0.0 MB)
-Frameworks/libSystem.Globalization.Native.framework/Info.plist: 881 bytes (0.9 KB = 0.0 MB)
+Frameworks/libSystem.Globalization.Native.framework/Info.plist: 867 bytes (0.8 KB = 0.0 MB)
Frameworks/libSystem.Globalization.Native.framework/libSystem.Globalization.Native: 110,608 bytes (108.0 KB = 0.1 MB)
Frameworks/libSystem.IO.Compression.Native.framework/_CodeSignature/CodeResources: 1,798 bytes (1.8 KB = 0.0 MB)
-Frameworks/libSystem.IO.Compression.Native.framework/Info.plist: 883 bytes (0.9 KB = 0.0 MB)
+Frameworks/libSystem.IO.Compression.Native.framework/Info.plist: 869 bytes (0.8 KB = 0.0 MB)
Frameworks/libSystem.IO.Compression.Native.framework/libSystem.IO.Compression.Native: 1,467,440 bytes (1,433.0 KB = 1.4 MB)
Frameworks/libSystem.Native.framework/_CodeSignature/CodeResources: 1,798 bytes (1.8 KB = 0.0 MB)
-Frameworks/libSystem.Native.framework/Info.plist: 853 bytes (0.8 KB = 0.0 MB)
+Frameworks/libSystem.Native.framework/Info.plist: 839 bytes (0.8 KB = 0.0 MB)
Frameworks/libSystem.Native.framework/libSystem.Native: 164,176 bytes (160.3 KB = 0.2 MB)
Frameworks/libSystem.Net.Security.Native.framework/_CodeSignature/CodeResources: 1,798 bytes (1.8 KB = 0.0 MB)
-Frameworks/libSystem.Net.Security.Native.framework/Info.plist: 879 bytes (0.9 KB = 0.0 MB)
+Frameworks/libSystem.Net.Security.Native.framework/Info.plist: 865 bytes (0.8 KB = 0.0 MB)
Frameworks/libSystem.Net.Security.Native.framework/libSystem.Net.Security.Native: 88,432 bytes (86.4 KB = 0.1 MB)
Frameworks/libSystem.Security.Cryptography.Native.Apple.framework/_CodeSignature/CodeResources: 1,798 bytes (1.8 KB = 0.0 MB)
-Frameworks/libSystem.Security.Cryptography.Native.Apple.framework/Info.plist: 909 bytes (0.9 KB = 0.0 MB)
+Frameworks/libSystem.Security.Cryptography.Native.Apple.framework/Info.plist: 895 bytes (0.9 KB = 0.0 MB)
Frameworks/libSystem.Security.Cryptography.Native.Apple.framework/libSystem.Security.Cryptography.Native.Apple: 224,080 bytes (218.8 KB = 0.2 MB)
Frameworks/SizeTestApp.framework/_CodeSignature/CodeResources: 1,798 bytes (1.8 KB = 0.0 MB)
-Frameworks/SizeTestApp.framework/Info.plist: 842 bytes (0.8 KB = 0.0 MB)
-Frameworks/SizeTestApp.framework/SizeTestApp: 9,441,664 bytes (9,220.4 KB = 9.0 MB)
-Info.plist: 1,167 bytes (1.1 KB = 0.0 MB)
+Frameworks/SizeTestApp.framework/Info.plist: 828 bytes (0.8 KB = 0.0 MB)
+Frameworks/SizeTestApp.framework/SizeTestApp: 9,441,712 bytes (9,220.4 KB = 9.0 MB)
+Info.plist: 1,153 bytes (1.1 KB = 0.0 MB)
Microsoft.iOS.dll: 163,840 bytes (160.0 KB = 0.2 MB)
PkgInfo: 8 bytes (0.0 KB = 0.0 MB)
runtimeconfig.bin: 1,481 bytes (1.4 KB = 0.0 MB)
diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ComputeInstructionSetTaskTests.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ComputeInstructionSetTaskTests.cs
new file mode 100644
index 000000000000..83afdb878553
--- /dev/null
+++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/ComputeInstructionSetTaskTests.cs
@@ -0,0 +1,119 @@
+#nullable enable
+using System;
+using NUnit.Framework;
+using Xamarin.MacDev.Tasks;
+using Xamarin.Utils;
+
+namespace Xamarin.MacDev.Tasks {
+ [TestFixture]
+ public class ComputeInstructionSetTaskTests : TestBase {
+ ComputeInstructionSet CreateTask (ApplePlatform platform = ApplePlatform.iOS)
+ {
+ var task = CreateTask ();
+ task.TargetFrameworkMoniker = TargetFramework.GetTargetFramework (platform).ToString ();
+ return task;
+ }
+
+ [Test]
+ [TestCase (ApplePlatform.iOS, "12.0", "armv8-a")] // iPhone 6s era (iOS 12)
+ [TestCase (ApplePlatform.iOS, "13.0", "armv8-a")] // iPhone 6s era (iOS 13)
+ [TestCase (ApplePlatform.iOS, "14.0", "armv8-a")] // iPhone 6s era (iOS 14)
+ [TestCase (ApplePlatform.iOS, "15.0", "armv8-a")] // iPhone 6s era (iOS 15)
+ [TestCase (ApplePlatform.iOS, "16.0", "armv8-a")] // iPad5 (A9) can run iOS 16
+ [TestCase (ApplePlatform.iOS, "17.0", "armv8-a")] // iPad7 (A10) can run iOS 17
+ [TestCase (ApplePlatform.iOS, "18.0", "armv8.3-a")] // iPhone XR and newer (iOS 18)
+ public void TestiOSInstructionSets (ApplePlatform platform, string osVersion, string expectedInstructionSet)
+ {
+ var task = CreateTask (platform);
+ task.SupportedOSPlatformVersion = osVersion;
+
+ ExecuteTask (task);
+
+ Assert.AreEqual (expectedInstructionSet, task.InstructionSet, $"Instruction set for {platform} {osVersion}");
+ }
+
+ [Test]
+ [TestCase (ApplePlatform.TVOS, "12.0", "armv8-a")] // Apple TV 4
+ [TestCase (ApplePlatform.TVOS, "13.0", "armv8-a")] // Apple TV 4
+ [TestCase (ApplePlatform.TVOS, "14.0", "armv8-a")] // Apple TV 4
+ [TestCase (ApplePlatform.TVOS, "15.0", "armv8-a")] // Apple TV 4
+ [TestCase (ApplePlatform.TVOS, "16.0", "armv8.1-a")] // Apple TV 4K and newer
+ [TestCase (ApplePlatform.TVOS, "17.0", "armv8.1-a")] // Apple TV 4K and newer
+ public void TesttvOSInstructionSets (ApplePlatform platform, string osVersion, string expectedInstructionSet)
+ {
+ var task = CreateTask (platform);
+ task.SupportedOSPlatformVersion = osVersion;
+
+ ExecuteTask (task);
+
+ Assert.AreEqual (expectedInstructionSet, task.InstructionSet, $"Instruction set for {platform} {osVersion}");
+ }
+
+ [Test]
+ [TestCase (ApplePlatform.MacOSX, "10.15", "osx-x64", "x86-64-v2")]
+ [TestCase (ApplePlatform.MacOSX, "11.0", "osx-x64", "x86-64-v2")]
+ [TestCase (ApplePlatform.MacOSX, "11.0", "osx-arm64", "apple-m1")]
+ [TestCase (ApplePlatform.MacOSX, "12.0", "osx-x64", "x86-64-v2")]
+ [TestCase (ApplePlatform.MacOSX, "12.0", "osx-arm64", "apple-m1")]
+ [TestCase (ApplePlatform.MacCatalyst, "14.0", "maccatalyst-x64", "x86-64-v2")]
+ [TestCase (ApplePlatform.MacCatalyst, "14.0", "maccatalyst-arm64", "apple-m1")]
+ [TestCase (ApplePlatform.MacCatalyst, "15.0", "maccatalyst-x64", "x86-64-v2")]
+ [TestCase (ApplePlatform.MacCatalyst, "15.0", "maccatalyst-arm64", "apple-m1")]
+ public void TestmacOSInstructionSets (ApplePlatform platform, string osVersion, string runtimeIdentifier, string expectedInstructionSet)
+ {
+ var task = CreateTask (platform);
+ task.SupportedOSPlatformVersion = osVersion;
+ task.RuntimeIdentifier = runtimeIdentifier;
+
+ ExecuteTask (task);
+
+ Assert.AreEqual (expectedInstructionSet, task.InstructionSet, $"Instruction set for {platform} {osVersion} with {runtimeIdentifier}");
+ }
+
+ [Test]
+ public void TestEmptyOSVersion ()
+ {
+ var task = CreateTask (ApplePlatform.iOS);
+ task.SupportedOSPlatformVersion = "";
+
+ ExecuteTask (task);
+
+ Assert.AreEqual ("", task.InstructionSet, "Instruction set should be empty for empty OS version");
+ }
+
+ [Test]
+ public void TestInvalidOSVersion ()
+ {
+ var task = CreateTask (ApplePlatform.iOS);
+ task.SupportedOSPlatformVersion = "invalid";
+
+ ExecuteTask (task);
+
+ Assert.AreEqual ("", task.InstructionSet, "Instruction set should be empty for invalid OS version");
+ }
+
+ [Test]
+ public void TestVeryOldOSVersion ()
+ {
+ var task = CreateTask (ApplePlatform.iOS);
+ task.SupportedOSPlatformVersion = "9.0";
+
+ // iOS 9 was supported by iPhone 4s (A5), but we don't have data for that era
+ // The task should handle this gracefully
+ ExecuteTask (task);
+ }
+
+ [Test]
+ public void TestFutureOSVersion ()
+ {
+ var task = CreateTask (ApplePlatform.iOS);
+ task.SupportedOSPlatformVersion = "99.0";
+
+ ExecuteTask (task);
+
+ // For a future OS version that no current device supports, we won't compute an instruction set
+ // This is expected behavior - we can't predict future instruction sets
+ Assert.IsEmpty (task.InstructionSet, "Should not compute instruction set for future OS version");
+ }
+ }
+}