Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] ignore .csproj.user changes (#5283)
Browse files Browse the repository at this point in the history
I noticed that changing the selected device or emulator in
Visual Studio 2019 16.8 on Windows was causing many MSBuild targets
to run again in the IDE.  The time taken was similar to a `Rebuild`!

Looking closer, I noticed:

	Building target "_CompileJava" completely.
	Input file "App42.csproj.user" is newer than output file "obj\Debug\_javac.stamp".

`.csproj.user` is where the IDE stores the selected device or
emulator.  The contents of the file:

	<?xml version="1.0" encoding="utf-8"?>
	<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
	  <PropertyGroup>
	    <SelectedDevice>pixel_2_pie_9_0_-_api_28</SelectedDevice>
	    <DefaultDevice>pixel_2_pie_9_0_-_api_28</DefaultDevice>
	  </PropertyGroup>
	</Project>

The reason this triggers many targets is that
[`*.csproj.user` is actually imported][0], which in turn means this
file is automatically included in `$(MSBuildAllProjects)`,
which is used by many `Inputs` of Xamarin.Android MSBuild targets.

I first tried editing `$(MSBuildAllProjects)`, but this property
appears to be readonly, since it is a built-in property in MSBuild.
Attempts at setting it were ignored.

To solve this, create a new `@(_AndroidMSBuildAllProjects)` item
group to be used instead that excludes the `.csproj.user` file.

I was able to reproduce this issue in a new test in
`IncrementalBuildTest`.

TODO:

After this goes in, there is one place in the xamarin/monodroid repo
that needs to use `@(_AndroidMSBuildAllProjects)` instead of
`$(MSBuildAllProjects)`.

[0]: https://github.com/dotnet/msbuild/blob/7452552ce911efdca6aea5a189c409f083db7bc7/src/Tasks/Microsoft.Common.CurrentVersion.targets#L31
  • Loading branch information
jonathanpeppers authored Dec 2, 2020
1 parent 113ffcc commit fd8aa17
Show file tree
Hide file tree
Showing 12 changed files with 69 additions and 19 deletions.
5 changes: 5 additions & 0 deletions Documentation/guides/MSBuildBestPractices.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,11 @@ will re-run the target completely. `$(MSBuildAllProjects)` is a list
of every MSBuild file imported during a build, MSBuild automatically
evaluates `$(MSBuildAllProjects)` since [MSBuild 16.0][allprojects].

> NOTE: You might consider using `@(_AndroidMSBuildAllProjects)`
> instead of `$(MSBuildAllProjects)` when working on the
> Xamarin.Android MSBuild targets. We have excluded the `*.csproj.user`
> file for performance reasons.
One pitfall, is this `_GenerateDocumentation` example *must* touch the
timestamps on all files in `Outputs` -- regardless if they were
actually changed. Otherwise, your target can get into a state where it
Expand Down
8 changes: 8 additions & 0 deletions Documentation/release-notes/5283.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
### Build and deployment performance

* [GitHub PR 5283](https://github.com/xamarin/xamarin-android/pull/5283):
Fixed an issue where changing the selected device or emulator in
the IDE would cause many parts of the build to run on an
incremental build. This reduced the overall build time from 5.526
seconds to 1.451 seconds for this scenario in a small test
project.
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
</Target>

<Target Name="_ConvertResourcesCases"
Inputs="$(MSBuildAllProjects);$(_AndroidBuildPropertiesCache);@(AndroidResource);@(_LibraryResourceDirectories->'%(StampFile)')"
Inputs="@(_AndroidMSBuildAllProjects);$(_AndroidBuildPropertiesCache);@(AndroidResource);@(_LibraryResourceDirectories->'%(StampFile)')"
Outputs="$(_AndroidStampDirectory)_ConvertResourcesCases.stamp"
DependsOnTargets="_CollectLibraryResourceDirectories;$(_BeforeConvertResourcesCases)"
>
Expand All @@ -116,7 +116,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
</Target>

<Target Name="_CompileResources"
Inputs="$(MSBuildAllProjects);$(_AndroidBuildPropertiesCache);@(_CompileResourcesInputs)"
Inputs="@(_AndroidMSBuildAllProjects);$(_AndroidBuildPropertiesCache);@(_CompileResourcesInputs)"
Outputs="@(_CompileResourcesInputs->'%(_ArchiveDirectory)%(_FlatFile)')"
DependsOnTargets="$(_BeforeCompileResources);_ConvertResourcesCases;_CalculateResourceFileName"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This file is only used by binding projects.
<UsingTask TaskName="Xamarin.Android.Tasks.ClassParse" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />

<Target Name="_ExportJarToXml"
Inputs="@(EmbeddedJar);@(EmbeddedReferenceJar);@(InputJar);@(ReferenceJar);$(MSBuildAllProjects)"
Inputs="@(EmbeddedJar);@(EmbeddedReferenceJar);@(InputJar);@(ReferenceJar);@(_AndroidMSBuildAllProjects)"
Outputs="$(ApiOutputFile)">
<ItemGroup>
<_AndroidDocumentationPath Include="@(JavaDocIndex->'%(RootDir)\%(Directory)')" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ It is shared between "legacy" binding projects and .NET 5 projects.
<Target Name="GenerateBindings"
Condition=" '$(UsingAndroidNETSdk)' != 'true' Or '@(InputJar->Count())' != '0' Or '@(EmbeddedJar->Count())' != '0' Or '@(LibraryProjectZip->Count())' != '0' "
DependsOnTargets="ExportJarToXml;_ResolveMonoAndroidSdks"
Inputs="$(ApiOutputFile);@(TransformFile);@(ReferencePath);@(ReferenceDependencyPaths);$(MSBuildAllProjects)"
Inputs="$(ApiOutputFile);@(TransformFile);@(ReferencePath);@(ReferenceDependencyPaths);@(_AndroidMSBuildAllProjects)"
Outputs="$(_GeneratorStampFile)">

<!-- Delete previous generated files if they still exist -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This file is only used by binding projects.
<UsingTask TaskName="Xamarin.Android.Tasks.JarToXml" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />

<Target Name="_ExportJarToXml"
Inputs="@(EmbeddedJar);@(EmbeddedReferenceJar);@(InputJar);@(ReferenceJar);$(MSBuildAllProjects)"
Inputs="@(EmbeddedJar);@(EmbeddedReferenceJar);@(InputJar);@(ReferenceJar);@(_AndroidMSBuildAllProjects)"
Outputs="$(ApiOutputFile)">
<JarToXml
JavaMaximumHeapSize="$(JavaMaximumHeapSize)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ Copyright (C) 2016 Xamarin. All rights reserved.

<Target Name="SetupDependenciesForDesigner"
DependsOnTargets="UpdateAndroidResources;_AdjustJavacVersionArguments;_GeneratePackageManagerJavaForDesigner;_GetMonoPlatformJarPath;_DetermineJavaLibrariesToCompile"
Inputs="$(MSBuildAllProjects);$(MonoPlatformJarPath);@(_JavaStubFiles);@(AndroidJavaSource)"
Inputs="@(_AndroidMSBuildAllProjects);$(MonoPlatformJarPath);@(_JavaStubFiles);@(AndroidJavaSource)"
Outputs="$(_AndroidStampDirectory)SetupDependenciesForDesigner.stamp">
<Javac
JavaPlatformJarPath="$(JavaPlatformJarPath)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ projects, these properties are set in Xamarin.Android.Legacy.targets.
<BuildDependsOn>
_ValidateLinkMode;
_CheckNonIdealConfigurations;
_SetupMSBuildAllProjects;
_SetupDesignTimeBuildForBuild;
_CategorizeAndroidLibraries;
_CreatePropertiesCache;
Expand Down Expand Up @@ -70,6 +71,7 @@ projects, these properties are set in Xamarin.Android.Legacy.targets.
<PropertyGroup Condition=" '$(AndroidApplication)' != 'True' ">
<BuildDependsOn>
_ValidateLinkMode;
_SetupMSBuildAllProjects;
_SetupDesignTimeBuildForBuild;
_CategorizeAndroidLibraries;
_CreatePropertiesCache;
Expand Down Expand Up @@ -115,6 +117,7 @@ projects, these properties are set in Xamarin.Android.Legacy.targets.
$([MSBuild]::Unescape($(CoreBuildDependsOn.Replace('IncrementalClean;', '$(_BeforeIncrementalClean);IncrementalClean;'))))
</CoreBuildDependsOn>
<CompileDependsOn>
_SetupMSBuildAllProjects;
_SetupDesignTimeBuildForCompile;
_AddAndroidDefines;
_IncludeLayoutBindingSources;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,29 @@ public void LinkAssembliesNoShrink ()
}
}

