Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Xamarin.Android.Build.Tasks] filter @(ReferencePath) for MonoAndroid assemblies #2934

Merged
merged 1 commit into from
Apr 8, 2019

Conversation

jonathanpeppers
Copy link
Member

@jonathanpeppers jonathanpeppers commented Apr 5, 2019

We have a couple MSBuild targets that need to only operate on
MonoAndroid assemblies:

  • _BuildAdditionalResourcesCache is the precursor to
    Xamarin.Build.Download
  • _ResolveLibraryProjectImports unzips
    __AndroidLibrariesProjects__.zip, .jar/.aar files, etc.

Both of these targets all looking at all assemblies, so we could
make a new item group @(_MonoAndroidReferencePath) and use this
instead. This would both allow the tasks inside these targets to
operate on less assemblies. It would also allow them to skip for
changes in NetStandard projects.

I added a new <FilterAssemblies/> MSBuild task to filter based on
the presence of this attribute in an assembly:

[assembly: System.Runtime.Versioning.TargetFrameworkAttribute ("MonoAndroid,Version=v8.1")]

MSBuild/Roslyn populate this attribute based on the
$(TargetFrameworkIdentifier) of the project.

One complication is that during design-time builds, some assemblies
may not exist. I made <FilterAssemblies/> just skip files in this
case--using the same logic that <ResolveLibraryProjectImports/>
uses. (I also fixed some wording/misspelling)

Results

I tested the Xamarin.Forms project in this repo.

Initial build:

Before:
  78 ms  _BuildAdditionalResourcesCache             1 calls
1678 ms  _ResolveLibraryProjectImports              1 calls
After:
  47 ms  FilterAssemblies                           1 calls
  23 ms  _BuildAdditionalResourcesCache             1 calls
1120 ms  _ResolveLibraryProjectImports              1 calls

Incremental build with XAML change:

Before:
 62 ms  _BuildAdditionalResourcesCache             1 calls
300 ms  _ResolveLibraryProjectImports              1 calls
After:
 62 ms  FilterAssemblies                           1 calls
  0 ms  _BuildAdditionalResourcesCache             1 calls
 16 ms  _ResolveLibraryProjectImports              1 calls

Note that during the incremental build, since only a NetStandard
assembly was updated the following targets are skipped:

_BuildAdditionalResourcesCache:
Skipping target "_BuildAdditionalResourcesCache" because all output files are up-to-date with respect to the input files.
...
_ResolveLibraryProjectImports:
Skipping target "_ResolveLibraryProjectImports" because all output files are up-to-date with respect to the input files.

Overall I would say this saves ~500ms on initial build, and ~250ms on
incremental builds.

@jonathanpeppers
Copy link
Member Author

Logs: monoandroidreferencepath.zip

@jonpryor
Copy link
Member

jonpryor commented Apr 5, 2019

I love the idea!

Alas, macOS PR Release Pipeline Build is failing:

error MSB4018: The "FilterAssemblies" task failed unexpectedly.
error MSB4018: System.IO.DirectoryNotFoundException: Could not find a part of the path "…/bin/TestRelease/temp/DesignerBeforeNuGetRestoreTrue/Library1/bin/Debug/Library1.dll".
error MSB4018:   at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.Boolean anonymous, System.IO.FileOptions options)
error MSB4018:   at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share)
error MSB4018:   at (wrapper remoting-invoke-with-check) System.IO.FileStream..ctor(string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare)
error MSB4018:   at System.IO.File.OpenRead (System.String path)
error MSB4018:   at Xamarin.Android.Tasks.FilterAssemblies.Execute ()
error MSB4018:   at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute ()
error MSB4018:   at Microsoft.Build.BackEnd.TaskBuilder.ExecuteInstantiatedTask (Microsoft.Build.BackEnd.ITaskExecutionHost taskExecutionHost, Microsoft.Build.BackEnd.Logging.TaskLoggingContext taskLoggingContext, Microsoft.Build.BackEnd.TaskHost taskHost, Microsoft.Build.BackEnd.ItemBucket bucket, Microsoft.Build.BackEnd.TaskExecutionMode howToExecuteTask)

… assemblies

We have a couple MSBuild targets that need to only operate on
`MonoAndroid` assemblies:

* `_BuildAdditionalResourcesCache` is the precursor to
  Xamarin.Build.Download
* `_ResolveLibraryProjectImports` unzips
  `__AndroidLibrariesProjects__.zip`, .jar/.aar files, etc.

Both of these targets all looking at *all* assemblies, so we could
make a new item group `@(_MonoAndroidReferencePath)` and use this
instead. This would both allow the tasks inside these targets to
operate on less assemblies. It would also allow them to skip for
changes in NetStandard projects.

I added a new `<FilterAssemblies/>` MSBuild task to filter based on
the presence of this attribute in an assembly:

    [assembly: System.Runtime.Versioning.TargetFrameworkAttribute ("MonoAndroid,Version=v8.1")]

MSBuild/Roslyn populate this attribute based on the
`$(TargetFrameworkIdentifier)` of the project.

One complication is that during design-time builds, some assemblies
may not exist. I made `<FilterAssemblies/>` just skip files in this
case--using the same logic that `<ResolveLibraryProjectImports/>`
uses. (I also fixed some wording/misspelling)

~~ Results ~~

I tested the Xamarin.Forms project in this repo.

Initial build:

    Before:
      78 ms  _BuildAdditionalResourcesCache             1 calls
    1678 ms  _ResolveLibraryProjectImports              1 calls
    After:
      47 ms  FilterAssemblies                           1 calls
      23 ms  _BuildAdditionalResourcesCache             1 calls
    1120 ms  _ResolveLibraryProjectImports              1 calls

Incremental build with XAML change:

    Before:
     62 ms  _BuildAdditionalResourcesCache             1 calls
    300 ms  _ResolveLibraryProjectImports              1 calls
    After:
     62 ms  FilterAssemblies                           1 calls
      0 ms  _BuildAdditionalResourcesCache             1 calls
     16 ms  _ResolveLibraryProjectImports              1 calls

Note that during the incremental build, since only a NetStandard
assembly was updated the following targets are skipped:

    _BuildAdditionalResourcesCache:
    Skipping target "_BuildAdditionalResourcesCache" because all output files are up-to-date with respect to the input files.
    ...
    _ResolveLibraryProjectImports:
    Skipping target "_ResolveLibraryProjectImports" because all output files are up-to-date with respect to the input files.

Overall I would say this saves ~500ms on initial build, and ~250ms on
incremental builds.
@dellis1972
Copy link
Contributor

Nice idea.

Just a head up this might impact this PR #2899 for the AndroidX support. Especially if we apply this to other tasks.

@jonathanpeppers
Copy link
Member Author

jonathanpeppers commented Apr 8, 2019

The failure on macOS is network-related failures:

image

@jonpryor jonpryor merged commit 5ec3e3a into dotnet:master Apr 8, 2019
@jonathanpeppers jonathanpeppers deleted the filterassemblies branch April 8, 2019 19:28
@erikpowa
Copy link
Contributor

erikpowa commented Apr 11, 2019

@jonathanpeppers

only MonoAndroid-profile assemblies can contain those
"special" embedded resources.

It's only true for "official" nuget packages and how they distribute libraries... nothing is stopping anyone to distribute embedded resources differently.

@jonathanpeppers
Copy link
Member Author

@erikpowa are you using a NetStandard library that contains __AndroidLibraryProjects__.zip or __AndroidNativeLibraries__.zip? I wouldn't recommend doing that, it is a private implementation detail that we might change.

@erikpowa
Copy link
Contributor

erikpowa commented Apr 11, 2019

@jonathanpeppers yeah, I have binding libraries's native stuph (only) in netstandard libs and packed targeting multiple monoandroid like this.

Guess forced to use MSBuild.Sdk.Extras for embedded resources aswell.

Damn multitargeting 😂

@jonathanpeppers
Copy link
Member Author

If you are using MSBuild.Sdk.Extras, you should be OK. You can put MonoAndroid90 or whichever in the list of $(TargetFrameworks), and then you have a MonoAndroid assembly.

This PR looks for:

[assembly: System.Runtime.Versioning.TargetFrameworkAttribute ("MonoAndroid,Version=v8.1")]

(v8.1 could be any number, it just looks before the ,)

jonathanpeppers added a commit to jonathanpeppers/XamarinComponents that referenced this pull request Jul 16, 2019
Fixes: dotnet/android#3343
Context: dotnet/android#3343 (comment)
Context: dotnet/android#2934

In Visual Studio 2019 16.1, we added some performance improvements in
Xamarin.Android.

In cases of .NET assemblies that:

* Do not have `[assembly: TargetFramework ("MonoAndroid")]`
* Have no reference to `Mono.Android.dll`

Unfortunately, these two Guava projects fit into this category! They
include `<EmbeddedJar/>` but otherwise have no markings at all that
would indicate they are Xamarin.Android assemblies.

Reading the source code for MSBuild, I found that including a single
`@(Compile)` item solves the issue:

https://github.com/microsoft/msbuild/blob/0cd0e92a7243088977d31b56626b56d6116de016/src/Tasks/Microsoft.Common.CurrentVersion.targets#L3341-L3344

    <ItemGroup Condition="'@(Compile)' != '' and '$(TargetFrameworkMonikerAssemblyAttributeText)' != ''">
      <Compile Include="$(TargetFrameworkMonikerAssemblyAttributesPath)"/>
    </ItemGroup>

As soon as I added an empty `*.cs` file to the projects,
`[assembly:TargetFramework]` appeared in the output assembly with the
necessary info.

This must be a weird corner case for MSBuild... I am not sure if there
is anything we can do on the Xamarin.Android side yet.
@github-actions github-actions bot locked and limited conversation to collaborators Jan 31, 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