Matthias
Matthias

Reputation: 16209

How should I structure my MSBuild script

Recently, I started to learn MSBuild in order to flexible build scripts for local as well as server builds (CI, Nightly, Weekly). Based on my experience I knew that build scripts can be very awkward. Even at my company with some guidance it was a pain to get to know all targets and how they work together. For sure, it was a long-term process: you need something, you don't have enough time, you start being lazy and messy. But I asked myself, how could I structure a MSBuild script for easy extensibility and readability? Especially the three relationships between targets DependsOnTargets, BeforeTargets, AfterTargets were useful to shoot myself in the foot.

Upvotes: 3

Views: 1053

Answers (1)

Sayed Ibrahim Hashimi
Sayed Ibrahim Hashimi

Reputation: 44332

In my MSBuild Book I have a section based on how to create reusable elements in MSBuild, if you are interested. I'll give some comments here as well though. This content is different from what the book has.

When creating MSBuild files you should be careful to isolate what versus how. To explain that a bit, lets examine how the managed VS projects work out of the box (which is a great model for reusable elements).

When you create a C#/VB project you get a .csproj file, this .csproj file primarily contains Properties and Items. You will not find a single target in that file. These files contains what will get built (along with some settings relating to the build). At the bottom of the project file you will find an import statement. This import bring in How the project is built.

The files which are imported include:

  • Microsoft.CSharp/VisualBasic/FSharp.targets
  • Microsoft.common.targets

In this case Microsoft.common.targets defines the overall build process for all the managed languages. Then Microsoft.CSharp.targets (or one of the other lang specific .targets file) fills in the blanks of how to invoke the specific language specific tools.

DependsOnTargets versus Before/AfterTargets

In your answer above you state "I recommend to avoid DependsOnTargets unless it is really really necessary, for instance if two". I disagree with this. Here is my take on DependsOnTargets versus Before/AfterTargets.

Use DependsOnTargets when

  • When you are trying to create a workflow of targets to be executed
  • When a target will not function without the other target(s) executing first
  • When you need to inject different targets at specific steps based on the desired operation

Use Before/AfterTargets when

  • When you don't own the file the target resides in and it has no DependsOnTargets property that can be extended
  • You want a target to execute Before/After a specific target no matter when it gets executed

To tease out the difference a bit consider web projects. For web projects there are two workflows that the .csproj/.vbproj take care of:

  1. Build
  2. Publish

If I want to add a target to the list of targets to be executed before the Build target I can dynamically update the BuildDependsOn property for publish scenarios only. You cannot do this with Before/AfterTargets.

In an ideal world each target would have the following wrt DependsOnTargets.

  • All targets have a DependsOnTargets attribute which is feed by a property
  • Each DependsOnTargets always prepends the existing value to the property definition

For example

<MyTargetDependsOn>
    $(MyTargetDependsOn);
    Target1;
    Target2
</MyTargetDependsOn>

Unfortunately many targets do not follow this pattern, so DependsOnTargets is dead in the water for many cases.

When I am authoring MSBuild scripts I always use DependsOnTargets unless there is a solid reason why I should chose to use Before/AfterTargets. I feel that (I have no insight on the real reasons to the design as I wasn't with Microsoft at the time) Before/AfterTargets was really created to allow users to inject targets to be executed before/after a target which they did not own, and the creators did not use the pattern above.

Upvotes: 7

Related Questions