Skip to content

Commit a1962c0

Browse files
committed
Dynamically Pack MVVM SourceGen project outputs
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.
1 parent a1fcd7e commit a1962c0

File tree

4 files changed

+76
-11
lines changed

4 files changed

+76
-11
lines changed

CommunityToolkit.Mvvm.SourceGenerators/CommunityToolkit.Mvvm.SourceGenerators.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,6 @@
2626
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" PrivateAssets="All" Pack="false" />
2727
</ItemGroup>
2828

29+
<Import Project="$(BuildToolsDirectory)Community.Toolkit.GetBuildOutputs.targets" />
30+
2931
</Project>

CommunityToolkit.Mvvm/CommunityToolkit.Mvvm.csproj

+26-10
Original file line numberDiff line numberDiff line change
@@ -50,22 +50,38 @@
5050
</ItemGroup>
5151

5252
<!-- Source generator project reference for packing -->
53-
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
53+
<ItemGroup>
5454
<ProjectReference Include="..\CommunityToolkit.Mvvm.SourceGenerators\CommunityToolkit.Mvvm.SourceGenerators.csproj"
5555
ReferenceOutputAssembly="false" />
5656
</ItemGroup>
5757

58+
<!-- Use 'GenerateNuSpecDependsOn' extensibility point to include source generator assets in the package -->
59+
<PropertyGroup>
60+
<GenerateNuSpecDependsOn>GetSourceGenBuildOutputs</GenerateNuSpecDependsOn>
61+
</PropertyGroup>
62+
5863
<!--
5964
Pack the source generator build outputs to the correct package folder for it to be used as an analyzer.
60-
61-
HACK: The recommended way to pack is to get the build outputs using the project's built-in targets,
62-
and include them using NuGet's Pack targets. However, due to a bug in v5 of those targets,
63-
the outputs were not included in the package. So, including them directly via final
64-
output path and building it first is the only way to ensure they are included.
65+
The following target uses 'GenerateNuSpecDependsOn' extensibility point to pack the build assets
66+
by using the custom 'GetBuildOutputs' target imported within the target project.
6567
-->
66-
<ItemGroup>
67-
<PackageFile Include="..\CommunityToolkit.Mvvm.SourceGenerators\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.SourceGenerators.dll"
68-
TargetPath="analyzers\dotnet\roslyn4.0\cs" />
69-
</ItemGroup>
68+
<Target Name="GetSourceGenBuildOutputs"
69+
BeforeTargets="_AddGlobalPackageFilesToNuGetPack"
70+
AfterTargets="_CalculateInputsOutputsForPack">
71+
72+
<!-- Get the build outputs of the source generator project -->
73+
<MSBuild
74+
Projects="@(ProjectReference->WithMetadataValue('ReferenceOutputAssembly', 'false'))"
75+
Targets="GetBuildOutputs">
76+
<Output TaskParameter="TargetOutputs" ItemName="SourceGenBuildOutput" />
77+
</MSBuild>
78+
79+
<ItemGroup>
80+
<!-- Include the Build Outputs in the package via 'PackageFile' item -->
81+
<PackageFile Include="@(SourceGenBuildOutput)" TargetPath="analyzers\dotnet\roslyn4.0\cs" />
82+
<!-- Use the 'FinalOutputPath' metadata to mark the inputs thus enabling incremental builds -->
83+
<NuGetPackInput Include="@(SourceGenBuildOutput->'%(FinalOutputPath)')" />
84+
</ItemGroup>
85+
</Target>
7086

7187
</Project>

build/Community.Toolkit.Common.targets

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
Use 'TargetsForTfmSpecificContentInPackage' extensibility point to include custom TFM-specific assets in the package.
2323
-->
2424
<PropertyGroup>
25-
<GenerateNuSpecDependsOn>_AddGlobalPackageFilesToNuGetPack</GenerateNuSpecDependsOn>
25+
<GenerateNuSpecDependsOn>_AddGlobalPackageFilesToNuGetPack;$(GenerateNuSpecDependsOn)</GenerateNuSpecDependsOn>
2626
<TargetsForTfmSpecificContentInPackage>_AddPackageFilesPerTargetFrameworkToNuGetPack</TargetsForTfmSpecificContentInPackage>
2727
</PropertyGroup>
2828

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<Project>
2+
3+
<!-- We depend on these Common Targets that gathers various Build Outputs of the included project -->
4+
<PropertyGroup>
5+
<_GetBuildOutputsDependsOn>BuiltProjectOutputGroup;DocumentationProjectOutputGroup</_GetBuildOutputsDependsOn>
6+
<_GetBuildOutputsDependsOn Condition="'$(IncludeSymbols)' != 'false'">$(_GetBuildOutputsDependsOn);DebugSymbolsProjectOutputGroup</_GetBuildOutputsDependsOn>
7+
<_GetBuildOutputsDependsOn Condition="'$(IncludeSatelliteAssemblies)' != 'false'">$(_GetBuildOutputsDependsOn);SatelliteDllsProjectOutputGroup</_GetBuildOutputsDependsOn>
8+
</PropertyGroup>
9+
10+
<!-- Check for 'TargetFramework' input before proceeding. -->
11+
<Target Name="_CheckTargetFrameworkInput"
12+
DependsOnTargets="_CheckForInvalidConfigurationAndPlatform"
13+
Condition="'$(TargetFramework)' == ''">
14+
<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'."/>
15+
</Target>
16+
17+
<!--
18+
Gathers various Build Outputs from included Project per 'TargetFramework'.
19+
This target is called in by the 'GetBuildOutputs' target to combine build outputs from all 'TargetFrameworks'.
20+
-->
21+
<Target Name="GetBuildOutputsPerTarget"
22+
DependsOnTargets="_CheckTargetFrameworkInput;$(_GetBuildOutputsDependsOn)"
23+
Returns="@(BuildOutputPerTarget)">
24+
<ItemGroup>
25+
<BuildOutputPerTarget Include="@(BuiltProjectOutputGroupOutput);@(DocumentationProjectOutputGroupOutput)"/>
26+
<BuildOutputPerTarget Include="@(DebugSymbolsProjectOutputGroupOutput)" Condition="'$(IncludeSymbols)' != 'false'"/>
27+
<BuildOutputPerTarget Include="@(SatelliteDllsProjectOutputGroupOutput)" Condition="'$(IncludeSatelliteAssemblies)' != 'false'"/>
28+
<BuildOutputPerTarget Update="@(BuildOutputPerTarget)" TargetFramework="$(TargetFramework)"/>
29+
</ItemGroup>
30+
</Target>
31+
32+
<!--
33+
Gathers various Build Outputs from this Project across 'TargetFrameworks'.
34+
This target is called in the parent project to pack into a package.
35+
-->
36+
<Target Name="GetBuildOutputs"
37+
DependsOnTargets="_GetTargetFrameworksOutput"
38+
Returns="@(BuildOutput)">
39+
<MSBuild
40+
Projects="$(MSBuildProjectFullPath)"
41+
Targets="GetBuildOutputsPerTarget"
42+
Properties="TargetFramework=%(_TargetFrameworks.Identity)">
43+
<Output TaskParameter="TargetOutputs" ItemName="BuildOutput" />
44+
</MSBuild>
45+
</Target>
46+
47+
</Project>

0 commit comments

Comments
 (0)