[Test]
public void CSProjUserFileChanges ()
{
var proj = new XamarinAndroidApplicationProject ();
var selectedDevice = "foo";
var csproj_user_file = $"{proj.ProjectName}.csproj.user";
proj.Sources.Add (new BuildItem.NoActionResource (csproj_user_file) {
TextContent = () => $"<Project><PropertyGroup><SelectedDevice>{selectedDevice}</SelectedDevice></PropertyGroup></Project>"
});
using (var b = CreateApkBuilder ()) {
Assert.IsTrue (b.Build (proj), "first build should have succeeded.");

// Simulates a different device/emulator selection in the IDE
selectedDevice = "bar";
proj.Touch (csproj_user_file);

Assert.IsTrue (b.Build (proj), "second build should have succeeded.");
b.Output.AssertTargetIsSkipped ("_CompileJava");
b.Output.AssertTargetIsSkipped ("_CompileToDalvik");
b.Output.AssertTargetIsSkipped ("_Sign");
}
}

[Test]
[NonParallelizable] // /restore can fail on Mac in parallel
public void ConvertCustomView ([Values (true, false)] bool useAapt2)
Expand Down
26 changes: 13 additions & 13 deletions src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ because xbuild doesn't support framework reference assemblies.
</Target>

<Target Name="_GenerateAndroidAssetsDir"
Inputs="$(MSBuildAllProjects);@(_AndroidResolvedAssets)"
Inputs="@(_AndroidMSBuildAllProjects);@(_AndroidResolvedAssets)"
Outputs="@(_AndroidAssetsDest)">
<MakeDir Directories="$(MonoAndroidAssetsDirIntermediate)" />
<Copy SourceFiles="@(_AndroidResolvedAssets)" DestinationFiles="@(_AndroidAssetsDest)" SkipUnchangedFiles="true" />
Expand Down Expand Up @@ -924,7 +924,7 @@ because xbuild doesn't support framework reference assemblies.
<Target Name="_BeforeManagedUpdateAndroidResgen">
<PropertyGroup>
<_ManagedUpdateAndroidResgenInputs>
$(MSBuildAllProjects);
@(_AndroidMSBuildAllProjects);
@(AndroidResource);
@(AndroidBoundLayout);
@(_MonoAndroidReferencePath);
Expand Down Expand Up @@ -1007,7 +1007,7 @@ because xbuild doesn't support framework reference assemblies.
</Target>

