Skip to content

Commit

Permalink
Simplify MSBuild logic in project files
Browse files Browse the repository at this point in the history
- Add necessary guard to check for pack.
- Remove redundant properties and values.
- Remove and adjust quotes in property functions.
- Use wildcards to generalize and reduce items declared.
  • Loading branch information
Nirmal4G committed Jan 2, 2023
1 parent aef6f77 commit 4271041
Show file tree
Hide file tree
Showing 12 changed files with 71 additions and 115 deletions.
1 change: 1 addition & 0 deletions CommunityToolkit.sln
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Root", "Root", "{CFA75BE0-5
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{CD16E790-7B7B-411E-9CE7-768E759CC22D}"
ProjectSection(SolutionItems) = preProject
eng\AssemblyInfo.Shared.cs = eng\AssemblyInfo.Shared.cs
eng\Sign-Package.ps1 = eng\Sign-Package.ps1
eng\SignClientSettings.json = eng\SignClientSettings.json
eng\Toolkit.Common.props = eng\Toolkit.Common.props
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<!-- Embed source files that are not tracked by the source control manager to the PDB -->
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<!-- Include PDB in the built .nupkg -->
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<AllowedOutputExtensionsInPackageBuildOutputFolder>.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
Expand Down
16 changes: 16 additions & 0 deletions eng/AssemblyInfo.Shared.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

// This file contains assembly and module attributes that is shared across projects.
// Include it in `Directory.Build.targets` near to all projects that need this file.

using System.Runtime.CompilerServices;

/*
Using `[module: SkipLocalsInit]` suppresses the .init flag for local variables for the entire module.
This doesn't affect the correctness of the methods in this assembly, as none of them are relying on
JIT ensuring that all local memory is zeroed out to work. Doing this can provide some minor
performance benefits, depending on the workload.
*/
[module: SkipLocalsInit]
12 changes: 9 additions & 3 deletions eng/Toolkit.Common.targets
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>

<PropertyGroup>
<PropertyGroup Condition="'$(IsPackable)' == 'true'">
<Company>Microsoft</Company>
<Authors>Microsoft</Authors>
<Product>.NET Community Toolkit</Product>
Expand All @@ -13,19 +13,25 @@
<PackageIcon>Icon.png</PackageIcon>
</PropertyGroup>

<PropertyGroup>
<PropertyGroup Condition="'$(IsPackable)' == 'true'">
<!-- TODO: Dynamically generate Title if one wasn't set -->
<Title Condition="'$(Title)' == ''">$(Product) Asset</Title>
<PackageTags Condition="'$(PackageTags)' != ''">$(CommonTags);$(PackageTags)</PackageTags>
<PackageTags Condition="'$(PackageTags)' == ''">$(CommonTags)</PackageTags>
</PropertyGroup>

<ItemGroup Condition="$(IsPackable)">
<ItemGroup Condition="'$(IsPackable)' == 'true'">
<None Pack="true" PackagePath="\" Visible="False" Include="$(BuildToolsDirectory)Icon.png" />
<None Pack="true" PackagePath="\" Visible="False" Include="$(RepositoryDirectory)License.md" />
<None Pack="true" PackagePath="\" Visible="False" Include="$(RepositoryDirectory)ThirdPartyNotices.txt" />
</ItemGroup>

<!-- Checked Version properties to use down the line -->
<PropertyGroup Condition="'$([MSBuild]::GetTargetFrameworkIdentifier($(TargetFramework)))' == '.NETCoreApp'">
<_ToolkitTargetFrameworkVersion>$([MSBuild]::GetTargetFrameworkVersion($(TargetFramework)))</_ToolkitTargetFrameworkVersion>
<_NET_6_OR_GREATER>$([MSBuild]::VersionGreaterThanOrEquals($(_ToolkitTargetFrameworkVersion), '6.0'))</_NET_6_OR_GREATER>
</PropertyGroup>

<!--
Add additional Pre-Processor symbols to $(DefineConstants) and $(FinalDefineConstants) in VB.
This overrides the same target in the .NET SDK. Since, that version has issues in DesignTime.
Expand Down
35 changes: 4 additions & 31 deletions eng/Toolkit.TextTemplates.targets
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,17 @@
</ItemGroup>

<ItemGroup>
<None Update="Generated\Guard.Comparable.Numeric.tt">
<None Update="**\*.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Guard.Comparable.Numeric.g.cs</LastGenOutput>
</None>
<None Update="Generated\Guard.Collection.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Guard.Collection.g.cs</LastGenOutput>
</None>
<None Update="Generated\ThrowHelper.Collection.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>ThrowHelper.Collection.g.cs</LastGenOutput>
</None>
<None Update="Generated\TypeInfo.ttinclude">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>TypeInfo.g.cs</LastGenOutput>
<LastGenOutput>%(Filename).g.cs</LastGenOutput>
</None>
</ItemGroup>

<ItemGroup>
<Compile Update="Generated\Guard.Comparable.Numeric.g.cs">
<DesignTime>True</DesignTime>
<Compile Update="**\*.g.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Guard.Comparable.Numeric.tt</DependentUpon>
</Compile>
<Compile Update="Generated\Guard.Collection.g.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Guard.Collection.tt</DependentUpon>
</Compile>
<Compile Update="Generated\ThrowHelper.Collection.g.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>ThrowHelper.Collection.tt</DependentUpon>
</Compile>
<Compile Update="Generated\TypeInfo.g.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>TypeInfo.ttinclude</DependentUpon>
<DependentUpon>$([System.IO.Path]::ChangeExtension(%(Filename), '.tt'))</DependentUpon>
</Compile>
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

<!-- On .NET Standard 2.0, the unit test project also needs access to internals -->
<ItemGroup>
<InternalsVisibleTo Include="CommunityToolkit.HighPerformance.UnitTests, PublicKey=$(AssemblySignPublicKey)" />
<InternalsVisibleTo Include="CommunityToolkit.HighPerformance.UnitTests" />
</ItemGroup>

<!-- .NET Standard 2.0 doesn't have the Span<T>, HashCode and ValueTask types -->
Expand Down
2 changes: 1 addition & 1 deletion src/CommunityToolkit.Mvvm/CommunityToolkit.Mvvm.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

<!-- Add the [InternalsVisibleTo] attribute for the test project -->
<ItemGroup>
<InternalsVisibleTo Include="CommunityToolkit.Mvvm.Internals.UnitTests, PublicKey=$(AssemblySignPublicKey)" />
<InternalsVisibleTo Include="CommunityToolkit.Mvvm.Internals.UnitTests" />
</ItemGroup>

<!--
Expand Down
48 changes: 24 additions & 24 deletions src/CommunityToolkit.Mvvm/CommunityToolkit.Mvvm.targets
Original file line number Diff line number Diff line change
@@ -1,88 +1,88 @@
<Project>

<!-- Get the analyzer from the CommunityToolkit.Mvvm NuGet package -->
<Target Name="MVVMToolkitGatherAnalyzers">
<Target Name="MVVMToolkit_GatherAnalyzers">
<ItemGroup>
<MVVMToolkitAnalyzer Include="@(Analyzer)" Condition="'%(Analyzer.NuGetPackageId)' == 'CommunityToolkit.Mvvm'" />
<MVVMToolkit_Analyzer Include="@(Analyzer)" Condition="'%(Analyzer.NuGetPackageId)' == 'CommunityToolkit.Mvvm'" />
</ItemGroup>
</Target>

<!-- Remove the analyzer if using Roslyn 3.x (incremental generators require Roslyn 4.x) -->
<Target Name="MVVMToolkitRemoveAnalyzersForRoslyn3"
<Target Name="MVVMToolkit_RemoveAnalyzers_WhenRoslynVersionIsNotSupported"
Condition="'$(CSharpCoreTargetsPath)' != ''"
AfterTargets="ResolvePackageDependenciesForBuild;ResolveNuGetPackageAssets"
DependsOnTargets="MVVMToolkitGatherAnalyzers">
DependsOnTargets="MVVMToolkit_GatherAnalyzers">

<!--
Use the CSharpCoreTargetsPath property to find the version of the compiler we are using. This is the same mechanism
MSBuild uses to find the compiler. We could check the assembly version for any compiler assembly (since they all have
the same version) but Microsoft.Build.Tasks.CodeAnalysis.dll is where MSBuild loads the compiler tasks from so if
someone is getting creative with msbuild tasks/targets this is the "most correct" assembly to check.
-->
<GetAssemblyIdentity AssemblyFiles="$([System.IO.Path]::Combine(`$([System.IO.Path]::GetDirectoryName($(CSharpCoreTargetsPath)))`,`Microsoft.Build.Tasks.CodeAnalysis.dll`))">
<Output TaskParameter="Assemblies" ItemName="MVVMToolkitCurrentCompilerAssemblyIdentity"/>
<GetAssemblyIdentity AssemblyFiles="$([System.IO.Path]::Combine($([System.IO.Path]::GetDirectoryName($(CSharpCoreTargetsPath))), 'Microsoft.Build.Tasks.CodeAnalysis.dll'))">
<Output TaskParameter="Assemblies" ItemName="MVVMToolkit_CurrentCompilerAssemblyIdentity"/>
</GetAssemblyIdentity>

<PropertyGroup>
<!-- Transform the resulting item from GetAssemblyIdentity into a property representing its assembly version -->
<MVVMToolkitCurrentCompilerVersion>@(MVVMToolkitCurrentCompilerAssemblyIdentity->'%(Version)')</MVVMToolkitCurrentCompilerVersion>
<MVVMToolkit_CurrentCompilerVersion>@(MVVMToolkit_CurrentCompilerAssemblyIdentity->%(Version))</MVVMToolkit_CurrentCompilerVersion>

<!-- The CurrentCompilerVersionIsNotNewEnough property can now be defined based on the Roslyn assembly version -->
<MVVMToolkitCurrentCompilerVersionIsNotNewEnough Condition="$([MSBuild]::VersionLessThan($(MVVMToolkitCurrentCompilerVersion), 4.0))">true</MVVMToolkitCurrentCompilerVersionIsNotNewEnough>
<!-- The CurrentCompilerIsNotNewEnough property can now be defined based on the Roslyn assembly version -->
<MVVMToolkit_CurrentCompilerIsNotNewEnough Condition="$([MSBuild]::VersionLessThan($(MVVMToolkit_CurrentCompilerVersion), 4.0))">true</MVVMToolkit_CurrentCompilerIsNotNewEnough>
</PropertyGroup>

<!-- If the Roslyn version is < 4.0, disable the source generators -->
<ItemGroup Condition ="'$(MVVMToolkitCurrentCompilerVersionIsNotNewEnough)' == 'true'">
<Analyzer Remove="@(MVVMToolkitAnalyzer)"/>
<ItemGroup Condition ="'$(MVVMToolkit_CurrentCompilerIsNotNewEnough)' == 'true'">
<Analyzer Remove="@(MVVMToolkit_Analyzer)"/>
</ItemGroup>

<!--
If the source generators are disabled, also emit a warning. This would've been produced by MSBuild itself as well, but
emitting this manually lets us customize the message to inform developers as to why exactly the generators have been
disabled, and that the rest of the MVVM Toolkit will still keep working as intended, just without additional features.
-->
<Warning Condition ="'$(MVVMToolkitCurrentCompilerVersionIsNotNewEnough)' == 'true'" Text="The MVVM Toolkit source generators have been disabled on the current configuration, as they need Roslyn 4.x in order to work. The MVVM Toolkit will work just fine, but features relying on the source generators will not be available."/>
<Warning Condition ="'$(MVVMToolkit_CurrentCompilerIsNotNewEnough)' == 'true'" Text="The MVVM Toolkit source generators have been disabled on the current configuration, as they need Roslyn 4.x in order to work. The MVVM Toolkit will work just fine, but features relying on the source generators will not be available."/>
</Target>

<!--
Manually remove duplicate analyzers if Roslyn component versioning is not supported (ie. if a legacy .csproj project is used).
Manually remove additional analyzers if Roslyn component versioning is not supported (ie. if a legacy .csproj project is used).
This target is only run if Roslyn 4.0 or greater is present, as otherwise all analyzers would have already been removed anyway.
-->
<Target Name="MVVMToolkitRemoveDuplicateAnalyzersWhenRoslynComponentVersioningIsNotSupported"
Condition="'$(MVVMToolkitCurrentCompilerVersionIsNotNewEnough)' != 'true' AND '$(SupportsRoslynComponentVersioning)' != 'true'"
<Target Name="MVVMToolkit_RemoveAdditionalAnalyzers_WhenRoslynComponentVersioningIsNotSupported"
Condition="'$(MVVMToolkit_CurrentCompilerIsNotNewEnough)' != 'true' AND '$(SupportsRoslynComponentVersioning)' != 'true'"
AfterTargets="ResolvePackageDependenciesForBuild;ResolveNuGetPackageAssets"
DependsOnTargets="MVVMToolkitRemoveAnalyzersForRoslyn3">
DependsOnTargets="MVVMToolkit_RemoveAnalyzers_WhenRoslynVersionIsNotSupported">

<!--
This switch manually implements Roslyn component versioning. That is, it checks the current version of Roslyn and
removes and removes all analyzers except the highest version that is supported. The fallback is just Roslyn 4.0.
-->
<PropertyGroup>
<MVVMToolkitSelectedRoslynAnalyzerDirectoryName Condition="$([MSBuild]::VersionGreaterThanOrEquals($(MVVMToolkitCurrentCompilerVersion), 4.3))">roslyn4.3</MVVMToolkitSelectedRoslynAnalyzerDirectoryName>
<MVVMToolkitSelectedRoslynAnalyzerDirectoryName Condition="'$(MVVMToolkitSelectedRoslynAnalyzerDirectoryName)' == ''">roslyn4.0</MVVMToolkitSelectedRoslynAnalyzerDirectoryName>
<MVVMToolkit_SelectedRoslynAnalyzerTarget Condition="$([MSBuild]::VersionGreaterThanOrEquals($(MVVMToolkit_CurrentCompilerVersion), 4.3))">roslyn4.3</MVVMToolkit_SelectedRoslynAnalyzerTarget>
<MVVMToolkit_SelectedRoslynAnalyzerTarget Condition="'$(MVVMToolkit_SelectedRoslynAnalyzerTarget)' == ''">roslyn4.0</MVVMToolkit_SelectedRoslynAnalyzerTarget>
</PropertyGroup>

<!--
This condition is a bit convoluted, but it's essentially just selecting all analyzers from the NuGet package that don't have the target Roslyn directory name in their full path.
For instance, if Roslyn 4.3 is the highest supported version, the target directory name will be "roslyn 4.3", and this condition will filter out all analyzers with a path such
as: "C:\...\.nuget\...\CommunityToolkit.Mvvm\analyzers\roslyn4.0\cs\CommunityToolkit.Mvvm". The [System.String]::Concat trick is used to achieve two things: we can't directly
as: "C:\...\.nuget\...\CommunityToolkit.Mvvm\analyzers\roslyn4.0\cs\CommunityToolkit.Mvvm". The [System.String]::Copy trick is used to achieve two things: we can't directly
invoke a property function (ie. Contains in this case) on a metadata item, so we need an intermediate string to invoke it on. We could also use [System.String]::new, but using
Concat is more efficient as it'll just skip the allocation entirely if one of the two inputs is an empty string, which is the case here.
Copy is more efficient (on .NET Framework runtime) as it'll just skip the allocation entirely.
-->
<ItemGroup>
<Analyzer Remove="@(MVVMToolkitAnalyzer)" Condition="!$([System.String]::Concat('', '%(MVVMToolkitAnalyzer.FullPath)').Contains('$(MVVMToolkitSelectedRoslynAnalyzerDirectoryName)'))"/>
<Analyzer Remove="@(MVVMToolkit_Analyzer)" Condition="!$([System.String]::Copy(%(MVVMToolkit_Analyzer.FullPath)).Contains($(MVVMToolkit_SelectedRoslynAnalyzerTarget)))"/>
</ItemGroup>
</Target>

<!-- Remove the analyzer if Roslyn is missing -->
<Target Name="MVVMToolkitRemoveAnalyzersForRosynNotFound"
<Target Name="MVVMToolkit_RemoveAnalyzers_WhenRoslynIsNotFound"
Condition="'$(CSharpCoreTargetsPath)' == ''"
AfterTargets="ResolvePackageDependenciesForBuild;ResolveNuGetPackageAssets"
DependsOnTargets="MVVMToolkitGatherAnalyzers">
DependsOnTargets="MVVMToolkit_GatherAnalyzers">

<!-- If no Roslyn assembly could be found, just remove the analyzer without emitting a warning -->
<ItemGroup>
<Analyzer Remove="@(MVVMToolkitAnalyzer)"/>
<Analyzer Remove="@(MVVMToolkit_Analyzer)"/>
</ItemGroup>
</Target>

Expand Down
7 changes: 2 additions & 5 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>

<Import Project="..\Directory.Build.props" />
<Import Project="..\$(MSBuildThisFile)" />

<PropertyGroup>
<IsPackable>true</IsPackable>
Expand All @@ -12,10 +12,7 @@

<!-- Include PolySharp to generate polyfills for all projects (on their .NET Standard 2.x targets) -->
<ItemGroup>
<PackageReference Include="PolySharp" Version="1.8.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>build; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="PolySharp" Version="1.8.1" PrivateAssets="All" IncludeAssets="Analyzers;Build" />
</ItemGroup>

</Project>
57 changes: 10 additions & 47 deletions src/Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -1,56 +1,19 @@
<Project>

<Import Project="..\Directory.Build.targets" />
<Import Project="..\$(MSBuildThisFile)" />

<!-- Define NETSTANDARD2_1_OR_GREATER for .NET Standard 2.1 targets and above -->
<PropertyGroup Condition="'$(TargetFramework)' == 'net6.0' OR '$(TargetFramework)' == 'net7.0'">
<DefineConstants>NETSTANDARD2_1_OR_GREATER</DefineConstants>
</PropertyGroup>

<!-- Configure trimming for projects on .NET 6 and above -->
<PropertyGroup Condition="'$(TargetFramework)' == 'net6.0' OR '$(TargetFramework)' == 'net7.0'">
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
<PropertyGroup Condition="'$(_NET_6_OR_GREATER)' == 'true'">
<IsTrimmable>true</IsTrimmable>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
<DefineConstants>NETSTANDARD2_1_OR_GREATER</DefineConstants>
</PropertyGroup>

<!--
The following target has been ported from TerraFX.Interop.Windows.
See: https://github.com/terrafx/terrafx.interop.windows.
Using [module: SkipLocalsInit] suppresses the .init flag for local variables for the entire module.
This doesn't affect the correctness of methods in this assembly, as none of them are relying on the
JIT ensuring that all local memory is zeroed out to work. Doing this can provide some minor
performance benefits, depending on the workload.
-->
<PropertyGroup>
<GeneratedSkipLocalsInitFile Condition="'$(GeneratedSkipLocalsInitFile)' == ''">$(IntermediateOutputPath)$(MSBuildProjectName).SkipLocalsInit.g.cs</GeneratedSkipLocalsInitFile>
<GeneratedSkipLocalsInitFileLines>
<![CDATA[//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
[module: global::System.Runtime.CompilerServices.SkipLocalsInitAttribute]]]>
</GeneratedSkipLocalsInitFileLines>
</PropertyGroup>

<Target Name="GenerateSkipLocalsInit"
BeforeTargets="BeforeCompile;CoreCompile"
DependsOnTargets="PrepareForBuild"
Condition="'$(Language)' == 'C#'"
Inputs="$(MSBuildAllProjects)"
Outputs="$(GeneratedSkipLocalsInitFile)">

<!-- Write the file with the attribute -->
<WriteLinesToFile Lines="$(GeneratedSkipLocalsInitFileLines)" Overwrite="true" WriteOnlyWhenDifferent="true" File="$(GeneratedSkipLocalsInitFile)" />
<ItemGroup>
<Compile Include="$(BuildToolsDirectory)AssemblyInfo.Shared.cs" LinkBase="Properties" Visible="False" />
</ItemGroup>

<!-- Include the generated file in the list of files to compile -->
<ItemGroup>
<Compile Include="$(GeneratedSkipLocalsInitFile)" />
</ItemGroup>
</Target>
<ItemGroup>
<InternalsVisibleTo Update="@(InternalsVisibleTo)" PublicKey="$(AssemblySignPublicKey)" Condition="@(InternalsVisibleTo->Count()) != 0" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion tests/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>

<Import Project="..\Directory.Build.props" />
<Import Project="..\$(MSBuildThisFile)" />

<PropertyGroup>
<IsPackable>false</IsPackable>
Expand Down
2 changes: 1 addition & 1 deletion tests/Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>

<Import Project="..\Directory.Build.targets" />
<Import Project="..\$(MSBuildThisFile)" />

<!-- MSTest v2 -->
<ItemGroup Condition="'$(IsTestProject)' == 'true'">
Expand Down

0 comments on commit 4271041

Please sign in to comment.