Share via


Hack the Build: Target Overriding Step-by-Step

Jomo Fisher--John Lam recently mentioned Target Overriding as a useful tool for extending a pre-existing build process. In MSBuild, a target is a grouping of build functionality—there’s a good MSDN article here that gives some details. The build scripts that ship with VS are largely collections of targets that do certain useful things. For example, in Microsoft.CSharp.Targets there is a Compile target that invokes the C# compiler.

 

Target overriding is how you get your code running in someone else’s build script. Here’s how you do it with a C# project in VS Beta1 (the principles apply to any kind of MSBuild project).

 

(1) Create a new C# Console application call MyApp.

(2) Turn on the output window—ViewàOther WindowsàOutput—and build. In the output window, you should see that Resgen.exe and Csc.exe were called.

(3) Find the file MyApp.csproj—this is the MSBuild project file.

(4) In the same directory as MyApp.csproj, create a file called Override.targets (the actual name doesn’t really matter) with the following XML:

 

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

    <Target Name="Build" Outputs="$(TargetPath)"

       DependsOnTargets="$(BuildDependsOn)">

   <Exec Command="echo My code is running here!!!"/>

    </Target>

</Project>

This MSBuild code overrides the Build target with custom behavior.

(5) Open MyApp.csproj with notepad and look at the very end for an <Import> tag. Add a new import tag.

 

  <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />

  <Import Project="Override.proj" />

</Project>

Now save. If VS is open, you’ll be prompted to reload the project after this step.

(6) Go back to VS and do Build or Rebuild. You should see your code running in the output window.

 

A few key things to remember:

 

- The last target seen by MSBuild is the one that is used—this is why we put the <Import> at the end of MyApp.csproj.

- The overriding target replaces the target that is overridden.

 

If you look in the .targets files that ship with VS Beta1, you’ll see many, many targets. Any of these can be overridden, but some are more useful to override than others. Here are a few interesting candidates, in the order that they build in:

 

PrepareForBuild

PreBuildEvent

UnmanagedUnregistration

ResolveReferences

PrepareResources

ResolveKeySource

Compile

CreateSatelliteAssemblies

BuildManifests

PrepareForRun

UnmanagedRegistration

 

In a future entry, I’ll talk some more about what some of these targets do and how. Also, there are some other ways to change a pre-existing build system—Property Overriding and Target Chaining—that I’d like to talk about.

 

This posting is provided "AS IS" with no warranties, and confers no rights.

Comments

  • Anonymous
    September 16, 2004
    The way you describe it, <import> seems to work quite similar to Ant's version[1], including the ability to override targets (explained in a bit more detail in [2]).

    The major differences I see:

    * In Ant, the target that is the "outermost" target will be the one that wins. I.e. if in your example MyApp.csproj contained a target named Build, Ant would use that, but MSBuild would use the one from Override since that's the last one MSBuild sees. Is this correct? Why have you designed it that way? Is there any benefit over a more hierarchical way to control it?

    * In Ant you still have access to the overridden target . Let's say your $(MSBuildBinPath)Microsoft.CSHARP.Targets was named "msbuilddefault" then you could access its Build target as msbuilddefault.Build. Is something similar possible in MSBuild?

    [1] http://ant.apache.org/manual/CoreTasks/import.html
    [2] http://www.oracle.com/technology/pub/articles/bodewig_ant1.6.html
  • Anonymous
    September 17, 2004
    The comment has been removed
  • Anonymous
    September 28, 2004
    One thing I have learned from complex use of ant's new <import> thingy is that the most wonderful aspect of any inheritance enabled language is the ability to mark something as private.

    We dont have that in ant1.6, so you rely on trust that nobody has accidentally overriden something you needed.

    More to the point, it makes maintenance harder, as you need to think of obscure names for all your targets to be sure that nothing is using them.

    I'm sure we will add a scope attribute before long, for public/private/protected. What is your solution going to be?
  • Anonymous
    September 28, 2004
    As we've scaled up our use of MSBuild in our own build labs, we've seen how important private targets are going to become. I'm not sure when we'll implement this, but its definitely something we need to get to.

    This posting is provided "AS IS" with no warranties, and confers no rights.
  • Anonymous
    September 29, 2004
    more on inheritance plus the need to get at the dependency list of a super target.
  • Anonymous
    April 19, 2007
    Recently, I ran into an issue where my Team Build process would fail when building our main application...