Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android.
</ItemGroup>

<!-- Make IlcCompile depend on the trimmer -->
<PropertyGroup>
<PropertyGroup Condition=" '$(_AndroidTypeMapImplementation)' != 'trimmable' ">
<IlcCompileDependsOn>
_AndroidBeforeIlcCompile;
SetupOSSpecificProps;
Expand All @@ -57,10 +57,22 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android.
_AndroidComputeIlcCompileInputs;
$(IlcCompileDependsOn)
</IlcCompileDependsOn>
<_AndroidBeforeIlcCompileDependsOn>_PrepareLinking</_AndroidBeforeIlcCompileDependsOn>
</PropertyGroup>
<!-- Trimmable typemap: skip ILLink, ILC handles trimming directly -->
<PropertyGroup Condition=" '$(_AndroidTypeMapImplementation)' == 'trimmable' ">
<IlcCompileDependsOn>
_AndroidBeforeIlcCompile;
SetupOSSpecificProps;
ComputeIlcCompileInputs;
_AndroidComputeIlcCompileInputs;
$(IlcCompileDependsOn)
</IlcCompileDependsOn>
<_AndroidBeforeIlcCompileDependsOn>_CreatePropertiesCache</_AndroidBeforeIlcCompileDependsOn>
</PropertyGroup>

<Target Name="_AndroidBeforeIlcCompile"
DependsOnTargets="_PrepareLinking"
DependsOnTargets="$(_AndroidBeforeIlcCompileDependsOn)"
BeforeTargets="SetupProperties">
<!-- Example settings from: https://github.com/jonathanpeppers/Android-NativeAOT/blob/ea69d122cdc7de67aa6a5db14b7e560763c63cdd/DotNet/libdotnet.targets -->
<PropertyGroup>
Expand Down Expand Up @@ -110,7 +122,10 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android.

<!-- We must ensure this is `false`, as it would interfere with statically linking libc++ -->
<LinkStandardCPlusPlusLibrary>false</LinkStandardCPlusPlusLibrary>
</PropertyGroup>

<!-- ILLink-specific settings: only when ILLink runs before ILC (non-trimmable path) -->
<PropertyGroup Condition=" '$(_AndroidTypeMapImplementation)' != 'trimmable' ">
<!-- Example settings from: https://github.com/xamarin/xamarin-macios/blob/c43d4ea40bc777969e3b158cf46446df292d8449/dotnet/targets/Xamarin.Shared.Sdk.targets#L541-L550 -->
<RunILLink>true</RunILLink>
<!--
Comment thread
sbomer marked this conversation as resolved.
Expand All @@ -127,7 +142,7 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android.
</Target>

<Target Name="_AndroidComputeIlcCompileInputs">
<PropertyGroup>
<PropertyGroup Condition=" '$(_AndroidTypeMapImplementation)' != 'trimmable' ">
<!-- Turn trimmer warnings back to original value -->
<SuppressTrimAnalysisWarnings>$(_OriginalSuppressTrimAnalysisWarnings)</SuppressTrimAnalysisWarnings>
</PropertyGroup>
Expand All @@ -137,26 +152,27 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android.
<LinkerArg Include="-Wl,--error-unresolved-symbols" />
<LinkerArg Include="-Wl,--no-undefined" />

<!-- Prevent ComputeLinkedFilesToPublish from removing trimmed assemblies from
ResolvedFileToPublish. We run ILLink before ILC (to support custom trimmer
steps), so the assemblies are already trimmed and must remain in
ResolvedFileToPublish for the outer build's _ResolveAssemblies target.
Context: https://github.com/dotnet/runtime/pull/124801 -->
<_IlcManagedInputAssemblies Remove="@(_IlcManagedInputAssemblies)" />

<!-- Required for [UnmanagedCallersOnly] to work inside this assembly -->
<UnmanagedEntryPointsAssembly Include="Microsoft.Android.Runtime.NativeAOT" />
<!-- Give ILLink's output to ILC -->
<IlcCompileInput Remove="@(IlcCompileInput)" />
<IlcCompileInput Include="$(IntermediateLinkDir)$(TargetName)$(TargetExt)" />
<_AndroidILLinkAssemblies Include="@(ManagedAssemblyToLink->'$(IntermediateLinkDir)%(Filename)%(Extension)')" Condition="Exists('$(IntermediateLinkDir)%(Filename)%(Extension)')" />
<IlcReference Remove="@(IlcReference)" />

<!-- The SDK's NativeCompile target uses _IlcManagedInputAssemblies to remove managed
assemblies from ResolvedFileToPublish after native compilation. Clear it so the
managed assemblies remain — the outer build needs them for _GenerateJavaStubs
and typemap generation. -->
<_IlcManagedInputAssemblies Remove="@(_IlcManagedInputAssemblies)" />
</ItemGroup>

