Skip to content

Commit

Permalink
Dynamically Pack MVVM SourceGen project outputs
Browse files Browse the repository at this point in the history
Previously, static output path to the MVVM SourceGen assembly was used to pack the MVVM project.
This leads to error when OutputPath was updated dynamically when testing or in forks.

So, here, we'll update the build so that the SourceGen build outputs will be dynamically packed.
  • Loading branch information
Nirmal4G committed Jan 14, 2023
1 parent b4e2745 commit 5d893b8
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 23 deletions.
3 changes: 0 additions & 3 deletions eng/Toolkit.Common.props
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,4 @@
<!-- Use custom build logic for projects targeting multiple version of the Roslyn Compiler -->
<Import Project="Toolkit.CompilerTargeting.props" Condition="'$(IsCompilerTargeting)' == 'true'" />

<!-- Extends NuGet packaging with specific features required for packing toolkit projects -->
<Import Project="Toolkit.Packaging.props" Condition="'$(IsPackable)' != 'false'" />

</Project>
3 changes: 0 additions & 3 deletions eng/Toolkit.Common.targets
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,4 @@
</PropertyGroup>
</Target>

<!-- Extends NuGet packaging with specific features required for packing toolkit projects -->
<Import Project="Toolkit.Packaging.targets" Condition="'$(IsPackable)' == 'true'" />

</Project>
9 changes: 9 additions & 0 deletions eng/Toolkit.CustomAfterCommon.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project>

<!--
Supports getting common build outputs out of a project in a coherent and packable way.
This also makes it easy to pack the Roslyn source generator outputs to the NuGet package.
-->
<Import Project="Toolkit.GetBuildOutputs.targets" Condition="'$(IsPackable)' == 'false'" />

</Project>
53 changes: 53 additions & 0 deletions eng/Toolkit.GetBuildOutputs.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<Project>

<!-- We depend on these Common Targets that gathers various Build Outputs of the included project -->
<PropertyGroup>
<_GetBuildOutputsDependsOn>BuiltProjectOutputGroup;DocumentationProjectOutputGroup</_GetBuildOutputsDependsOn>
<_GetBuildOutputsDependsOn Condition="'$(IncludeSymbols)' != 'false'">$(_GetBuildOutputsDependsOn);DebugSymbolsProjectOutputGroup</_GetBuildOutputsDependsOn>
<_GetBuildOutputsDependsOn Condition="'$(IncludeSatelliteAssemblies)' != 'false'">$(_GetBuildOutputsDependsOn);SatelliteDllsProjectOutputGroup</_GetBuildOutputsDependsOn>
</PropertyGroup>

<!-- Check for 'TargetFramework' input before proceeding. -->
<Target Name="_CheckTargetFrameworkInput"
DependsOnTargets="_CheckForInvalidConfigurationAndPlatform"
Condition="'$(TargetFramework)' == ''">
<Error Code="NCTDEV01" Text="The 'GetBuildOutputsPerTarget' target is meant to output the build items per 'TargetFramework'. Please call the target with a non-empty 'TargetFramework'." />
</Target>

<!--
Gathers various Build Outputs from included Project per 'TargetFramework'.
This target is called in by the 'GetBuildOutputs' target to combine build outputs from all 'TargetFrameworks'.
-->
<Target Name="GetBuildOutputsPerTarget"
DependsOnTargets="_CheckTargetFrameworkInput;$(_GetBuildOutputsDependsOn)"
Returns="@(BuildOutputPerTarget)">
<ItemGroup>
<BuildOutputPerTarget Include="@(BuiltProjectOutputGroupOutput);@(DocumentationProjectOutputGroupOutput)" />
<BuildOutputPerTarget Include="@(DebugSymbolsProjectOutputGroupOutput)" Condition="'$(IncludeSymbols)' != 'false'" />
<BuildOutputPerTarget Include="@(SatelliteDllsProjectOutputGroupOutput)" Condition="'$(IncludeSatelliteAssemblies)' != 'false'" />
<BuildOutputPerTarget Update="@(BuildOutputPerTarget)" TargetFramework="$(TargetFramework)" />
</ItemGroup>

<ItemGroup Condition="'$(IsCompilerTargeting)' == 'true'">
<BuildOutputPerTarget Update="@(BuildOutputPerTarget)" IsCompilerExtension="true" />
<BuildOutputPerTarget Update="@(BuildOutputPerTarget)" TargetCompiler="$(TargetCompiler)" />
<BuildOutputPerTarget Update="@(BuildOutputPerTarget)" TargetLanguage="$(TargetLanguage)" />
</ItemGroup>
</Target>

<!--
Gathers various Build Outputs from this Project across 'TargetFrameworks'.
This target is called in the parent project to pack into a package.
-->
<Target Name="GetBuildOutputs"
DependsOnTargets="_GetTargetFrameworksOutput"
Returns="@(BuildOutput)">
<MSBuild
Projects="$(MSBuildProjectFullPath)"
Targets="GetBuildOutputsPerTarget"
Properties="TargetFramework=%(_TargetFrameworks.Identity)">
<Output TaskParameter="TargetOutputs" ItemName="BuildOutput" />
</MSBuild>
</Target>

</Project>
42 changes: 41 additions & 1 deletion eng/Toolkit.Packaging.targets
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@
Use 'TargetsForTfmSpecificContentInPackage' extensibility point to include custom TFM-specific assets in the package.
-->
<PropertyGroup>
<GenerateNuSpecDependsOn>_AddGlobalPackageFilesToNuGetPack;$(GenerateNuSpecDependsOn)</GenerateNuSpecDependsOn>
<GenerateNuSpecDependsOn>_GetNonReferencingProjectBuildOutputs;_AddGlobalPackageFilesToNuGetPack;$(GenerateNuSpecDependsOn)</GenerateNuSpecDependsOn>
<TargetsForTfmSpecificContentInPackage>_AddPackageFilesPerTargetFrameworkToNuGetPack</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>

