Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use BeforeBuild and AfterBuild targets with Visual Studio 2017?

After upgrading to a csproj to use Visual Studio 2017 and Microsoft.NET.Sdk, my "BeforeBuild" and "AfterBuild" targets are no longer running. My file looks like this:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net46</TargetFramework>
  </PropertyGroup>

  <!-- my targets that don't run -->
  <Target Name="BeforeBuild">
      <Message Text="Should run before build" Importance="High" />
  </Target>

  <Target Name="AfterBuild">
      <Message Text="Should run after build" Importance="High" />
  </Target>

</Project>
like image 363
natemcmaster Avatar asked May 11 '17 17:05

natemcmaster


People also ask

What is target file in Visual Studio?

targets files that contain items, properties, targets, and tasks for common scenarios. These files are automatically imported into most Visual Studio project files to simplify maintenance and readability. Projects typically import one or more . targets files to define their build process.

Which is the inbuilt MSBuild target for C# projects?

MSBuild allows you to specify build-targets such as Build or Clean with -target:<build-target> (Example: MSBuild.exe -target:Clean ). Of course, a developer can define their own target using a . targets xml file. However, some targets, such as Build or Clean , are pre-defined by Microsoft.

What is an MSBuild target?

A target element can have both Inputs and Outputs attributes, indicating what items the target expects as input, and what items it produces as output. If all output items are up-to-date, MSBuild skips the target, which significantly improves the build speed. This is called an incremental build of the target.

Will MSBuild compile a file without any target?

If MSBuild determines that any output files are out of date with respect to the corresponding input file or files, then MSBuild executes the target. Otherwise, MSBuild skips the target. After the target is executed or skipped, any other target that lists it in an AfterTargets attribute is run.


3 Answers

The associated MSBuild git issue recommends not using BeforeBuild/AfterBuild as task names going forward, instead name the task appropriately and wiring up against targets

<Project Sdk="Microsoft.NET.Sdk"> 
  <PropertyGroup>
    <TargetFramework>net46</TargetFramework>
  </PropertyGroup>

  <!-- Instead of BeforeBuild target -->
  <Target Name="MyCustomTask" BeforeTargets="CoreBuild" >
      <Message Text="Should run before build" Importance="High" />
  </Target>

  <!-- Replaces AfterBuild target -->
  <Target Name="AnotherCustomTarget" AfterTargets="CoreCompile">
      <Message Text="Should run after build" Importance="High" />
  </Target>    
</Project>

This gets you an idiomatic VS 2017 project file, but which targets you trigger before/after is still a matter of some debate at this time

like image 156
Paul Hatcher Avatar answered Oct 22 '22 04:10

Paul Hatcher


When you specify Project Sdk="Microsoft.NET.Sdk", you are using "implicit top and bottom imports". This means there is an invisible Import to Microsoft.NET.Sdk/Sdk.targets at the bottom of your csproj file which is overriding the "BeforeBuild" and "AfterBuild" targets.

You can fix this by using explicit imports so you can control the import order.

<Project>

  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />

  <PropertyGroup>
    <TargetFramework>net46</TargetFramework>
  </PropertyGroup>

  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />

  <!-- add your custom targets after Sdk.targets is imported -->
  <Target Name="BeforeBuild">
      <Message Text="Should run before build" Importance="High" />
  </Target>

  <Target Name="AfterBuild">
      <Message Text="Should run after build" Importance="High" />
  </Target>

</Project>
like image 12
natemcmaster Avatar answered Oct 22 '22 04:10

natemcmaster


In the already mentioned GitHub issue Rainer Sigwald provides much shorter and elegant solution:

<Target Name="CustomBeforeBuild" BeforeTargets="BeforeBuild"> ... </Target>
<Target Name="CustomAfterBuild" AfterTargets="AfterBuild"> ... </Target>

Looks odd, but works fine.

like image 7
George Chakhidze Avatar answered Oct 22 '22 06:10

George Chakhidze