Skip to content
Draft
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
7 changes: 6 additions & 1 deletion dotnet/targets/Microsoft.Sdk.R2R.targets
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
<_ReadyToRunFilesToPublish Remove="@(_ReadyToRunFilesToPublish)" />
<_ReadyToRunFilesToPublish Include="@(_ReadyToRunFilesToPublishFixed)" />
</ItemGroup>
<ItemGroup Condition="'$(PublishReadyToRunComposite)' != 'true'">
<_ReadyToRunCompileListFixed Include="@(_ReadyToRunCompileList)" OutputR2RImage="$(_ReadyToRunOutputPath)/%(Filename)%(Extension)" />
<_ReadyToRunCompileList Remove="@(_ReadyToRunCompileList)" />
<_ReadyToRunCompileList Include="@(_ReadyToRunCompileListFixed)" />
</ItemGroup>
</Target>

<!--
Expand Down Expand Up @@ -78,7 +83,7 @@
</Target>

<!-- Set some default properties -->
<PropertyGroup Condition="'$(PublishReadyToRun)' == 'true' And '$(UseMonoRuntime)' == 'false' And '$(_UseNativeAot)' != 'true'">
<PropertyGroup Condition="'$(PublishReadyToRun)' == 'true' And '$(PublishReadyToRunContainerFormat)' == 'macho' And '$(UseMonoRuntime)' == 'false' And '$(_UseNativeAot)' != 'true'">
<CreateR2RFramework Condition="'$(CreateR2RFramework)' == '' And ('$(_PlatformName)' == 'iOS' Or '$(_PlatformName)' == 'tvOS')">true</CreateR2RFramework>
<CreateR2RDylib Condition="'$(CreateR2RDylib)' == '' And '$(CreateR2RFramework)' != 'true'">true</CreateR2RDylib>

Expand Down
1 change: 1 addition & 0 deletions dotnet/targets/Xamarin.Shared.Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@
Platform=$(_PlatformName)
PlatformAssembly=$(_PlatformAssemblyName).dll
PublishReadyToRun=$(PublishReadyToRun)
PublishReadyToRunContainerFormat=$(PublishReadyToRunContainerFormat)
RelativeAppBundlePath=$(_RelativeAppBundlePath)
Registrar=$(Registrar)
@(ReferenceNativeSymbol -> 'ReferenceNativeSymbol=%(SymbolType):%(SymbolMode):%(Identity)')
Expand Down
12 changes: 9 additions & 3 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/SymbolStrip.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,16 @@ public class SymbolStrip : XamarinParallelTask, ITaskCallback {
public string Kind { get; set; } = string.Empty;
#endregion

bool GetIsFramework (ITaskItem item)
bool GetIsFrameworkOrDynamicLibrary (ITaskItem item)
{
var value = GetNonEmptyStringOrFallback (item, "Kind", Kind);
return string.Equals (value, "Framework", StringComparison.OrdinalIgnoreCase);
if (string.Equals (value, "Framework", StringComparison.OrdinalIgnoreCase))
return true;

if (string.Equals (value, "Dynamic", StringComparison.OrdinalIgnoreCase) || item.ItemSpec.EndsWith (".dylib", StringComparison.OrdinalIgnoreCase))
return true;

return false;
}

void ExecuteStrip (ITaskItem item)
Expand All @@ -45,7 +51,7 @@ void ExecuteStrip (ITaskItem item)
args.Add (symbolFile);
}

