RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Speed Up Project Delivery with Repeatability : Page 3

Automate high-friction, unpredictable tasks in your environment to regain sanity and achieve a rapid, sustainable pace.


Automated Build

Takeaway: The code should have an associated automated build script that requires no magic by the person running the script. Here's a common scenario: A new developer joins your team. She gets her workstation all set up. She checks out the latest source from your source control repository and attempts to build—and nothing works. She's missing this component, doesn't have this environment variable set up, etc, etc. Here's a related situation: You set up a test server to help build, test, and preview your software release packages and nothing seems to work because the server doesn't have Visual Studio on it, or some SDK installed, or some DLL in the GAC.

Automating your build process helps remove a lot of the guesswork of building your project. You can include simple dependency checks to make sure that the system has the prerequisites for building your software installed, which will allow you to give humans a better indication as to why things are failing (for example, "Please install the .NET Framework 3.5 SDK").

Automated builds also serve as documentation for how to build, assemble, and package your project for release. Should you win the lottery and quit tomorrow, the next person to take over after you will be able to get going quickly, without having to guess your software's requirements.

I like the NAnt build tool for doing automated builds. NAnt uses a simple-format XML build file format that harkens back to MAKE days, but doesn't have all those pesky whitespace problems. A typical NAnt build file has several "targets" that do common things, such as building/compiling a Visual Studio solution, running tests, generating documentation, packaging up the results, and putting them in a well-known location for people to grab and use.

Getting Started with NAnt

Before launching into this brief introduction to NAnt, David C. Bost's article on NAnt goes into more detail, if you're interested.

First, download the latest version of NAnt. At the time of this writing, the release is 0.86 Beta 1. Don't be put off by the version-numbering scheme. Nant has been pre-version 1 since before Windows XP was released, yet NAnt has been one of the most reliable pieces of software I've ever used.

I recommend getting the bin ZIP package and grabbing the contents of the bin and schema folders. The docs and examples are there for your convenience, but the online versions are probably more up-to-date. Create a sub-folder of the \trunk folder in your source code tree; call it something like "tools" or "support." Create a sub-folder of that called NAnt, and extract the bin folder from the NAnt ZIP package in that new NAnt folder.

The reason for keeping the NAnt binaries with your source trunk is that you may, at a later date, add custom tasks to NAnt or apply special configuration changes that are appropriate to build your project. These changes usually end up being tied to specific versions of the software and so it's beneficial to keep both the NAnt version and project-specific modifications together. It takes a little extra space, but is usually worthwhile.

Remember the schema file I told you to grab from the NAnt ZIP package? Place the XSD file located inside that folder into your Visual Studio XML Schemas folder. That enables IntelliSense when you're editing NAnt build files in Visual Studio. Intellisense comes in very handy—especially at the beginning of the project when you're doing a lot of build file hacking.

For Visual Studio 2005 and 2008, copy the XSD file to C:\Program Files\Microsoft Visual Studio 8.0\Xml\Schemas or C:\Program Files\Microsoft Visual Studio 9.0\Xml\Schemas, respectively, where C: is your system root drive. Note that if you're using a 64-bit version of Windows, you will probably have to use Program Files (x86) instead of Program Files.

Now you have an installed copy of NAnt with Visual Studio support. Now you can create your first NAnt build file.

Creating the NAnt Build File

Create a new empty XML file in your \trunk folder called build.xml. The specific name of this file isn't terribly important, because you can tell NAnt what the file name is, (by default it'll have the name default.build) but it helps when editing in Visual Studio if the file name ends with XML.

Next, create a simple batch file called build.bat that executes the NAnt executable with the build file and any optional parameters:

   .\tools\NAnt\nant.exe -nologo /f:build.xml %*
Using that batch file, from a command-prompt whose current working directory is your \trunk folder, you can simply type "build" to execute NAnt with your build script. You can also pass in any optional arguments to your build script, allowing you to run a "release" build, or a "debug" build, etc.

Next, you'll add the first parts of the build file to get a simple, working build. The most basic NAnt build script file has the XML declaration and the root element:

   <?xml version="1.0" encoding="utf-8" ?>
   <project xmlns=
In the project root element, the name attribute is useful for documentation purposes. The basedir attribute value of "." tells NAnt to resolve all relative paths from that base directory. In this simple case, the basedir is just the current working directory. The default attribute specifies which target to execute if you don't tell NAnt specifically which task to run. A "target" is analogous to a "method" on a class in .NET. Both are small units of functionality expected to perform a specific task and yield specific results. The preceding snippet does not have any targets, so NAnt will raise an error if you try to execute this build script. So the next thing you need to add is a target named build.