<Target Name="_GenerateAndroidResourceDir"
Inputs="$(MSBuildProjectFullPath);$(MSBuildAllProjects);@(_AndroidResolvedResources);$(_AndroidBuildPropertiesCache)"
Inputs="$(MSBuildProjectFullPath);@(_AndroidMSBuildAllProjects);@(_AndroidResolvedResources);$(_AndroidBuildPropertiesCache)"
Outputs="$(_AndroidResFlagFile)"
DependsOnTargets="$(_OnResolveMonoAndroidSdks)">
<CheckForInvalidResourceFileNames
Expand Down Expand Up @@ -1147,7 +1147,7 @@ because xbuild doesn't support framework reference assemblies.
_DefineBuildTargetAbis;
</_UpdateAndroidResgenDependsOnTargets>
<_UpdateAndroidResgenInputs>
$(MSBuildAllProjects);
@(_AndroidMSBuildAllProjects);
@(_AndroidResourceDest);
$(_AndroidBuildPropertiesCache);
$(ProjectAssetsFile);
Expand Down Expand Up @@ -1379,7 +1379,7 @@ because xbuild doesn't support framework reference assemblies.

<Target Name="_GenerateJavaStubs"
DependsOnTargets="$(_GenerateJavaStubsDependsOnTargets);$(BeforeGenerateAndroidManifest)"
Inputs="$(MSBuildAllProjects);@(_ResolvedUserMonoAndroidAssemblies);$(_AndroidManifestAbs);$(_AndroidBuildPropertiesCache)"
Inputs="@(_AndroidMSBuildAllProjects);@(_ResolvedUserMonoAndroidAssemblies);$(_AndroidManifestAbs);$(_AndroidBuildPropertiesCache)"
Outputs="$(_AndroidStampDirectory)_GenerateJavaStubs.stamp">

