Skip to content

[One .NET] improve native library ABI detection at build time #5432

Closed
dotnet/android-tools
#121

Description

@jonathanpeppers

Context: #5386

To determine the Android ABI of native libraries, we currently:

  • Look for %(Abi) metadata
  • Look for a directory named: armeabi-v7a, arm64-v8a, x86, x86_64

This will not work in .NET 6, if the native library is coming from a NuGet package with a path such as:

packages\sqlitepclraw.lib.e_sqlite3.android\1.1.11\runtimes\android-arm64\native\libe_sqlite3.so

Instead of doing more inference with directory names, we should actually look at the contents of the .so file and:

  • Give a warning if it is not an Android library and ignore it.
  • Determine the ABI. If none found, emit a warning and ignore it.

We should still use the %(Abi) metadata if specified, for backwards compatibility.

We could try using the ElfSharp library to do this. We would need to make sure the code path is fast, or we have some mechanism for making incremental builds fast.

Useful links:

Activity

  1. added this to the One .NET milestone on Dec 16, 2020
  2. jonathanpeppers commented on Dec 18, 2020

    @jonathanpeppers
    MemberAuthor

    I wrote a sample program using ElfSharp: ElfSharpTest.zip

    It looks for the equivalent of readelf -d | grep NEEDED | grep ld-linux in about 47ms for 10 native libraries.

    However one native library breaks the pattern:

    $ readelf -d linux-x86/libe_sqlite3.so | grep NEEDED
     0x00000001 (NEEDED)                     Shared library: [libc.so.6]
    

    We may need to just check the file path and not use ElfSharp at all.

  3. mattleibow commented on May 20, 2021

    @mattleibow
    Member

    We could just add another rule and see if it came from a nuget and was in the runtimes, then look at the value after the android-.

  4. jonathanpeppers commented on May 20, 2021

    @jonathanpeppers
    MemberAuthor

    I just haven't gotten around to doing this yet, but I think the plan will be:

    • If the directory name is an Android RuntimeIdentifier, so you could put android-arm64/libfoo.so in an app
    • If the directory name two levels above is an Android RuntimeIdentifier, so NuGet packages will work.

    android-arm64/foo/libbar.so would also work in an app, but I think that would be fine.

  5. mattleibow commented on May 24, 2021

    @mattleibow
    Member

    I am looking at the targets here now and I think this code already works. When the packages restore, there is metadata on the .so files RuntimeIdentifier=android-arm64. There is also the code that detects and converts from this RID to the ABI in the ProcessNativeLibraries task in the _IncludeNativeSystemLibraries target.

    However, the files that this task uses is obtained via the _ResolveAssemblies target, which calls msbuild with the _ComputeFilesToPublishForRuntimeIdentifiers target. The result of this operation does not include the RID metadata.

    I got a bit of a hack to add it back...

        <Target Name="_IncludeNativeSystemLibrariesFixes" BeforeTargets="_IncludeNativeSystemLibraries">
            <ItemGroup>
                <_FixedResolvedFileToPublish
                    Include="@(ResolvedFileToPublish)"
                    Condition=" 
                        '%(ResolvedFileToPublish.Extension)' == '.so' and 
                        '%(ResolvedFileToPublish.NuGetPackageId)' != '' and 
                        '%(ResolvedFileToPublish.RuntimeIdentifier)' == '' and 
                        '%(ResolvedFileToPublish.PathInPackage)' != '' " />
                <ResolvedFileToPublish Remove="@(_FixedResolvedFileToPublish)" />
                <ResolvedFileToPublish Include="@(_FixedResolvedFileToPublish)">
                    <RuntimeIdentifier>$([System.Text.RegularExpressions.Regex]::Match('%(_FixedResolvedFileToPublish.PathInPackage)', 'runtimes/([^/]+)/native/.*').Groups[1].Value)</RuntimeIdentifier>
                </ResolvedFileToPublish>
            </ItemGroup>
        </Target>
  6. jonathanpeppers commented on May 24, 2021

    @jonathanpeppers
    MemberAuthor

    The dotnet/sdk creates @(ResolvedFileToPublish), and I've noticed that %(RuntimeIdentifier) is blank when the file is coming from a regular NuGet package.

    For some reason, it's there for "runtime" packs that are defined such as:

    https://github.com/xamarin/xamarin-android/blob/02ab8f723b6b8e327a3d8a6fd99192598ca94668/build-tools/create-packs/Microsoft.Android.Sdk.proj#L103-L114

    Native libraries from Microsoft.Android.Runtime.android-arm has RuntimeIdentifier=android-arm filled out for us.

  7. ghost locked as resolved and limited conversation to collaborators on Jun 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Area: App+Library BuildIssues when building Library projects or Application projects.

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions