Skip to content

Conversation

@jonathanpeppers
Copy link
Member

@jonathanpeppers jonathanpeppers commented Dec 8, 2020

I've noticed the _IncludeNativeSystemLibraries MSBuild target can
take 40ms because it is running this workaround:

<!-- HACK remove any unexpected runtime components -->
<FrameworkNativeLibrary
    Remove="@(ResolvedFileToPublish)"
    Condition="  $([System.Text.RegularExpressions.Regex]::IsMatch('%(FullPath)', '.*linux-.*'))  "
/>

The _IncludeNativeSystemLibraries also can be split up between
"legacy" Xamarin.Android and .NET 6. The .NET 6 version can simply
check the @(ResolvedFileToPublish) item group, as the other parts
support the intepreter, profiler, etc., which are not available in .NET
6 yet.

I created a new <ProcessNativeLibraries/> MSBuild task to simplify
the work in C#:

  • We can iterate over all .so files from @(ResolvedFileToPublish).
  • We can fix up libmonodroid.so as needed.
  • We can emit a warning if the ABI is unknown without using a Regex.
    It is possible for Linux .so files to be brought in from NuGet
    packages as discussed in: Use unix as the parent for the Android RID graph runtime#45927

The warning is a new alternate message for XA4301, such as:

warning XA4301: Cannot determine ABI of native library 'C:\src\xamarin-android\packages\sqlitepclraw.lib.e_sqlite3.linux\1.1.11\runtimes\linux-arm64\native\libe_sqlite3.so'. Remove the 'SQLitePCLRaw.lib.e_sqlite3.linux' NuGet package, or notify the library author.

As part of this change, .NET 6 will no longer need to do:

<PropertyGroup>
  <_Assemblies>@(_ResolvedFrameworkAssemblies)</_Assemblies>

So we can avoid creating a ~14K character string.

Results

Timing the project fromm the DotNetBuild(android.21-arm,false) test,
in a build with no changes:

Before:
40 ms  _IncludeNativeSystemLibraries              1 calls
After:
 4 ms  _IncludeNativeSystemLibraries              1 calls

This should save ~36ms from all .NET 6 builds.

@jonathanpeppers jonathanpeppers force-pushed the dotnet-includenativesystemlibraries branch from 783d16f to 896f410 Compare December 9, 2020 14:23
@jonathanpeppers jonathanpeppers marked this pull request as ready for review December 9, 2020 16:12
Include="@(ResolvedFileToPublish)"
Condition=" '%(Extension)' == '.so' and '%(Filename)' != 'libmono-android.debug' and '%(Filename)' != 'libmono-android.release' "
/>
</ItemGroup>
Copy link
Contributor

Choose a reason for hiding this comment

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

How are we going to handle _AndroidNativeLibraryForFastDev in the .net 6 world? This is used when we fast deploy most native libraries to the override directory rather than include them in the apk.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hopefully some test will fail here, as this was removed for .NET 6:

<_AndroidNativeLibraryForFastDev Condition=" '$(_InstantRunEnabled)' == 'True' And '$(AndroidUseDebugRuntime)' == 'True' And '$(_AndroidCheckedBuild)' == '' " Include="%(_TargetLibDir.Identity)\libxamarin-debug-app-helper.so" />

I'll need to add an equivalent for these.

Copy link
Member

Choose a reason for hiding this comment

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

libxamarin-debug-app-helper.so is in our runtime packs and will end up as a @(FrameworkNativeLibrary), and those items aren't fast deployed. Before fb727f0, these files were hard coded in the <BuildApk/> task.

It looks like only @(AndroidNativeLibrary) items are added to @(_AndroidNativeLibraryForFastDev): https://github.com/xamarin/monodroid/blob/27736a7ffc48d606ab45598f761e873f8572f46a/tools/msbuild/Xamarin.Android.Common.Debugging.targets#L224.

Maybe we should look at fast deploying @(FrameworkNativeLibrary) in a future PR? If we try to fast deploy both customer libs and framework libs we'll need to rework: https://github.com/xamarin/xamarin-android/blob/aaa37c3df94490ee9befb8381f4dd7aa18226355/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs#L589

