2
votes

Given an MSBuild Task that runs in AfterTargets="AfterCompile" and produces some files how do you get those files to be included in the current projects output so that the files will be copied to the bin directory of any projects referencing that project?

2
If you know the file paths before compilation, you can add a target with BeforeTargets="AssignTargetPaths" and populate the Content ItemGroup in it, if the CopyToOutputDirectory metadata is set to true it will get copied to depending projects. I don't immediately know how to do this after compilation.stijn

2 Answers

1
votes

I have no guarantees that this is the right solution but it seems to work:

<Target Name="MyTarget" AfterTargets="AfterCompile">
  <PropertyGroup>
    <MyInput>D:\1.txt</MyInput>
    <MyOutput>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)$(OutDir)\1.txt'))</MyOutput>
  </PropertyGroup>
  <Copy SourceFiles="$(MyInput)" DestinationFolder="$(OutDir)" SkipUnchangedFiles="true" />
  <ItemGroup>
    <AllItemsFullPathWithTargetPath Include="$(MyOutput)">
      <TargetPath>1.txt</TargetPath>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </AllItemsFullPathWithTargetPath>
  </ItemGroup>
</Target>

The relevant logic is here: http://sourceroslyn.io/#MSBuildTarget=GetCopyToOutputDirectoryItems http://sourceroslyn.io/#MSBuildItem=AllItemsFullPathWithTargetPath

Basically we rely on the fact that to determine the list of files to copy from dependent projects MSBuild calls the GetCopyToOutputDirectoryItems target of the dependent projects and uses its output (which is AllItemsFullPathWithTargetPath).

By adding ourselves to AllItemsFullPathWithTargetPath at the last minute we get picked up when a dependent project calls us.

0
votes

Thank you, Kirill. That was an excellent answer and it helped me when trying to copy ETW manifest files from a different project's output. Below is the final output.

Since I've simply expanded upon Kirill's answer, I do not expect this answer to be accepted. I post this here in the hope it helps someone else.

<Target Name="IncludeEtwFilesInOutput"
        BeforeTargets="GetCopyToOutputDirectoryItems">

    <PropertyGroup>
        <EtwManifestFile>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)$(OutDir)\My.etwManifest.man'))</EtwManifestFile>
        <EtwResourceFile>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)$(OutDir)\My.etwManifest.dll'))</EtwResourceFile>
    </PropertyGroup>

    <ItemGroup>
        <AllItemsFullPathWithTargetPath Include="$(EtwManifestFile)">
            <TargetPath>My.etwManifest.man</TargetPath>
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </AllItemsFullPathWithTargetPath>
        
        <AllItemsFullPathWithTargetPath Include="$(EtwResourceFile)">
            <TargetPath>My.etwManifest.dll</TargetPath>
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </AllItemsFullPathWithTargetPath>
    </ItemGroup>
</Target>