Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions Documentation/guides/MSBuildBestPractices.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,63 @@ abbreviation could be used if the name is quite long, such as:
[msbuild-transforms]: https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-transforms
[msbuild-metadata]: https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-well-known-item-metadata

## Conditions

You can skip an MSBuild `<Target/>` or task with a `Condition` such
as:

```xml
<Target Name="Foo" Condition=" '$(Bar)' == 'true' ">
<!-- ... -->
</Target>
```

If you want to skip the target if an item group is empty, you might be
tempted to do:

```xml
<Target Name="Foo" Condition=" '@(MyItems)' != '' ">
<!-- ... -->
</Target>
```

If you think about what this does, it's doing a `string.Join()` on
`@(MyItems)` to compare if it matches an empty string. Luckily MSBuild
has a "fast path" for evaluating against an empty string, but it still
can generate the log message:

```
Target "Foo" skipped, due to false condition; ('@(MyItems)' != '') was evaluated as ('A;B;C' != '')
```

If `@(MyItems)` was 100 full paths to files, this would be a long log
message!

The solution is you should generally do this instead:

```xml
<Target Name="Foo" Condition=" '@(MyItems->Count())' != '0' ">
<!-- ... -->
</Target>
```

This causes MSBuild to always generate a reasonable log message:

```
Target "Foo" skipped, due to false condition; ('@(MyItems->Count())' != '0') was evaluated as ('100' != '0')
```

`->Count()` will return 0 even if the item group does not exist. See
the [MSBuild Documentation][itemfunctions] for details.

Some links around the logging behavior:

* https://github.com/dotnet/msbuild/issues/5315
* https://github.com/dotnet/msbuild/pull/5553
* https://github.com/dotnet/roslyn/pull/46445

[itemfunctions]: https://docs.microsoft.com/visualstudio/msbuild/item-functions

## Incremental Builds

The MSBuild Github repo has some [documentation][msbuild] on this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,12 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
</Target>

<Target Name="_FixupCustomViewsForAapt2"
Condition=" '$(_AndroidUseAapt2)' == 'True' And '@(_ProcessedCustomViews)' != '' ">
Condition=" '$(_AndroidUseAapt2)' == 'True' And '@(_ProcessedCustomViews->Count())' != '0' ">
<ItemGroup>
<_ItemsToFixup Include="@(_CompileResourcesInputs)" Condition=" '@(_ProcessedCustomViews->'%(Identity)')' == '%(Identity)' "/>
</ItemGroup>
<Aapt2Compile
Condition=" '$(AndroidUseAapt2)' == 'True' And '@(_ItemsToFixup)' != '' "
Condition=" '$(AndroidUseAapt2)' == 'True' And '@(_ItemsToFixup->Count())' != '0' "
ContinueOnError="$(DesignTimeBuild)"
DaemonMaxInstanceCount="$(Aapt2DaemonMaxInstanceCount)"
DaemonKeepInDomain="$(_Aapt2DaemonKeepInDomain)"
Expand All @@ -212,7 +212,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
ToolExe="$(Aapt2ToolExe)">
<Output TaskParameter="CompiledResourceFlatFiles" ItemName="_UpdatedFlatFiles" />
</Aapt2Compile>
<Touch Files="$(_AndroidResgenFlagFile)" AlwaysCreate="True" Condition=" '@(_UpdatedFlatFiles)' != '' " />
<Touch Files="$(_AndroidResgenFlagFile)" AlwaysCreate="True" Condition=" '@(_UpdatedFlatFiles->Count())' != '0' " />
</Target>

<Target Name="_CreateBaseApkWithAapt2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ It is shared between "legacy" binding projects and .NET 5 projects.

<Target Name="ExportJarToXml"
DependsOnTargets="$(ExportJarToXmlDependsOnTargets)"
Condition=" '$(UsingAndroidNETSdk)' != 'true' Or '@(InputJar)' != '' Or '@(EmbeddedJar)' != '' ">
Condition=" '$(UsingAndroidNETSdk)' != 'true' Or '@(InputJar->Count())' != '0' Or '@(EmbeddedJar->Count())' != '0' ">
<PropertyGroup>
<AllowUnsafeBlocks Condition=" '$(AllowUnsafeBlocks)' != 'true' ">true</AllowUnsafeBlocks>
</PropertyGroup>
</Target>

