Skip to content

Commit 6687464

Browse files
[Xamarin.Android.Build.Tasks] filter @(ReferencePath) for MonoAndroid 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. ~~ 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.
1 parent d31cae1 commit 6687464

File tree

4 files changed

+83
-5
lines changed

4 files changed

+83
-5
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using Microsoft.Build.Framework;
2+
using Microsoft.Build.Utilities;
3+
using System.Collections.Generic;
4+
using System.IO;
5+
using System.Reflection.Metadata;
6+
using System.Reflection.PortableExecutable;
7+
8+
namespace Xamarin.Android.Tasks
9+
{
10+
/// <summary>
11+
/// Filters a set of assemblies based on a given TargetFrameworkIdentifier
12+
/// </summary>
13+
public class FilterAssemblies : Task
14+
{
15+
[Required]
16+
public string TargetFrameworkIdentifier { get; set; }
17+
18+
public ITaskItem [] InputAssemblies { get; set; }
19+
20+
[Output]
21+
public ITaskItem [] OutputAssemblies { get; set; }
22+
23+
public override bool Execute ()
24+
{
25+
if (InputAssemblies == null)
26+
return true;
27+
28+
var output = new List<ITaskItem> (InputAssemblies.Length);
29+
foreach (var assemblyItem in InputAssemblies) {
30+
using (var pe = new PEReader (File.OpenRead (assemblyItem.ItemSpec))) {
31+
var reader = pe.GetMetadataReader ();
32+
var assemblyDefinition = reader.GetAssemblyDefinition ();
33+
var targetFrameworkIdentifier = assemblyDefinition.GetTargetFrameworkIdentifier (reader);
34+
if (targetFrameworkIdentifier == TargetFrameworkIdentifier) {
35+
output.Add (assemblyItem);
36+
}
37+
}
38+
}
39+
OutputAssemblies = output.ToArray ();
40+
41+
return !Log.HasLoggedErrors;
42+
}
43+
}
44+
}

src/Xamarin.Android.Build.Tasks/Utilities/MetadataExtensions.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Reflection.Metadata;
1+
using System;
2+
using System.Reflection.Metadata;
23

34
namespace Xamarin.Android.Tasks
45
{
@@ -22,5 +23,31 @@ public static CustomAttributeValue<object> GetCustomAttributeArguments (this Cus
2223
{
2324
return attribute.DecodeValue (DummyCustomAttributeProvider.Instance);
2425
}
26+
27+
/// <summary>
28+
/// Returns the TargetFrameworkIdentifier of an assembly, or null if not found
29+
/// </summary>
30+
public static string GetTargetFrameworkIdentifier (this AssemblyDefinition assembly, MetadataReader reader)
31+
{
32+
foreach (var handle in assembly.GetCustomAttributes ()) {
33+
var attribute = reader.GetCustomAttribute (handle);
34+
var name = reader.GetCustomAttributeFullName (attribute);
35+
if (name == "System.Runtime.Versioning.TargetFrameworkAttribute") {
36+
var arguments = attribute.GetCustomAttributeArguments ();
37+
foreach (var p in arguments.FixedArguments) {
38+
// Of the form "MonoAndroid,Version=v8.1"
39+
var value = p.Value?.ToString ();
40+
if (!string.IsNullOrEmpty (value)) {
41+
int commaIndex = value.IndexOf (",", StringComparison.Ordinal);
42+
if (commaIndex != -1) {
43+
return value.Substring (0, commaIndex);
44+
}
45+
}
46+
}
47+
return null;
48+
}
49+
}
50+
return null;
51+
}
2552
}
2653
}

src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128
<Compile Include="Tasks\CheckForInvalidResourceFileNames.cs" />
129129
<Compile Include="Tasks\CollectNonEmptyDirectories.cs" />
130130
<Compile Include="Tasks\CollectPdbFiles.cs" />
131+
<Compile Include="Tasks\FilterAssemblies.cs" />
131132
<Compile Include="Tasks\GenerateLibraryResources.cs" />
132133
<Compile Include="Tasks\Generator.cs" />
133134
<Compile Include="Tasks\JarToXml.cs" />

