[question] supporting multiple $(RuntimeIdentifiers) in Xamarin
See original GitHub issueThis might also need changes in dotnet/runtime, but I’ll file here since it is mostly build related.
In https://github.com/xamarin/xamarin-android/pull/4767, I have an implementation that would enable:
<RuntimeIdentifiers>android.21-arm;android.21-arm64;android.21-x86;android.21-x64</RuntimeIdentifiers>
And you could build the project via:
> dotnet build HelloAndroid.csproj -p:Configuration=Release
This produces an Android HelloAndroid.apk
file with contents such as:
assemblies\HelloAndroid.dll
assemblies\armeabi-v7a\System.Private.CoreLib.dll
assemblies\arm64-v8a\System.Private.CoreLib.dll
assemblies\x86\System.Private.CoreLib.dll
assemblies\x86_64\System.Private.CoreLib.dll
lib\armeabi-v7a\libmonosgen-2.0.so
lib\arm64-v8a\libmonosgen-2.0.so
lib\x86\libmonosgen-2.0.so
lib\x86_64\libmonosgen-2.0.so
You can install and run this .apk
file on Android devices/emulators of any of the 4 architectures.
What I actually had to do to make this work, brings up several questions.
Is the mechanism I’m using to process multiple $(RuntimeIdentifier)
the right idea?
At a high level, after Build
we do something like:
<ItemGroup>
<_RIDs Include="$(RuntimeIdentifiers)" />
</ItemGroup>
<MSBuild
Projects="$(MSBuildProjectFile)"
Targets="_ComputeFilesToPublishForRuntimeIdentifiers"
Properties="RuntimeIdentifier=%(_RIDs.Identity)">
<Output TaskParameter="TargetOutputs" ItemName="ResolvedFileToPublish" />
</MSBuild>
Against a new target we define:
<Target Name="_ComputeFilesToPublishForRuntimeIdentifiers"
DependsOnTargets="ResolveReferences;ComputeFilesToPublish"
Returns="@(ResolvedFileToPublish)">
</Target>
So in the example above with 4 architectures:
Build
occurs. Microsoft.Android.Sdk defaults$(AppendRuntimeIdentifierToOutputPath)
tofalse
. We only need a singleHelloAndroid.dll
andHelloAndroid.apk
file.- The
<MSBuild/>
task call runs for each RID. ILLink
will run 4 times (once per RID). We get linker output into 4 distinct directories such as$(IntermediateOutputPath)$(RuntimeIdentifier)\linked\
.--deterministic
is passed toILLink
, so almost all of the BCL assemblies are duplicate across architectures.- We have an MSBuild task that uses System.Reflection.Metadata to read the mvid of all assemblies. Any duplicates are removed, architecture-specific assemblies go in a sub-directory as described above.
Is this the right idea, in general? Is there a change in dotnet/sdk that could simplify this?
If we should deduplicate .NET assemblies, should the assemblies be identical across all runtime packs?
In a Debug
build (or ILLink
disabled), the deduplication does not work. The BCL assemblies in the runtime pack for each architecture are different. This results in a ~130MB .apk
file.
But if I compare them:
$ monodis packages/microsoft.netcore.app.runtime.android-arm/5.0.0-preview.6.20264.1/runtimes/android-arm/lib/net5.0/System.IO.dll --module
Module Table (1..1)
1: System.IO.dll 1 {1D745C86-CC08-41A8-ABA5-F221F7BAD20D}
$ monodis packages/microsoft.netcore.app.runtime.android-arm64/5.0.0-preview.6.20264.1/runtimes/android-arm64/lib/net5.0/System.IO.dll --module
Module Table (1..1)
1: System.IO.dll 1 {B582D0AC-1AE7-4E41-8DF0-6938725B4ADB}
It looks like only the mvid differs, and none of the IL differs. Is this intentional or are these packages built with /p:Deterministic=false
?
If a fix is needed for the runtime packs, I think this would be in dotnet/runtime.
Issue Analytics
- State:
- Created 3 years ago
- Comments:7 (7 by maintainers)
Top GitHub Comments
@jonathanpeppers I think we don’t have the deterministic option enabled for illinker process libraries during runtime pack build step and that’s what is causing the different outputs.
@jonathanpeppers I think it should be we cannot enable it as it exposes Cecil bug we didn’t resolve yet