<Target Name="GenerateBindings"
Condition=" '$(UsingAndroidNETSdk)' != 'true' Or '@(InputJar)' != '' Or '@(EmbeddedJar)' != '' "
Condition=" '$(UsingAndroidNETSdk)' != 'true' Or '@(InputJar->Count())' != '0' Or '@(EmbeddedJar->Count())' != '0' "
DependsOnTargets="ExportJarToXml;_ResolveMonoAndroidSdks"
Inputs="$(ApiOutputFile);@(TransformFile);@(ReferencePath);@(ReferenceDependencyPaths);$(MSBuildAllProjects)"
Outputs="$(_GeneratorStampFile)">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ This file is only used by binding projects. .NET 5 can eventually use it, once `
</Target>

<Target Name="BuildDocumentation"
Condition=" '@(JavaDocIndex)' != '' And '$(_JavadocSupported)' == 'True' "
Condition=" '@(JavaDocIndex->Count())' != '0' And '$(_JavadocSupported)' == 'True' "
Inputs="@(JavaDocIndex);@(IntermediateAssembly->'$(IntermediateOutputPath)%(filename).xml')"
Outputs="@(IntermediateAssembly->'$(OutputPath)%(filename).xml')">
<MDoc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ This file is only used by "legacy" Xamarin.Android projects.
</PropertyGroup>

<Target Name="_PrepareWearApplication"
Condition=" $(AndroidApplication) And '@(_AppExtensionReference)' != '' "
Condition=" $(AndroidApplication) And '@(_AppExtensionReference->Count())' != '0' "
DependsOnTargets="_ValidateAndroidPackageProperties">
<ParseAndroidWearProjectAndManifest ProjectFiles="@(_AppExtensionReference)">
<Output TaskParameter="ApplicationManifestFile" PropertyName="BundledWearApplicationManifestFile" />
Expand Down
14 changes: 7 additions & 7 deletions src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,7 @@ because xbuild doesn't support framework reference assemblies.
Files="@(Content)"
Code="XA0101"
Text="%40(Content) build action is not supported"
Condition=" '@(Content)' != '' "
Condition=" '@(Content->Count())' != '0' "
/>
</Target>

Expand Down Expand Up @@ -1008,7 +1008,7 @@ because xbuild doesn't support framework reference assemblies.
<RemoveUnknownFiles Files="@(_AndroidResourceDest)" Directory="$(MonoAndroidResDirIntermediate)" RemoveDirectories="true">
<Output ItemName="_AndroidResourceDestRemovedFiles" TaskParameter="RemovedFiles" />
</RemoveUnknownFiles>
<Touch Files="$(_AndroidResFlagFile)" AlwaysCreate="True" Condition=" !Exists ('$(_AndroidResFlagFile)') Or '@(_ModifiedResources)' != '' Or '@(_AndroidResourceDestRemovedFiles)' != '' " />
<Touch Files="$(_AndroidResFlagFile)" AlwaysCreate="True" Condition=" !Exists ('$(_AndroidResFlagFile)') Or '@(_ModifiedResources->Count())' != '0' Or '@(_AndroidResourceDestRemovedFiles->Count())' != '0' " />
<ItemGroup>
<FileWrites Include="$(_AndroidResFlagFile)" />
</ItemGroup>
Expand All @@ -1032,7 +1032,7 @@ because xbuild doesn't support framework reference assemblies.
</Target>

<Target Name="_FindLayoutsForBinding"
Condition=" '$(Language)' == 'C#' And ('$(AndroidGenerateLayoutBindings)' == 'True' Or '@(AndroidBoundLayout)' != '') ">
Condition=" '$(Language)' == 'C#' And ('$(AndroidGenerateLayoutBindings)' == 'True' Or '@(AndroidBoundLayout->Count())' != '0') ">
<FindLayoutsToBind
GenerateLayoutBindings="$(AndroidGenerateLayoutBindings)"
BoundLayouts="@(AndroidBoundLayout)"
Expand Down Expand Up @@ -1068,18 +1068,18 @@ because xbuild doesn't support framework reference assemblies.
</Target>

<Target Name="_IncludeLayoutBindingSources" DependsOnTargets="_GenerateLayoutBindings" Condition=" '$(Language)' == 'C#' ">
<ItemGroup Condition=" '@(_LayoutForBinding)' != '' ">
<ItemGroup Condition=" '@(_LayoutForBinding->Count())' != '0' ">
<Compile Include="$(MSBuildThisFileDirectory)\LayoutBinding$(DefaultLanguageSourceExtension)" />
</ItemGroup>

<ItemGroup Condition=" '@(_LayoutForBinding)' != '' ">
<ItemGroup Condition=" '@(_LayoutForBinding->Count())' != '0' ">
<Compile Include="$(MonoAndroidCodeBehindDir)\%(_LayoutForBinding.LayoutBindingFileName)"
Condition="Exists ('$(MonoAndroidCodeBehindDir)\%(_LayoutForBinding.LayoutBindingFileName)')"/>
<FileWrites Include="$(MonoAndroidCodeBehindDir)\%(_LayoutForBinding.LayoutBindingFileName)"
Condition="Exists ('$(MonoAndroidCodeBehindDir)\%(_LayoutForBinding.LayoutBindingFileName)')"/>
</ItemGroup>

<ItemGroup Condition=" '@(_LayoutPartialClass)' != '' ">
<ItemGroup Condition=" '@(_LayoutPartialClass->Count())' != '0' ">
<Compile Include="$(MonoAndroidCodeBehindDir)\%(_LayoutPartialClass.LayoutPartialClassFileName)"
Condition="Exists ('$(MonoAndroidCodeBehindDir)\%(_LayoutPartialClass.LayoutPartialClassFileName)')"/>
<FileWrites Include="$(MonoAndroidCodeBehindDir)\%(_LayoutPartialClass.LayoutPartialClassFileName)"
Expand Down Expand Up @@ -1218,7 +1218,7 @@ because xbuild doesn't support framework reference assemblies.
</PropertyGroup>

<Target Name="UpdateAndroidInterfaceProxies"
Condition="@(AndroidInterfaceDescription) != ''"
Condition=" '@(AndroidInterfaceDescription->Count())' != '0' "
DependsOnTargets="$(CoreResolveReferencesDependsOn);_RunManagedAidlTool;_AddManagedAidlOutputsToCompile" />

<Target Name="_RunManagedAidlTool">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ This file is used by all project types, including binding projects.
</Target>

<Target Name="_CreateNativeLibraryArchive"
Condition=" '$(AndroidApplication)' != 'true' And '@(EmbeddedNativeLibrary)' != '' "
Condition=" '$(AndroidApplication)' != 'true' And '@(EmbeddedNativeLibrary->Count())' != '0' "
Inputs="@(EmbeddedNativeLibrary)"
Outputs="$(IntermediateOutputPath)__AndroidNativeLibraries__.zip">
<CreateNativeLibraryArchive
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
If $(_HasReferenceToSystemRuntime) is true, then the facades are going to be expanded anyway, so don't run this.
-->
<GetDependsOnNETStandard
Condition="'$(_HasReferenceToSystemRuntime)' != 'true' and '$(_IsXBuild)' != 'true' and '$(DependsOnNETStandard)' == '' and '@(_XACandidateNETStandardReferences)' != ''"
Condition="'$(_HasReferenceToSystemRuntime)' != 'true' and '$(_IsXBuild)' != 'true' and '$(DependsOnNETStandard)' == '' and '@(_XACandidateNETStandardReferences->Count())' != '0'"
References="@(_XACandidateNETStandardReferences)">
<Output TaskParameter="DependsOnNETStandard" PropertyName="_XADependsOnNETStandard" />
</GetDependsOnNETStandard>
Expand Down