Search code examples
msbuild.net-coredotnet-clidotnet-sdk

How to include an item in BuiltProjectOutputGroup


I have a custom project system, that uses the standard net sdk targets. During the build, I produce an extra zip file. I'd like this extra file to be included in an output group, so that when I query my projects output groups (from vs) it shows up.

My project file looks like this:

<Project Sdk="Microsoft.NET.Sdk"> 
 ... stuff
  <ItemGroup>
    <PackageReference Include="DnnVsProjectSystem.BuildTools" Version="0.0.5">
      <PrivateAssets>All</PrivateAssets>
    </PackageReference>
  </ItemGroup>
  <Import Project="$(CustomProjectExtensionsPath)DnnVsProjectSystem.targets"/>
</Project>

Notice, I am using the "sdk" attribute, which is a fairly new feature of msbuild.

The PackageReference that you see, is a nuget package that imports a .props and a .targets which augment the build with some custom build tasks. These are the ones that produce the zip file.

I have drilled into the net sdk targets and found this:

<Target Name="AllProjectOutputGroups" DependsOnTargets="&#xD;&#xA;            BuiltProjectOutputGroup;&#xD;&#xA;            DebugSymbolsProjectOutputGroup;&#xD;&#xA;            DocumentationProjectOutputGroup;&#xD;&#xA;            SatelliteDllsProjectOutputGroup;&#xD;&#xA;            SourceFilesProjectOutputGroup;&#xD;&#xA;            ContentFilesProjectOutputGroup;&#xD;&#xA;            SGenFilesOutputGroup" />
  <!--
    This is the key output for the BuiltProjectOutputGroup and is meant to be read directly from the IDE.
    Reading an item is faster than invoking a target.
    -->
  <ItemGroup Condition=" '$(OutputType)' != 'winmdobj' ">
    <BuiltProjectOutputGroupKeyOutput Include="@(IntermediateAssembly->'%(FullPath)')">
      <IsKeyOutput>true</IsKeyOutput>
      <FinalOutputPath>$(TargetPath)</FinalOutputPath>
      <TargetPath>$(TargetFileName)</TargetPath>
      <COM2REG Condition="'$(RegisterForComInterop)'=='true' and '$(OutputType)'=='library'">true</COM2REG>
    </BuiltProjectOutputGroupKeyOutput>
  </ItemGroup>
  <ItemGroup Condition=" '$(OutputType)' == 'winmdobj' ">
    <WinMDExpOutputWindowsMetadataFileItem Include="$(_IntermediateWindowsMetadataPath)" Condition="'$(_IntermediateWindowsMetadataPath)' != ''" />
    <BuiltProjectOutputGroupKeyOutput Include="@(WinMDExpOutputWindowsMetadataFileItem->'%(FullPath)')">
      <IsKeyOutput>true</IsKeyOutput>
      <FinalOutputPath>$(TargetPath)</FinalOutputPath>
      <TargetPath>$(TargetFileName)</TargetPath>
    </BuiltProjectOutputGroupKeyOutput>
  </ItemGroup>

This appears to be the target that is called by VS, when it wants information about output groups.

The problem is, i am not sure how I can get my item included in one of those output groups, as If i just add the item to the item group, in my own targets - my targets are irrelevent at this point, as they are not included in this dependency chain.

I also can't override any of the targets, because, as i'm using the sdk attribute, it looks like the sdk targets will always be imported last, overwriting anything that I declare.

Any guidance much appreciated.


Solution

  • If your only concern is to hook into the target or its dependency chain, I suggest using msbuild's BeforeTargets functionality:

    <Target Name="IncludeMyCustomOutputGroup" BeforeTargets="AllProjectOutputGroups" DependsOnTargets="ResolveMyCustomPropertiesAndItems">
      <ItemGroup>
        <!-- Assuming @(MyCustomOutput) items are generated by your ResolveMyCustomPropertiesAndItems target, or just add anything else -->
        <BuiltProjectOutputGroupKeyOutput Include="@(MyCustomOutput->'%(FullPath)')">
          <IsKeyOutput>true</IsKeyOutput>
          <FinalOutputPath>$(TargetPath)</FinalOutputPath>
          <TargetPath>$(TargetFileName)</TargetPath>
        </BuiltProjectOutputGroupKeyOutput>
      </ItemGroup>
    </Target>