As for the three $(_AndroidNativeLibraryForFastDev) items explicitly mentioned here, two files are used for native static code analysis (which I don't think we ever need to put into customer apps). The other one is for the interpreter, and I am not sure if that is available in .NET 6? I am not sure if we need to worry about any of these in a .NET 6 context?

Copy link
Contributor

Choose a reason for hiding this comment

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

certain native libs still need to be in the apk even when fast deploying. specifically monodroid.so and its immediate dependencies. This is because it is loaded as part of the runtime startup. So we can't just fast dev everything.

Copy link
Member Author

Choose a reason for hiding this comment

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

The latest changes shouldn't change the current logic for .NET 6, except the block:

<!-- HACK remove any unexpected runtime components -->
<FrameworkNativeLibrary
    Remove="@(ResolvedFileToPublish)"
    Condition="  $([System.Text.RegularExpressions.Regex]::IsMatch('%(FullPath)', '.*linux-.*'))  "
/>

Instead of silently ignoring, you get a XA4301 warning now.

The tests we have for Fast Deployment should be passing, so I don't think there is actually anything broken?

@jonathanpeppers jonathanpeppers marked this pull request as draft December 9, 2020 17:21
@jonathanpeppers
Copy link
Member Author

I was seeing an issue with SQLite NuGet packages, I think we'll need this addressed before we can finish this:

dotnet/sdk#14908

{0} - The file path</comment>
</data>
<data name="XA4301_ABI_RID" xml:space="preserve">
<value>Cannot determine ABI of native library '{0}'. The RuntimeIdentifier '{1}' does not target Android platforms.</value>
Copy link
Contributor

Choose a reason for hiding this comment

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

This message isn't actionable; what should the user do to fix this?

For that matter, what's it mean? This reads like two separate bits of information: we can't determine the ABI, a'la "normal" XA4301_ABI, in which case the library needs to be moved into a different directory (?), but what's that have to do with RuntimeIdentifier?

Copy link
Member Author

Choose a reason for hiding this comment

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

This message isn't actionable; what should the user do to fix this?

I don't think there is much they can do? I could log the name of the NuGet package it came from, and suggest they remove it?

See details here: dotnet/runtime#45927

Basically, if you add a NuGet package that is missing android-* RID for native libraries, the dotnet/sdk will potentially fall back to including linux-* native libraries. I tried to get them to change the behavior, but it is setup this way for other reasons.

Copy link
Member Author

Choose a reason for hiding this comment

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

Looking closer at the item metadata available:

image

We don't even have %(RuntimeIdentifier), so I changed the message to be:

warning XA4301: Cannot determine ABI of native library 'C:\src\xamarin-android\packages\sqlitepclraw.lib.e_sqlite3.linux\1.1.11\runtimes\linux-arm64\native\libe_sqlite3.so'. Remove the 'SQLitePCLRaw.lib.e_sqlite3.linux' NuGet package, or notify the library author.

Let me know if you have other ideas, thanks.


foreach (var library in InputLibraries) {
var abi = MonoAndroidHelper.GetNativeLibraryAbi (library);
if (string.IsNullOrEmpty (abi)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

…especially when I look at this: XA4301_ABI_RID won't be emitted if the lib is in a directory named after an ABI we know about, %(RuntimeIdentifier) be damned.

Presumably if %(RuntimeIdentifier) doesn't "match", it's unusable, e.g. trying to use a "desktop" Linux .so on Android is doomed, because libc.so is in the wrong location (among other things). Should we "fail early" and error, and check before calling MonoAndroidHelper.GetNativeLibraryAbi()? Or should we "fail at runtime" and warn -- as is done in this PR -- if the .so can't actually be used?

Which dovetails back with the warning message: if an unsupported %(RuntimeIdentifier) means "this has no chance of working", then the message needs to state that, and the fix is to remove the offending .so file. If it has a chance of working, then XA4301_ABI_RID should mirror XA4301_ABI, and mention that moving the .so into a directory with the ABI name will work.

As-is, the XA4301_ABI_RID warning means nothing.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't believe the %(RuntimeIdentifier) metadata would be present in user projects. It would only be present from NuGet packages.

Do you think the existing checks here needs to be changed?

https://github.com/xamarin/xamarin-android/blob/866085a611579ae270289751e46d7388c97f4251/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs#L286-L313

I think it will already check %(RuntimeIdentifier) before directory names.

I've noticed the `_IncludeNativeSystemLibraries` MSBuild target can
take 40ms because it is running this workaround:

    <!-- HACK remove any unexpected runtime components -->
    <FrameworkNativeLibrary
        Remove="@(ResolvedFileToPublish)"
        Condition="  $([System.Text.RegularExpressions.Regex]::IsMatch('%(FullPath)', '.*linux-.*'))  "
    />

The `_IncludeNativeSystemLibraries` also can be split up between
"legacy" Xamarin.Android and .NET 6. The .NET 6 version can simply
check the `@(ResolvedFileToPublish)` item group, as the other parts
support the intepreter, profiler, etc., which are not available in .NET
6 yet.

I created a new `<ProcessNativeLibraries/>` MSBuild task to simplify
the work in C#:

* We can iterate over all `.so` files from `@(ResolvedFileToPublish)`.
* We can fix up `libmonodroid.so` as needed.
* We can emit a warning if the ABI is unknown without using a `Regex`.
  It is possible for Linux `.so` files to be brought in from NuGet
  packages as discussed in: dotnet/runtime#45927

The warning is a new alternate message for XA4301, such as:

    warning XA4301: Cannot determine ABI of native library 'C:\src\xamarin-android\packages\sqlitepclraw.lib.e_sqlite3.linux\1.1.11\runtimes\linux-arm64\native\libe_sqlite3.so'. Remove the 'SQLitePCLRaw.lib.e_sqlite3.linux' NuGet package, or notify the library author.

As part of this change, .NET 6 will no longer need to do:

    <PropertyGroup>
      <_Assemblies>@(_ResolvedFrameworkAssemblies)</_Assemblies>

So we can avoid creating a ~14K character string.

~~ Results ~~

Timing the project fromm the `DotNetBuild(android.21-arm,false)` test,
in a build with no changes:

    Before:
    40 ms  _IncludeNativeSystemLibraries              1 calls
    After:
     4 ms  _IncludeNativeSystemLibraries              1 calls

This should save ~36ms from all .NET 6 builds.
@jonathanpeppers jonathanpeppers force-pushed the dotnet-includenativesystemlibraries branch from 5b575fc to fc0de47 Compare December 16, 2020 17:33
@jonpryor jonpryor merged commit 6034f6f into dotnet:master Dec 17, 2020
@jonathanpeppers jonathanpeppers deleted the dotnet-includenativesystemlibraries branch December 17, 2020 23:40
@github-actions github-actions bot locked and limited conversation to collaborators Jan 26, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants