MSBuild 4.0 BeforeTargets and AfterTargets

Visual Studio 2010 Beta 1 gives the wider community their first look at what is on offer in MSBuild 4.0. In this post I’ll briefly cover the new BeforeTargets and AfterTargets features.

These targets sit in the new MSBuild.Construction namespace and on initial inspection, they provide you with the ability to plug in targets to alter the execution path of a MSBuild file.

Lets cover this with a basic example. Running the following sample,

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <Target Name="Default">
    <Message Text="Hello from Default"/>
  </Target>

</Project>

we get the expected:

Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" on node 1 (default targets).
  Hello from Default
Done Building Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" (default targets).

Now suppose you wanted to run a target before the Default target. In .NET 3.5 you would use DependsOnTargets as shown with the following:

 

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <Target Name="Default" DependsOnTargets="DefaultDependsOn">
    <Message Text="Hello from Default"/>
  </Target>

  <Target Name="DefaultDependsOn">
    <Message Text="Hello from DefaultDependsOn"/>
  </Target>

</Project>

which would result in:

Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" on node 1 (default targets).
  Hello from DefaultDependsOn
Default:
  Hello from Default
Done Building Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" (default targets).

So what’s wrong with DependsOnTargets? Well, not a lot, however the above implementation does create an explicit bind between the targets and may reduce your ability to reuse the default target efficiently.

 

Enter BeforeTargets

In MSBuild 4.0 you can achieve the same result by using the following

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <Target Name="Default">
    <Message Text="Hello from Default"/>
  </Target>

  <Target Name="DefaultBeforeTarget" BeforeTargets="Default">
    <Message Text="Hello from DefaultBeforeTarget"/>
  </Target>

</Project>

which results in:

Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" on node 1 (default targets).
  Hello from DefaultBeforeTarget
Default:
  Hello from Default
Done Building Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" (default targets).

So we get the same functionality, but our targets are arguably more reusable. I don’t think there is a need to go and re-write all your code, but remember that you have this feature in your tool belt in 4.0.

Now it may be that I’ve used it a lot, but DependsOnTargets makes a lot of sense to me. It does ‘as it reads’, i.e. the Default target depends on Targets xyz… A minor concern I have with this new feature is that it doesn’t do ‘as it reads’. The first time i saw a sample with this I expected that all the BeforeTargets would run before the named target. Perhaps a better name would be RunBeforeTargets, which makes it clear that the named target will run before all the targets listed. The same logic could be applied to AfterTargets (or perhaps a better named RunAfterTargets)

 

Enter AfterTargets

In a very similar light, the new AfterTargets feature allows us to run a target after a given target. Running the following sample:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <Target Name="Default">
    <Message Text="Hello from Default"/>
  </Target>

  <Target Name="DefaultBeforeTarget" BeforeTargets="Default">
    <Message Text="Hello from DefaultBeforeTarget"/>
  </Target>

  <Target Name="DefaultAfterTarget" AfterTargets="Default">
    <Message Text="Hello from DefaultAfterTarget"/>
  </Target>
</Project>

we get:

Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" on node 1 (default targets).
  Hello from DefaultBeforeTarget
Default:
  Hello from Default
DefaultAfterTarget:
  Hello from DefaultAfterTarget
Done Building Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" (default targets).

 

But DependsonTargets Rules!

So you can see how these two new features provide the ability to easily tweak execution. You can also plug into existing target frameworks without affecting other users. Now what of the DependsOnTargets in 4.0? It still lives on of course and its important to understand the order of execution.

Take the following example:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <Target Name="Default" DependsOnTargets="DefaultDependsOn">
    <Message Text="Hello from Default"/>
  </Target>

  <Target Name="DefaultDependsOn">
    <Message Text="Hello from DefaultDependsOn"/>
  </Target>

  <Target Name="DefaultBeforeTarget" BeforeTargets="Default">
    <Message Text="Hello from DefaultBeforeTarget"/>
  </Target>

  <Target Name="DefaultAfterTarget" AfterTargets="Default">
    <Message Text="Hello from DefaultAfterTarget"/>
  </Target>
</Project>

Would you expect to see DefaultBeforeTarget or DefaultDependsOn execute first? Below is the result:

Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" on node 1 (default targets).
  Hello from DefaultDependsOn
DefaultBeforeTarget:
  Hello from DefaultBeforeTarget
Default:
  Hello from Default
DefaultAfterTarget:
  Hello from DefaultAfterTarget
Done Building Project "C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj" (default targets).

So as you can see, order of execution is DependsOnTargets, BeforeTargets, [NamedTarget], AfterTargets.

What do you think of this new feature? Can you think of better names or do they make sense to you?

— Mike

About these ads
This entry was posted in MSBuild. Bookmark the permalink.

5 Responses to MSBuild 4.0 BeforeTargets and AfterTargets

  1. Brandon says:

    RunBeforeTargets and RunAfterTargets are much better names. With the existing names, I expected them to do the opposite of what they do.

  2. mamatucci says:

    Hi, I thinks theses names have sense:
    at max it could be TargetsToRunBefore (RunBeforeTargets)
    using the

    you have just to focus on the T1 T2 definitions and change the Before/After contents, this useful is you have a chain of Task so just say what happens before and what later (using only DependsOn it would be harder as you have to imagine all the chain flow….)
    About the order of execution is optimized by msbuild….
    Cheers, Mario

  3. Arun says:

    The BeforeTargets does have sense in the following situation:
    (1) there are 2 projects, part of the build on them overlap – that is there are targets that both projects would use – essentially this results in creation of a third file for common targets in two
    (2) in one project you need to perform an action Before executing a target; at the same time, you do not want that to be coded into the other project or (obviously) in the common targets file
    (3) you would create a Before target in the project where you want the change to happen

    This case is very much present when I had to make a change to the common “Microsoft.common.Targets” include.

  4. Doug Clutter says:

    How do AfterTargets behave if there is an error in a target? Does it still get called?

  5. Doug Clutter says:

    Just tested it…AfterTargets does NOT get called if there is an error in your Target. Bummer.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s