I guess you tried do it this way:
<Target Name="MyCustomBeforeBuild" BeforeTargets="BeforeBuild" Inputs="@(Compile)" Outputs="@(Compile->'%(RecursiveDir)%(Filename)%(Extension).generated')">
<Message Text="MyCustomBeforeBuild Begin" Importance="High" />
<Copy SourceFiles="@(Compile)" DestinationFiles="@(Compile->'%(RecursiveDir)%(Filename)%(Extension).generated')" />
<Message Text="MyCustomBeforeBuild End" Importance="High" />
</Target>
In this case MSBuild will use incremental build and evaluates that no file were modified based on timestamp comparison of input and output files.
In this case you can see in detailed or in diagnostic log message like this
Skipping target "MyCustomBeforeBuild" because all output files are up-to-date with respect to the input files.
But by specifying “fake outputs” (see .fake
in Outputs attribute of Target) you can force MSBuild execute it every time (because fake file does not exist, no timestamp comparison will happen so it is always executed).
<Target Name="MyCustomBeforeBuild" BeforeTargets="BeforeBuild" Inputs="@(Compile)" Outputs="@(Compile->'%(RecursiveDir)%(Filename)%(Extension).generated.fake')">
<Message Text="MyCustomBeforeBuild Begin" Importance="High" />
<Copy SourceFiles="@(Compile)" DestinationFiles="@(Compile->'%(RecursiveDir)%(Filename)%(Extension).generated')" />
<Message Text="MyCustomBeforeBuild End" Importance="High" />
</Target>