How To: Wrap Custom Targets Around a Solution Build

We got the following question on the msbuild@microsoft.com alias last week:

I'm migrating from VS2003/NAnt to VS2005/MSBuild for my build solution, and want to create a custom project that does the following:

  1. Pre-build actions
  2. Sync my source from source control
  3. Build the .sln file that Visual Studio uses
  4. Post-build actions
  5. Deploy the output of the build using my own deployment solution

I know how to write a project file that does all the steps except the third one. How do I build a solution file from within a project file?

The answer is to use the <MSBuild> task. While it is usually used to build projects, the task also supports building solution files. Here's what it would look like within the custom project file:

<

MSBuild Projects="@(SolutionFiles)"/>

where SolutionFiles is an ItemGroup that's been defined earlier in the file.

What is more interesting about how to do this is to look at the overall structure of a project file that accomplishes steps 1-5. To illustrate the design pattern for this type of build process I've built a little sample project file. The comments in the project file explain how it works, but in a nutshell there are a list of targets that need to get executed to complete the build:

<

PropertyGroup>
<BuildDependsOn>
      BeforeBuild;
SyncSource;
CoreBuild;
AfterBuild;
Deploy
</BuildDependsOn>
</PropertyGroup>

Notice how there are five targets listed in the property group, each corresponding to one step in the original question. This property group is used as the TargetDependsOn parameter to a target called "Build", and "Build" is defined as the default target for the project file:

<

Target Name="Build" DependsOnTargets="$(BuildDependsOn)">
</Target>

The Build target does nothing at all. Since it depends on the five other targets MSBuild will automatically build those other targets in order whenever the Build target is invoked. This is exactly how the Microsoft.Common.Targets file handles builds.

To experiment with the sample project rename it ends in ".proj", put it in a directory with a solution file, and run it by by typing "msbuild solutionbuild.proj". You can also try running individual targets by doing "msbuild solutionbuild.proj /target:<name>".

[ Author: Neil Enns ]