<!-- ILLink path: ILLink already applied Android-specific trimming via custom steps.
Root everything for ILC so it doesn't trim further. Replace PrivateSdkAssemblies
with untrimmed originals since ILLink may have removed them. -->
<ItemGroup Condition=" '$(_AndroidTypeMapImplementation)' != 'trimmable' ">
<IlcReference Remove="@(PrivateSdkAssemblies->'$(IntermediateLinkDir)%(Filename)%(Extension)')" />
<IlcReference Include="@(PrivateSdkAssemblies)" />
<IlcReference Include="@(_AndroidILLinkAssemblies)" />
<!-- Root *everything* for ILC, as it's already trimmed -->
<_AndroidILLinkAssemblies Include="@(ManagedAssemblyToLink->'$(IntermediateLinkDir)%(Filename)%(Extension)')" Condition="Exists('$(IntermediateLinkDir)%(Filename)%(Extension)')" />
<TrimmerRootAssembly Include="@(_AndroidILLinkAssemblies->'%(Filename)')" Exclude="System.Private.CoreLib" TrimMode="All" />
<!-- Passes linked assemblies to outer MSBuild tasks/targets -->
<ResolvedFileToPublish Include="@(IlcCompileInput);@(_AndroidILLinkAssemblies)" RuntimeIdentifier="$(RuntimeIdentifier)" />
</ItemGroup>

<ItemGroup>

<!-- Satellite assemblies -->
<IlcSatelliteAssembly Include="$(_OuterIntermediateSatelliteAssembliesWithTargetPath)" />
Expand Down Expand Up @@ -265,9 +281,13 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android.
Restore the old scheduling so NativeCompile runs after ComputeResolvedFilesToPublishList
in the inner per-RID build.
-->
<PropertyGroup>
<_AndroidRunNativeCompileDependsOn Condition=" '$(_AndroidTypeMapImplementation)' != 'trimmable' ">_PreTrimmingFixLegacyDesignerUpdateItems;NativeCompile</_AndroidRunNativeCompileDependsOn>
<_AndroidRunNativeCompileDependsOn Condition=" '$(_AndroidTypeMapImplementation)' == 'trimmable' ">NativeCompile</_AndroidRunNativeCompileDependsOn>
</PropertyGroup>
<Target Name="_AndroidRunNativeCompile"
AfterTargets="ComputeResolvedFilesToPublishList"
DependsOnTargets="_PreTrimmingFixLegacyDesignerUpdateItems;NativeCompile" />
DependsOnTargets="$(_AndroidRunNativeCompileDependsOn)" />

<Target Name="_AndroidFixNativeLibraryFileName" AfterTargets="ComputeFilesToPublish">
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,21 @@ namespace Xamarin.Android.Build.Tests {
public class TrimmableTypeMapBuildTests : BaseTest {

[Test]
public void Build_WithTrimmableTypeMap_Succeeds ()
public void Build_WithTrimmableTypeMap_Succeeds ([Values] bool isRelease, [Values (AndroidRuntime.CoreCLR, AndroidRuntime.NativeAOT)] AndroidRuntime runtime)
{
var proj = new XamarinAndroidApplicationProject ();
proj.SetRuntime (AndroidRuntime.CoreCLR);
if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) {
return;
}

if (runtime == AndroidRuntime.CoreCLR && isRelease) {
Assert.Ignore ("CoreCLR + Release trimmable typemap not yet supported");
return;
}

var proj = new XamarinAndroidApplicationProject {
IsRelease = isRelease,
};
proj.SetRuntime (runtime);
proj.SetProperty ("_AndroidTypeMapImplementation", "trimmable");

// Full Build will fail downstream (manifest generation not yet implemented for trimmable path),
Expand All @@ -27,10 +38,27 @@ public void Build_WithTrimmableTypeMap_Succeeds ()
}

[Test]
public void Build_WithTrimmableTypeMap_IncrementalBuild ()
public void Build_WithTrimmableTypeMap_IncrementalBuild ([Values] bool isRelease, [Values (AndroidRuntime.CoreCLR, AndroidRuntime.NativeAOT)] AndroidRuntime runtime)
{
var proj = new XamarinAndroidApplicationProject ();
proj.SetRuntime (AndroidRuntime.CoreCLR);
if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) {
return;
}

if (runtime == AndroidRuntime.CoreCLR && isRelease) {
Assert.Ignore ("CoreCLR + Release trimmable typemap not yet supported");
return;
}

// https://github.com/dotnet/android/issues/11210
if (runtime == AndroidRuntime.NativeAOT) {
Assert.Ignore ("NativeAOT trimmable build does not yet generate JavaInteropRuntime.java");
return;
}

var proj = new XamarinAndroidApplicationProject {
IsRelease = isRelease,
};
proj.SetRuntime (runtime);
proj.SetProperty ("_AndroidTypeMapImplementation", "trimmable");

// Full Build will fail downstream (manifest generation not yet implemented for trimmable path),
Expand Down