Android framework version
net10.0-android (Preview)
Affected platform version
.NET 10
Description
This is just a tracking issue for fully enabling R2R builds ie with marshalled methods enabled.
This should be similar to how Mono AOT tasks are run.
Investigation
SDK limitations
There are several limitations with running ReadyToRun build tasks in the same fashion as Mono AOT compiler tasks:
- ReadyToRun compilation requires publishing i.e.,
dotnet publish which is different from how Android SDK handles AOT compilation with Mono especially with universal apps enabling AOT compilation for all supported abis/rids as part of regular build ie dotnet build. However, ReadyToRun and NativeAOT deployments are designed to be publish-only deployments and setting the properties which enable them PublishAot=true PublishReadyToRun=true do not have any effect if the app is built with dotnet build. This is true on both desktop and iOS, triggering NativeAOT builds only happens with dotnet publish , dotnet build uses "regular" default runtimes/builds -> on desktop: CoreCLR is used, on iOS: Mono is used. For reference here is how it is handled in iOS SDK: https://github.com/dotnet/macios/blob/d936f060894801df6350b7f3fb1a42e02d74ced4/dotnet/targets/Xamarin.Shared.Sdk.props#L39
- When publishing with ReadyToRun enabled SDK required RID to be specified early on in the SDK, throwing with:
dotnet/sdk/10.0.100-preview.4.25180.3/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.RuntimeIdentifierInference.targets(219,5): error NETSDK1191: A runtime identifier for the property 'PublishReadyToRun' couldn't be inferred. Specify a rid explicitly
Tentative list of possible approaches is provided below:
Approach 1
In the first Android SDK inner build (that runs ILLink), ReadyToRun targets must not run if we want to have postprocessing of assemblies as Mono.Cecil cannot modify mixed-mode assemblies. Disabling ReadyToRun targets can be accomplished by explicitly passing PublishReadyToRun=false as an additional property which would overwrite globally set PublishReadyToRun value. For example:
<PropertyGroup>
<!-- for some reason previous approach disabbles mono from running its AOT tasks.. --> <_PublishReadyToRunForInnerBuild Condition="'$(PublishReadyToRun)' == 'true'">PublishReadyToRun=false</_PublishReadyToRunForInnerBuild> </PropertyGroup>
</PropertyGroup>
<ItemGroup>
<_ProjectToBuild Include="$(MSBuildProjectFile)" AdditionalProperties="RuntimeIdentifier=%(_RIDs.Identity);$(_AdditionalProperties);$(_PublishReadyToRunForInnerBuild)" />
</ItemGroup>
<MSBuild Condition=" '$(DesignTimeBuild)' != 'true' " Projects="@(_ProjectToBuild)" BuildInParallel="$(_AndroidBuildRuntimeIdentifiersInParallel)" Targets="_ComputeFilesToPublishForRuntimeIdentifiers">
<Output TaskParameter="TargetOutputs" ItemName="ResolvedFileToPublish" />
</MSBuild>
Furthermore, ReadyToRun targets could run in a separate inner build which happens after _GenerateJavaStubs, similarly to Mono AOT compilation with the following changes, if it runs in the second inner build:
- We need to accommodate all required properties/items being properly resolved and set, like resolving crossgen packages, etc
- after it runs we need to rerun the majority of
_ResolveAssemblies which populates internally used MSBuild items and their metadata, since R2R targets are generating new assemblies. This needs to be handled with care as the targets running after AOT compilation rely on the fact internal MSBuild items are configured correctly.
For reference, here is a workaround which does not use the inner build for R2R compiler, but makes it work with marshalled methods generation: ivanpovazan/android@772de8e...36491ac
Approach 2
Move _GenerateJavaStubs into the first inner build, just after ILLink and before R2R MSBuild targets. This is probably more involved work considering dependencies of _GenerateJavaStubs but should be much more straight-forward in regard to running R2R targets at the right time of the build.
Final note
Once a solution is implemented marshal method generation should be reenabled with R2R builds:
|
<AndroidEnableMarshalMethods Condition=" '$(AndroidEnableMarshalMethods)' == '' and '$(_AndroidRuntime)' != 'NativeAOT' and '$(PublishReadyToRun)' != 'true' ">True</AndroidEnableMarshalMethods> |
|
<!-- NOTE: temporarily disable for NativeAOT for now, to get build passing --> |
|
<AndroidEnableMarshalMethods Condition=" '$(AndroidEnableMarshalMethods)' == '' and ('$(_AndroidRuntime)' == 'NativeAOT' or '$(PublishReadyToRun)' == 'true') ">False</AndroidEnableMarshalMethods> |
Android framework version
net10.0-android (Preview)
Affected platform version
.NET 10
Description
This is just a tracking issue for fully enabling R2R builds ie with marshalled methods enabled.
This should be similar to how Mono AOT tasks are run.
Investigation
SDK limitations
There are several limitations with running ReadyToRun build tasks in the same fashion as Mono AOT compiler tasks:
dotnet publishwhich is different from how Android SDK handles AOT compilation with Mono especially with universal apps enabling AOT compilation for all supported abis/rids as part of regular build iedotnet build. However, ReadyToRun and NativeAOT deployments are designed to be publish-only deployments and setting the properties which enable themPublishAot=truePublishReadyToRun=truedo not have any effect if the app is built withdotnet build. This is true on both desktop and iOS, triggering NativeAOT builds only happens with dotnet publish , dotnet build uses "regular" default runtimes/builds -> on desktop: CoreCLR is used, on iOS: Mono is used. For reference here is how it is handled in iOS SDK: https://github.com/dotnet/macios/blob/d936f060894801df6350b7f3fb1a42e02d74ced4/dotnet/targets/Xamarin.Shared.Sdk.props#L39Tentative list of possible approaches is provided below:
Approach 1
In the first Android SDK inner build (that runs ILLink), ReadyToRun targets must not run if we want to have postprocessing of assemblies as
Mono.Cecilcannot modify mixed-mode assemblies. Disabling ReadyToRun targets can be accomplished by explicitly passingPublishReadyToRun=falseas an additional property which would overwrite globally set PublishReadyToRun value. For example:Furthermore, ReadyToRun targets could run in a separate inner build which happens after
_GenerateJavaStubs, similarly to Mono AOT compilation with the following changes, if it runs in the second inner build:_ResolveAssemblieswhich populates internally used MSBuild items and their metadata, since R2R targets are generating new assemblies. This needs to be handled with care as the targets running after AOT compilation rely on the fact internal MSBuild items are configured correctly.For reference, here is a workaround which does not use the inner build for R2R compiler, but makes it work with marshalled methods generation: ivanpovazan/android@772de8e...36491ac
Approach 2
Move
_GenerateJavaStubsinto the first inner build, just after ILLink and before R2R MSBuild targets. This is probably more involved work considering dependencies of_GenerateJavaStubsbut should be much more straight-forward in regard to running R2R targets at the right time of the build.Final note
Once a solution is implemented marshal method generation should be reenabled with R2R builds:
android/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
Lines 345 to 347 in db84b3d