if (GetIsFramework (item)) {
if (GetIsFrameworkOrDynamicLibrary (item)) {
// Only remove debug symbols from frameworks.
args.Add ("-S");
args.Add ("-x");
Expand Down
9 changes: 9 additions & 0 deletions msbuild/Xamarin.Shared/Xamarin.Shared.targets
Original file line number Diff line number Diff line change
Expand Up @@ -2963,6 +2963,15 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<!-- This is the name of the dSYM that will be created (if that's the case) -->
<DSymName>%(Filename).dSYM</DSymName>
</_PostProcessingItem>
<!-- In outer multi-RID builds the merged app bundle already contains the universal dylibs,
but the RID-specific native references are no longer available as items. Scan the merged
app bundle so that dsymutil/strip still runs for those dylibs. -->
<_MergedAppBundleDylib Include="$(AppBundleDir)/$(_AppContentsRelativePathForPostProcessing)*.dylib" Condition="'$(RuntimeIdentifiers)' != ''" />
<_PostProcessingItem Include="@(_MergedAppBundleDylib -> '$(_AppBundleName)$(AppBundleExtension)/$(_AppContentsRelativePathForPostProcessing)%(Filename)%(Extension)')" Condition="'$(RuntimeIdentifiers)' != ''">
<ItemSourcePath>$(_AppContainerDir)%(_PostProcessingItem.Identity)</ItemSourcePath>
<dSYMSourcePath>$(_AppContainerDir)%(_PostProcessingItem.Identity).dSYM</dSYMSourcePath>
<DSymName>%(Filename).dSYM</DSymName>
</_PostProcessingItem>
<_PostProcessingItem Include="$([System.IO.Path]::GetFileName('$(AppBundleDir)'))/$(_NativeExecutableRelativePath)" Condition="'$(IsWatchApp)' != 'true'">
<SymbolFile Condition="'$(_ExportSymbolsExplicitly)' == 'true'">$(_SymbolsListFullPath)</SymbolFile>
<DSymName>$(_AppBundleName)$(AppBundleExtension).dSYM</DSymName>
Expand Down
14 changes: 11 additions & 3 deletions tests/dotnet/SizeTestApp/AppDelegate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@
#if HAS_UIKIT
using UIKit;
#endif
#if HAS_APPKIT
using AppKit;
#endif

namespace MySimpleApp {
public class Program {
static int Main (string [] args)
{
#if HAS_UIKIT

UIApplication.Main (args, null, typeof (AppDelegate));
#else
#elif HAS_APPKIT
NSApplication.Init ();
NSApplication.Main (args);
#else
#error This test app has not been implemented for this platform.
#endif
return 0;
}
Expand All @@ -40,7 +44,11 @@ public override bool FinishedLaunching (UIApplication app, NSDictionary options)
return true;
}
}
#elif HAS_APPKIT
[Register ("AppDelegate")]
public class AppDelegate : NSApplicationDelegate {
}
#else
#error This test app has not been implemented for AppKit yet.
#error This test app has not been implemented for this platform.
#endif
}
55 changes: 46 additions & 9 deletions tests/dotnet/UnitTests/AppSizeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,70 @@ namespace Xamarin.Tests {
public class AppSizeTest : TestBaseClass {

[TestCase (ApplePlatform.iOS, "ios-arm64")]
[TestCase (ApplePlatform.TVOS, "tvos-arm64")]
[TestCase (ApplePlatform.MacCatalyst, "maccatalyst-arm64")]
public void MonoVM (ApplePlatform platform, string runtimeIdentifiers)
{
Run (platform, runtimeIdentifiers, "Release", $"{platform}-MonoVM", true, new Dictionary<string, string> () { { "UseMonoRuntime", "true" } });
var dict = new Dictionary<string, string> () {
{ "UseMonoRuntime", "true" },
{ "NoDSymUtil", "false" },
};
Run (platform, runtimeIdentifiers, "Release", $"{platform}-MonoVM", true, dict);
}

[TestCase (ApplePlatform.iOS, "ios-arm64")]
[TestCase (ApplePlatform.TVOS, "tvos-arm64")]
[TestCase (ApplePlatform.MacCatalyst, "maccatalyst-arm64")]
public void MonoVM_Interpreter (ApplePlatform platform, string runtimeIdentifiers)
{
Run (platform, runtimeIdentifiers, "Release", $"{platform}-MonoVM-interpreter", true, new Dictionary<string, string> () { { "UseInterpreter", "true" }, { "UseMonoRuntime", "true" } });
var dict = new Dictionary<string, string> () {
{ "UseInterpreter", "true" },
{ "UseMonoRuntime", "true" },
{ "NoDSymUtil", "false" },
};
Run (platform, runtimeIdentifiers, "Release", $"{platform}-MonoVM-interpreter", true, dict);
}

[TestCase (ApplePlatform.iOS, "ios-arm64")]
[TestCase (ApplePlatform.TVOS, "tvos-arm64")]
[TestCase (ApplePlatform.MacCatalyst, "maccatalyst-arm64")]
[TestCase (ApplePlatform.MacOSX, "osx-arm64;osx-x64")]
public void NativeAOT (ApplePlatform platform, string runtimeIdentifiers)
{
Run (platform, runtimeIdentifiers, "Release", $"{platform}-NativeAOT", false, new Dictionary<string, string> () { { "PublishAot", "true" }, { "_IsPublishing", "true" } });
var dict = new Dictionary<string, string> () {
{ "PublishAot", "true" },
{ "_IsPublishing", "true" },
{ "NoDSymUtil", "false" }, // off by default for macOS, but we want to test it, so enable it
};
Run (platform, runtimeIdentifiers, "Release", $"{platform}-NativeAOT", false, dict);
}

[TestCase (ApplePlatform.iOS, "ios-arm64")]
public void CoreCLR_Interpreter (ApplePlatform platform, string runtimeIdentifiers)
[TestCase (ApplePlatform.iOS, "ios-arm64", true)]
[TestCase (ApplePlatform.TVOS, "tvos-arm64", true)]
[TestCase (ApplePlatform.MacCatalyst, "maccatalyst-arm64", true)]
[TestCase (ApplePlatform.MacOSX, "osx-arm64;osx-x64", false)]
public void CoreCLR_Interpreter (ApplePlatform platform, string runtimeIdentifiers, bool isTrimmed)
{
Run (platform, runtimeIdentifiers, "Release", $"{platform}-CoreCLR-Interpreter", true, new Dictionary<string, string> () { { "UseMonoRuntime", "false" }, { "PublishReadyToRun", "false" } });
var dict = new Dictionary<string, string> () {
{ "UseMonoRuntime", "false" },
{ "PublishReadyToRun", "false" },
{ "NoDSymUtil", "false" }, // off by default for macOS, but we want to test it, so enable it
};
Run (platform, runtimeIdentifiers, "Release", $"{platform}-CoreCLR-Interpreter", isTrimmed, dict);
}
Comment on lines +52 to 64
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isTrimmed parameter name is misleading here: it's passed directly to Run(..., supportsAssemblyInspection, ...) and controls whether the assembly API report is generated, not trimming. Rename this parameter (and the TestCase argument) to something like supportsAssemblyInspection/supportsApiInspection to match what it actually does, or introduce a separate trimming flag if that's the intent.

Copilot uses AI. Check for mistakes.

[TestCase (ApplePlatform.iOS, "ios-arm64")]
public void CoreCLR_R2R (ApplePlatform platform, string runtimeIdentifiers)
[TestCase (ApplePlatform.iOS, "ios-arm64", true)]
[TestCase (ApplePlatform.TVOS, "tvos-arm64", true)]
[TestCase (ApplePlatform.MacCatalyst, "maccatalyst-arm64", true)]
[TestCase (ApplePlatform.MacOSX, "osx-arm64;osx-x64", false)]
public void CoreCLR_R2R (ApplePlatform platform, string runtimeIdentifiers, bool isTrimmed)
{
Run (platform, runtimeIdentifiers, "Release", $"{platform}-CoreCLR-R2R", true, new Dictionary<string, string> () { { "UseMonoRuntime", "false" }, { "PublishReadyToRun", "true" } });
var dict = new Dictionary<string, string> () {
{ "UseMonoRuntime", "false" },
{ "PublishReadyToRun", "true" },
{ "NoDSymUtil", "false" }, // off by default for macOS, but we want to test it, so enable it
};
Run (platform, runtimeIdentifiers, "Release", $"{platform}-CoreCLR-R2R", isTrimmed, dict);
}
Comment on lines +66 to 78
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above: isTrimmed is used as the supportsAssemblyInspection argument to Run, so the name doesn't reflect its behavior. Consider renaming it to match its purpose (or split into separate flags if both trimming and inspection need to be modeled).

Copilot uses AI. Check for mistakes.

// This test will build the SizeTestApp, and capture the resulting app size.
Expand Down
Loading
Loading