<!--
=====================================================================================================================================================
Generic PackageFile support
=====================================================================================================================================================
-->

<!--
When the '$(IncludeContentInPack)' property is false, files specified via '@(None)', '@(Content)' items
are excluded from the NuGet package. Adding '@(PackageFile)' items directly to '%(_PackageFiles)' item
Expand Down Expand Up @@ -45,4 +51,38 @@
Text="The package file ('%(Identity)') is 'TargetFramework' specific and should include the value ('$(TargetFramework)') somewhere in the target path ('%(PackagePath)')." />
</Target>

<!--
=====================================================================================================================================================
Pack Non-Referencing Projects
=====================================================================================================================================================
-->

<!--
Pack non-referencing project's build outputs to the correct package folders depending on their intended usage.
The following target uses 'GenerateNuSpecDependsOn' extensibility point to pack the build assets
by using the custom 'GetBuildOutputs' target imported within the target project.
-->
<Target Name="_GetNonReferencingProjectBuildOutputs">
<!-- Get the build outputs of projects which don't reference the output assembly -->
<MSBuild
Projects="@(ProjectReference->WithMetadataValue('ReferenceOutputAssembly', 'false'))"
Targets="GetBuildOutputs">
<Output TaskParameter="TargetOutputs" ItemName="NonReferencingProjectBuildOutput" />
</MSBuild>
</Target>

<Target Name="_PackNonReferencingProjectBuildOutputs"
DependsOnTargets="_GetNonReferencingProjectBuildOutputs"
BeforeTargets="_AddGlobalPackageFilesToNuGetPack"
Condition="'$(PackNonReferencingProjects)' == 'true'">

<!-- Include the Build Outputs (also for each Custom target, like Roslyn analyzers and generators) in the package -->
<ItemGroup>
<PackageFile Include="@(NonReferencingProjectBuildOutput)">
<TargetPath Condition="'%(IsCompilerExtension)' == 'true'">$([System.IO.Path]::Combine('analyzers', 'dotnet', '%(TargetCompiler)', '%(TargetLanguage)'))</TargetPath>
<TargetPath Condition="'%(TargetPath)' == ''">$([System.IO.Path]::Combine('tools', '%(TargetFramework)'))</TargetPath>
</PackageFile>
</ItemGroup>
</Target>

</Project>
22 changes: 6 additions & 16 deletions src/CommunityToolkit.Mvvm/CommunityToolkit.Mvvm.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,12 @@
</ItemGroup>

<!--
Pack the source generator build outputs to the correct package folders (for each target Roslyn version)
for them to be used as analyzers. Roslyn compilers will automatically load the highest version compatible
with the Roslyn's version in the SDK.
HACK: The recommended way to pack is to get the build outputs using the project's built-in targets,
and include them using NuGet's Pack targets. However, due to a bug in v5 of those targets,
the outputs were not included in the package. So, including them directly via final
output path and building it first is the only way to ensure they are included.
Pack the source generator build outputs to the correct package folders for it to be used as an analyzer.
Roslyn compilers will automatically load the highest version compatible with it's version in the SDK.
This uses the Custom Packaging targets that the toolkit build infrastructure imports.
-->
<ItemGroup>
<!-- Roslyn v4.0 target -->
<PackageFile Include="..\CommunityToolkit.Mvvm.SourceGenerators\bin\$(Configuration)\netstandard2.0-roslyn4.0\CommunityToolkit.Mvvm.SourceGenerators.dll"
TargetPath="analyzers\dotnet\roslyn4.0\cs" />
<!-- Roslyn v4.3 target -->
<PackageFile Include="..\CommunityToolkit.Mvvm.SourceGenerators\bin\$(Configuration)\netstandard2.0-roslyn4.3\CommunityToolkit.Mvvm.SourceGenerators.dll"
TargetPath="analyzers\dotnet\roslyn4.3\cs" />
</ItemGroup>
<PropertyGroup>
<PackNonReferencingProjects>true</PackNonReferencingProjects>
</PropertyGroup>

</Project>
8 changes: 8 additions & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,12 @@
<PackageReference Include="PolySharp" Version="1.8.1" PrivateAssets="All" IncludeAssets="Analyzers;Build" />
</ItemGroup>

<!-- Hook various extension targets at the right place in MSBuild target graph using built-in extension points -->
<PropertyGroup>
<CustomAfterMicrosoftCommonTargets>$(BuildToolsDirectory)Toolkit.CustomAfterCommon.targets</CustomAfterMicrosoftCommonTargets>
</PropertyGroup>

<!-- Extends NuGet packaging with specific features required for packing toolkit projects -->
<Import Project="$(BuildToolsDirectory)Toolkit.Packaging.props" Condition="'$(IsPackable)' != 'false'" />

</Project>
3 changes: 3 additions & 0 deletions src/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@
<InternalsVisibleTo Update="@(InternalsVisibleTo)" PublicKey="$(AssemblySignPublicKey)" Condition="@(InternalsVisibleTo->Count()) != 0" />
</ItemGroup>

<!-- Extends NuGet packaging with specific features required for packing toolkit projects -->
<Import Project="$(BuildToolsDirectory)Toolkit.Packaging.targets" Condition="'$(IsPackable)' == 'true'" />

</Project>

0 comments on commit 5d893b8

Please sign in to comment.