<PropertyGroup>
Expand Down Expand Up @@ -1432,7 +1432,7 @@ because xbuild doesn't support framework reference assemblies.

<Target Name="_ManifestMerger"
Condition=" '$(AndroidManifestMerger)' == 'manifestmerger.jar' "
Inputs="$(IntermediateOutputPath)AndroidManifest.xml;@(ExtractedManifestDocuments);$(_AndroidBuildPropertiesCache);$(MSBuildAllProjects)"
Inputs="$(IntermediateOutputPath)AndroidManifest.xml;@(ExtractedManifestDocuments);$(_AndroidBuildPropertiesCache);@(_AndroidMSBuildAllProjects)"
Outputs="$(IntermediateOutputPath)android\AndroidManifest.xml"
>
<ManifestMerger
Expand Down Expand Up @@ -1530,7 +1530,7 @@ because xbuild doesn't support framework reference assemblies.

<Target Name="_GeneratePackageManagerJava"
DependsOnTargets="$(_GeneratePackageManagerJavaDependsOn)"
Inputs="$(MSBuildAllProjects);$(_ResolvedUserAssembliesHashFile);$(MSBuildProjectFile);$(_AndroidBuildPropertiesCache);@(AndroidEnvironment);@(LibraryEnvironments)"
Inputs="@(_AndroidMSBuildAllProjects);$(_ResolvedUserAssembliesHashFile);$(MSBuildProjectFile);$(_AndroidBuildPropertiesCache);@(AndroidEnvironment);@(LibraryEnvironments)"
Outputs="$(_AndroidStampDirectory)_GeneratePackageManagerJava.stamp">
<!-- Create java needed for Mono runtime -->
<GeneratePackageManagerJava
Expand Down Expand Up @@ -1576,7 +1576,7 @@ because xbuild doesn't support framework reference assemblies.
<PropertyGroup>
<_CreateBaseApkInputs>
$(_CreateBaseApkInputs);
$(MSBuildAllProjects);
@(_AndroidMSBuildAllProjects);
$(IntermediateOutputPath)android\AndroidManifest.xml;
@(_ModifiedResources);
@(_AndroidAssetsDest);
Expand Down Expand Up @@ -1703,7 +1703,7 @@ because xbuild doesn't support framework reference assemblies.

<Target Name="_CompileJava"
DependsOnTargets="$(_CompileJavaDependsOnTargets)"
Inputs="$(MSBuildAllProjects);$(MonoPlatformJarPath);@(_JavaStubFiles);@(AndroidJavaSource)"
Inputs="@(_AndroidMSBuildAllProjects);$(MonoPlatformJarPath);@(_JavaStubFiles);@(AndroidJavaSource)"
Outputs="$(IntermediateOutputPath)_javac.stamp">

<!-- remove existing <Javac /> outputs, since *.class files and classes.zip could contain old files -->
Expand Down Expand Up @@ -1758,7 +1758,7 @@ because xbuild doesn't support framework reference assemblies.
_CalculateProguardConfigurationFiles;
</_CompileToDalvikDependsOnTargets>
<_CompileToDalvikInputs>
$(MSBuildAllProjects)
@(_AndroidMSBuildAllProjects)
;@(_JavaLibrariesToCompileForApp)
;@(AndroidExternalJavaLibrary)
;$(_AndroidIntermediateClassesZip)
Expand Down Expand Up @@ -1982,7 +1982,7 @@ because xbuild doesn't support framework reference assemblies.