src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
5858
<UsingTask TaskName="Xamarin.Android.Tasks.CreateAdditionalLibraryResourceCache" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
5959
<UsingTask TaskName="Xamarin.Android.Tasks.CreateMsymManifest" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
6060
<UsingTask TaskName="Xamarin.Android.Tasks.Crunch" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
61+
<UsingTask TaskName="Xamarin.Android.Tasks.FilterAssemblies" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
6162
<UsingTask TaskName="Xamarin.Android.Tasks.FindLayoutsToBind" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
6263
<UsingTask TaskName="Xamarin.Android.Tasks.GenerateLayoutBindings" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
6364
<UsingTask TaskName="Xamarin.Android.Tasks.GenerateLibraryResources" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
@@ -494,6 +495,11 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
494495
<_ReferenceDependencyPaths Include="@(ReferenceDependencyPaths)"
495496
Condition="'$(AndroidApplication)' == '' Or !$(AndroidApplication)"/>
496497
</ItemGroup>
498+
<FilterAssemblies
499+
TargetFrameworkIdentifier="MonoAndroid"
500+
InputAssemblies="@(_ReferencePath);@(_ReferenceDependencyPaths)">
501+
<Output TaskParameter="OutputAssemblies" ItemName="_MonoAndroidReferencePath" />
502+
</FilterAssemblies>
497503
</Target>
498504

499505
<PropertyGroup>
@@ -503,13 +509,13 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
503509
</PropertyGroup>
504510

505511
<Target Name="_BuildAdditionalResourcesCache"
506-
Inputs="@(_ReferencePath);@(_ReferenceDependencyPaths);$(MSBuildProjectFullPath);$(NugetPackagesConfig);$(_AndroidBuildPropertiesCache)"
512+
Inputs="@(_MonoAndroidReferencePath);$(MSBuildProjectFullPath);$(NugetPackagesConfig);$(_AndroidBuildPropertiesCache)"
507513
Outputs="$(_AndroidStampDirectory)_BuildAdditionalResourcesCache.stamp"
508514
DependsOnTargets="$(_BeforeBuildAdditionalResourcesCache)">
509515
<GetAdditionalResourcesFromAssemblies
510516
AndroidSdkDirectory="$(_AndroidSdkDirectory)"
511517
AndroidNdkDirectory="$(_AndroidNdkDirectory)"
512-
Assemblies="@(_ReferencePath);@(_ReferenceDependencyPaths)"
518+
Assemblies="@(_MonoAndroidReferencePath)"
513519
CacheFile="$(_AndroidResourcePathsCache)"
514520
YieldDuringToolExecution="$(YieldDuringToolExecution)"
515521
DesignTimeBuild="$(DesignTimeBuild)"
@@ -1389,13 +1395,13 @@ because xbuild doesn't support framework reference assemblies.
13891395
</Target>
13901396

13911397
<Target Name="_ResolveLibraryProjectImports"
1392-
Inputs="$(ProjectAssetsFile);$(MSBuildProjectFullPath);@(_ReferencePath);@(_ReferenceDependencyPaths);$(_AndroidBuildPropertiesCache)"
1398+
Inputs="$(ProjectAssetsFile);$(MSBuildProjectFullPath);@(_MonoAndroidReferencePath);$(_AndroidBuildPropertiesCache)"
13931399
Outputs="$(_AndroidStampDirectory)_ResolveLibraryProjectImports.stamp">
13941400
<ResolveLibraryProjectImports
13951401
ContinueOnError="$(DesignTimeBuild)"
13961402
CacheFile="$(_AndroidLibraryProjectImportsCache)"
13971403
DesignTimeBuild="$(DesignTimeBuild)"
1398-
Assemblies="@(_ReferencePath);@(_ReferenceDependencyPaths)"
1404+
Assemblies="@(_MonoAndroidReferencePath)"
13991405
AarLibraries="@(AndroidAarLibrary)"
14001406
ImportsDirectory="$(_LibraryProjectImportsDirectoryName)"
14011407
NativeImportsDirectory="$(_NativeLibraryImportsDirectoryName)"

0 commit comments

Comments
 (0)