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 Apr 12, 2022
1 parent 1ab0a31 commit f435d10
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" PrivateAssets="All" Pack="false" />
</ItemGroup>

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

</Project>
31 changes: 22 additions & 9 deletions CommunityToolkit.Mvvm/CommunityToolkit.Mvvm.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,33 @@
</ItemGroup>

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

<!-- Use 'GenerateNuspecDependsOn' extensibility point to include build assets into our package -->
<PropertyGroup>
<GenerateNuspecDependsOn>GetSourceGenBuildOutputs</GenerateNuspecDependsOn>
</PropertyGroup>

<!--
Pack the source generator to the right package folder.
TODO: Find a way to get the analyzer project's build output path,
and include using NuGet Pack's extensibility target points.
Pack the source generator build outputs to the correct package folder for it to be used as an analyzer.
The following target uses 'GenerateNuspecDependsOn' extensibility point to pack the build assets
by using our custom 'GetBuildOutputs' target imported within the target project.
-->
<ItemGroup Label="Package">
<None Include="..\CommunityToolkit.Mvvm.SourceGenerators\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.SourceGenerators.dll"
PackagePath="analyzers\dotnet\roslyn4.0\cs"
Pack="true" Visible="false" />
</ItemGroup>
<Target Name="GetSourceGenBuildOutputs" AfterTargets="_CalculateInputsOutputsForPack">
<MSBuild
Projects="@(ProjectReference->WithMetadataValue('ReferenceOutputAssembly', 'false'))"
Targets="GetBuildOutputs">
<Output TaskParameter="TargetOutputs" ItemName="SourceGenBuildOutput" />
</MSBuild>
<ItemGroup>
<!-- Include SourceGen Build Outputs in the package -->
<_PackageFiles Include="@(SourceGenBuildOutput)" PackagePath="analyzers\dotnet\roslyn4.0\cs" />
<!-- Use the 'FinalOutputPath' metadata to mark the inputs thus enabling incremental builds -->
<NuGetPackInput Include="@(SourceGenBuildOutput->'%(FinalOutputPath)')" />
</ItemGroup>
</Target>

</Project>
47 changes: 47 additions & 0 deletions build/Community.Toolkit.GetBuildOutputs.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<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>
</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>

0 comments on commit f435d10

Please sign in to comment.