<PropertyGroup>
<_BuildApkEmbedInputs>
$(MSBuildAllProjects)
@(_AndroidMSBuildAllProjects)
;$(_PackagedResources)
;@(_ShrunkAssemblies)
;@(AndroidNativeLibrary)
Expand Down Expand Up @@ -2285,7 +2285,7 @@ because xbuild doesn't support framework reference assemblies.
<Target Name="_PrepareForSign">
<PropertyGroup Condition=" '$(AndroidPackageFormat)' == 'aab' ">
<_SignInputs>
$(MSBuildAllProjects);
@(_AndroidMSBuildAllProjects);
$(_AndroidBuildPropertiesCache);
$(_AppBundleIntermediate);
</_SignInputs>
Expand All @@ -2295,7 +2295,7 @@ because xbuild doesn't support framework reference assemblies.
</PropertyGroup>
<PropertyGroup Condition=" '$(AndroidPackageFormat)' != 'aab' ">
<_SignInputs>
$(MSBuildAllProjects);
@(_AndroidMSBuildAllProjects);
$(_AndroidBuildPropertiesCache);
$(ApkFileIntermediate);
</_SignInputs>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ This file is used by all project types, including binding projects.
/>
</Target>

<Target Name="_SetupMSBuildAllProjects">
<ItemGroup>
<_AndroidMSBuildAllProjects Include="$(MSBuildAllProjects)" Exclude="$(MSBuildProjectFullPath).user" />
</ItemGroup>
</Target>

<Target Name="_SetupDesignTimeBuildForBuild" DependsOnTargets="_CreateStampDirectory">
<PropertyGroup>
<DesignTimeBuild Condition=" '$(DesignTimeBuild)' == '' ">false</DesignTimeBuild>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ projects. .NET 5 projects will not import this file.
<BuildDependsOn>
_ValidateLinkMode;
_CheckNonIdealConfigurations;
_SetupMSBuildAllProjects;
_SetupDesignTimeBuildForBuild;
_CreatePropertiesCache;
_CleanIntermediateIfNeeded;
Expand Down Expand Up @@ -58,6 +59,7 @@ projects. .NET 5 projects will not import this file.
<PropertyGroup Condition=" '$(AndroidApplication)' != 'True' And '$(_AndroidIsBindingProject)' != 'True' ">
<BuildDependsOn>
_ValidateLinkMode;
_SetupMSBuildAllProjects;
_SetupDesignTimeBuildForBuild;
_CreatePropertiesCache;
_CleanIntermediateIfNeeded;
Expand All @@ -82,6 +84,7 @@ projects. .NET 5 projects will not import this file.
$([MSBuild]::Unescape($(CoreBuildDependsOn.Replace('IncrementalClean;', '$(_BeforeIncrementalClean);IncrementalClean;'))))
</CoreBuildDependsOn>
<CompileDependsOn>
_SetupMSBuildAllProjects;
_SetupDesignTimeBuildForCompile;
_AddAndroidDefines;
_IncludeLayoutBindingSources;
Expand Down Expand Up @@ -162,13 +165,15 @@ projects. .NET 5 projects will not import this file.

<PropertyGroup Condition=" '$(_AndroidIsBindingProject)' == 'True' ">
<BuildDependsOn>
_SetupMSBuildAllProjects;
_SetupDesignTimeBuildForBuild;
AddLibraryJarsToBind;
$(BuildDependsOn);
BuildDocumentation;
</BuildDependsOn>

<CompileDependsOn>
_SetupMSBuildAllProjects;
_SetupDesignTimeBuildForCompile;
AddLibraryJarsToBind;
$(CompileDependsOn);
Expand Down

0 comments on commit fd8aa17

Please sign in to comment.