This example of a basic target simply prints a message to the console:

   <target name="build"
     description="Rebuilds the entire solution">
     <echo message="Hello I'm a build!"/>
When you run build.bat file from the command line, NAnt executes, calling the "build" target. The output should look something like this:

   Target framework: Microsoft .NET Framework 3.5
   Target(s) specified: build
        [echo] Hello I'm a build!
   Total time: 0 seconds.
You've verified that NAnt is wired up properly and the build script has no errors. Now you'll compile the Visual Studio solution.

Creating the Build Target

With the basic structure set up, you should create some properties (variables) for the more interesting parts of your build. It's a pain to go back and extract these later, so it usually helps to apply them at the start. I recommend always starting out with the properties defined in the snippet below. Feel free to rename them:

You can now reference these properties anywhere a value is allowed using the ${} syntax. You can see an example of this in the value for the sln.file property.

Next, set up the compiler to compile the Visual Studio solution file. As it turns out, Visual Studio 2005 and 2008 project files are actually MSBuild scripts. MSBuild is Microsoft's build tool (which is similar to NAnt in many ways). Because the VBProj and CSProj files already contain all the information needed to compile your solution, it is actually easier to let MSBuild handle all that for you. NAnt comes in handy for all the other non-compile tasks, such as cleaning up build artifacts, running tests, creating a deployment package, etc. While MSBuild can do these things, it's not as easy to work with, nor does it have NAnt's straightforward procedural approach to these types of tasks.

So, I recommend using NAnt for all non-build tasks, and deferring to MSBuild for compilation. This has the added benefit of automatically keeping the build situation consistent between the IDE and the build script so that you don't get into a situation where the project builds in one but not the other. Also, it preserves all the IDE build behavior (such as post-build behavior, output files, embedded resources, etc.) and it's one less thing you need to think about in your NAnt script.

To call MSBuild, you must let NAnt know where the msbuild.exe file is. NAnt has some handy functions that allow you to discover where the framework directories are. Don't hard code your framework directory; let NAnt build it for you. This is particularly useful if you ever need to run the build on another computer, whose framework directory may be on a different drive or in a different directory for some reason. To determine the framework directories, set up some properties that are similar to the ones you've already seen, but require some special NAnt syntax:

Note the function-call like syntax. NAnt can do more than just store and retrieve properties and variables; it supports a rather complex expression syntax that lets you perform Boolean operations, call NAnt functions, and much more. You'll see more about that later. For now, you need to call MSBuild.

One more thing first: MSBuild has a large number of command-line options, some of which you always want, so it's useful to create yet another property that contains these "standard" command-line options. Here's a property definition for common MSBuild options (feel free to change these as needed):

     ${sln.file}" />
Note that this is a dynamic property (dynamic=true). Setting this property to "dynamic" means that NAnt evaluates the property value just-in-time, as opposed to only once, during startup. If the property weren't dynamic, then changing the value of project.config would have no effect. Because msBuildArgs would have already been evaluated (at startup), it would always be debug. However, because it's dynamic, the value will be determined only when it's requested, so it will factor whatever project.config happens to be at that moment into the value of msBuildArgs. In this way, you can change project.config whenever you like, and the referenced value of msBuildArgs will reflect those changes.

Finally, update the build target to call MSBuild on your Visual Studio solution file:

     description="Rebuilds the entire solution">
       commandline="/t:Rebuild ${msBuildArgs}"/>
Assuming your Visual Studio solution is compilable, when you re-run build.bat, you should now see something similar to this output:

   Target framework: Microsoft .NET Framework 3.5
   Target(s) specified: build
        [exec] CopyFilesToOutputDirectory:
        [exec]   CoDe.Repeatability.Core -> 
   Total time: 0.6 seconds.

A Few Other Targets to Consider

The msBuildArgs dynamic property you created in the previous section lets you change the value of project.config, giving you the ability to perform a "Release" configuration build with Visual Studio. First, add a new target that changes the value of project.config to release:

   <target name="releaseBuild">
Then, from the command line, execute:

   build releaseBuild build
This instructs NAnt to run the releaseBuild target first, followed by the build target. Notice that the output has changed slightly; it now compiles to the Release folder:

   Target framework: Microsoft .NET Framework 3.5
   Target(s) specified: releaseBuild build
        [exec] CopyFilesToOutputDirectory:
        [exec]   CoDe.Repeatability.Core -> 
   Total time: 0.6 seconds.
Your basic build script is now ready to go. Listing 1 shows the entire current build script. If you've been following along, and you have a Subversion repository already set up, this would be an ideal time to commit your changes to the repository.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date