0

What is the canonical way now to write a custom Target in an sdk-style project to perform operations on files in $(OutputPath) in the context of a multitargeted build? I'm trying to multitarget our build for a migration to net5 and am surprised how messy this is. We have various targets that need to reach into $(OutputPath) to copy files or run exes, etc as part of the build. For instance, a target like this:

<TargetFrameworks>net48;net5</TargetFrameworks> 
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
...
<ItemGroup>
    <MyTargetInputs Include="$(OutputPath)\Foo.exe">
</ItemGroup>
<Target Name="DoPostBuildStuff" AfterTargets="Build" Inputs="@(MyTargetInputs)" Outputs="@(MyTargetOutputs)">
    ...
</Target>

This worked fine in an sdk-style project without multitargeting as $(OutputPath) is set to bin\debug which is indeed where Foo.exe is. But with the above the ItemGroup gets evaluated before AppendTargetFrameworkToOutputPath does its work to make $(OutputPath) set to bin\debug\net48. So now my ItemGroup is still looking for Foo.exe in bin\debug instead of bin\debug\net48 (this is true even in the inner build where $(TargetFramework) is defined). As an alternative to relying on AppendTargetFrameworkToOutputPath I tried to define $(OutputPath) myself in a Directory.Build.props as bin$(Configuration)$(TargetFramework) but because $(TargetFramework) is not set by the sdk until after my csproj contents are evaluated the same problem occurs (paths in my ItemGroup that use $(OutputPath) evaluate to bin\debug\). The same issue obviously occurs for any PropertyGroup items too.

I can devise some workarounds but they all seem a bit hacky (ex define a preceding target whose only job is to define ItemGroups for inputs/outputs of future targets so that $(OutputPath) is constructed completely by the time it runs). I'm surprised the docs for multi-targeting did not seem to mention that using this feature really messes with your ability to ever refer to build artifacts as part of the build process?

Dan Quirk
  • 21
  • 2
  • You can try to make target that will evaluate before `DoPostBuildStuff`, like ` – JL0PD Apr 22 '21 at 03:20
  • Yeah that is one of my available workarounds but it feels quite annoying to have to do this for practically every custom target I have in 100s of projects (the majority are just trying to copy stuff to/from $(OutputPath)) after multitargeting was supposedly as simple as changing to . Is this really the canonical option for multitargeting builds? I did not think I was doing anything particular uncommon using post build tasks that reach into $(OutputPath) – Dan Quirk Apr 22 '21 at 20:56
  • You can create task in `Directory.Build.targets` in root of your repository which will be automatically executed and you will need only to assign `MyTargetInputs` in individual projects. But this may be tricky because of changed path and you will need to use something like [`MSBuildProjectDirectory`](https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-reserved-and-well-known-properties) – JL0PD Apr 23 '21 at 02:12

0 Answers0