About Me

Training

Nothin But .Net Developer Bootcamp

Navigation

Search

Categories

On this page

Automating Your Builds With NAnt - Part 2

Archive

Blogroll

 Agile Developer Venkat's Blog
 Ayende @ Blog
 B#
 Barry Gervin's Software Architecture Perspectives
 Boy Meets World
 Brad Abrams
 Canadian Developers
 Christopher Steen
 Claritude Software News
 Clemens Vasters: Enterprise Development and Alien Abductions
 Coding Horror
 Coding in an Igloo
 Dare Obasanjo aka Carnage4Life
 Darrell Norton's Blog [MVP]
 David Hayden [MVP C#]
 Don Box's Spoutlet
 Eric Gunnerson's C# Compendium
 EZWeb guy: Jeffrey Palermo [C# MVP]
 Fear and Loathing
 Generalities & Details: Adventures in the High-tech Underbelly
 Greg Young [MVP]
 Greg's Cool [Insert Clever Name] of the Day
 IanG on Tap
 Ingo Rammer's Weblog
 ISerializable - Roy Osherove's Blog
 James Kovacs' Weblog
 Jason Haley
 Jean-Luc David
 Jeremy D. Miller -- The Shade Tree Developer
 JetBrains .NET Tools Blog
 Jimmy Nilsson's weblog
 John Bristowe's Weblog
 John Papa [MVP C#]
 Jon Skeet's Coding Blog
 JonGalloway.ToString()
 Jump the Fence or Walk Around
 Lambda the Ultimate - Programming Languages Weblog
 Larkware News
 Lutz Roeder
 Marquee de Sells: Chris's insight outlet
 Martin Fowler's Bliki
 Mike Nichols - SonOfNun Technology
 MSDN Magazine - .NET Matters
 MSDN Magazine - All Articles
 OdeToCode Blogs
 Onion Blog
 Planet TW
 Raymond Lewallen [MVP]
 Rockford Lhotka
 RodMan's Corner
 Roger Johansson's blog
 Sahil Malik - blah.winsmarts.com
 Sam Gentile's Blog
 Scott Bellware [MVP]
 Scott Hanselman's Computer Zen
 ScottGu's Blog
 secretGeek
 Service Station, by Aaron Skonnard
 Signum sine tinnitu--by Guy Kawasaki
 Stephen Toub
 Steve Eichert's Blog
 Steven Rockarts
 The Blog Ride
 The Coding Hillbilly
 The Daily WTF
 TheServerSide.net: News
 Tim Gifford
 Vance Morrison's Weblog
 you've been HAACKED

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 477
This Year: 47
This Month: 2
This Week: 4
Comments: 1344

 Wednesday, April 05, 2006
Wednesday, April 05, 2006 2:41:19 PM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | Tools )

In the previous post we covered off solution structure and physical directory structure. It’s time to move on to talk about the actual build process. What does it mean to build? A “build” means different things to different people. For me building consists of the following crucial steps:

  • Cleaning up the results of a previous (if any) build process.
  • Creating a build area (folder)
  • Rebuilding databases (optional)
  • Compiling all project/solution related files
  • Compiling all test related projects
  • Running unit tests

Of course there are other activities that can occur in a build process, but the ones listed above are key. Notice that the “Rebuilding databases” step is optional, as there are lots of applications that do not require the use of database engines. I’ll break the process down step by step, so you can follow along if you desire. Before we can begin putting the steps in motion we are going to make use of a tool that will allow us to automate this process. Having some form of an automated build process is the key to enhancing your productivity as a developer. Getting back to a point I keep stressing, “A Developer should be able to do a fresh checkout and be able to hit the ground running.”.  As a developer, I would much rather do a fresh checkout and run some command at the command prompt to assert that my world is set up ok. As opposed to:

  • Checking Out
  • Opening the Solution file
  • Waiting for studio to load up
  • Building the solution
  • etc,etc,etc

In order to automate your build process you can take advantage of NAnt. NAnt is the open source, more mature, equivalent to MSBuild. Let me say that I think it is great that MS has introduced an automated build tool into the mix, and I am sure that eventually I will be able to retire NAnt and utilize it. In its current implementation, I definitely feel that NAnt is more feature rich out of the box, and a little easier to work with.

Setting Up The Build File

A NAnt build file, just like an MSBuild file, is nothing more than an xmldocument that is interpreted and executed by the NAnt runtime. Most of my build files start with the following basic skeleton:

<?xml version="1.0"?>
<project name="DotNetRocks" default="all">

    <property name="debug" value="true" />

    <target name=”all”/>

</project>

That’s it. This is the start of your build file. All these couple of lines of XML are telling NAnt is that this build file represents the project named “DotNetRocks” and that there is a global property called “debug” that has its value set to true. Most important is the “default” attribute. This attribute tells NAnt that the default target to execute is the “all” target. What is a target? More on that later. Think of properties defined at the top of the build file as variables that can be accessed (using the ${propertyName} syntax) during the build process.

So far this build file does not do much of anything, let’s take care of the first item on the build to-do list.

Cleaning up the results of a previous (if any) build process

Now of course, there are currently no unwanted artifacts to clean up, as I have not even completed a successful build yet. Don’t worry about that. The first thing you need to decide is where you want all of your build artifacts to go. When I say build artifacts, I am talking about dll’s, exe’s etc that result from compiling your projects. The following screenshot shows how I will augment my directory structure to support the build process:

BuildDirectory

There is one important thing you should realize about the “build” directory. It is created by the build process and is a completely transient directory. It exists solely for facilitating the placement of files and artifacts related to building and testing the project. As a side note, this directory would also not be under source control. Which means you would have to make sure that it is “ignored” from checkins/commits. The main executable unit for NAnt files is the <target> element. You can think of <targets> as subroutines that can be invoked to perform a series of tasks. Let’s change our build file to clean/recreate the build directory:

<?xml version="1.0"?>
<project name="DotNetRocks" default="all">

    <property name="debug" value="true" />

    <target name=”all”/>   

   <target name="clean" description="remove all build products">
        <delete dir="build"  if="${directory::exists('build')}" />
    </target>

</project>

Notice that the target element has attributes such as “description” that can be used to provide descriptive information about the targets contained in the build file. What about the nested element? The <delete> element is one of many NAnt tasks that can be composed within targets to provide the functionality contained within a target. Here I am using a conditional to tell NAnt to delete the build directory if it already exists. Within a NAnt build file, unless explicitly stated, all directory references are relative to the location of the build file itself. Which means when I tell NAnt to delete the ‘build’ directory, it will attempt to delete a subfolder named build in the folder where the build file itself is contained. I am not going to dive in depth into the ins and outs of each of the NAnt tasks, as the task documentation provides lots of good information that you can use. As long as you can read/write xml, you should be set!!

Creating a build area

Ok, I’ve ensured that a build directory does not exist, so now I want to create one that will be used in the build process. I do this by adding the following to the build file:

<?xml version="1.0"?>
<project name="DotNetRocks" default="all">

    <property name="debug" value="true" />

   <target name=”all”/>

   <target name="clean" description="remove all build products">
        <delete dir="build"  if="${directory::exists('build')}" />
    </target>

    <target name="init">
        <mkdir dir="build" />
    </target>

</project>

Again, here I am making use of the mkdir task provided by NAnt to create a subdirectory named build in the directory where the build file is located. Ok, I now have a NAnt file with three targets that know nothing about each other. Of course, all this XML means nothing if I can’t actually run something that will make use of it. Let me take a quick time-out to talk about utilizing NAnt to execute targets in the build file.

Running NAnt

The advantage of having everything related to your build process in one directory (the trunk) means that performing build tasks becomes much simpler. Remember back to where NAnt would actually live in my proposed directory layout:

ToolsDirectory

Remember, NAnt is just an executable with a bunch of supporting dll’s. To run it I have to run the exe file. Because I typically run NAnt from the command line on my local machine, it would be a bit of a pain to have to open up the command prompt and execute NAnt for my build file using the following command line:

Tools\nant\bin\NAnt.exe -buildfile:dotnetrocks.build all

The arguments tell NAnt that the build file to run is the dotnetrocks.build file and that the all target should be executed. Again, this would be a pain to have to type every time, so let’s make use of a good old trusted pal. The bat file!! Create a file called build.bat that will live in the same directory as your build file. The contents of the bat file are as follows:

@echo off
cls
Tools\nant\bin\NAnt.exe -buildfile:dotnetrocks.build %*

The most important aspect of this bat file is that it allows us to execute it and pass in extra arguments to be interpreted by the build file (using the %*). So, if I wanted to execute the clean target that exists in my build file, I would just have to open up a command prompt and navigate to the directory my build file is located (use Command Prompt Here for convenience) and run the command – build clean, which would result in the following console output:

NAnt 0.85 (Build 0.85.2139.0; nightly; 11/9/2005)
Copyright (C) 2001-2005 Gerry Shaw
http://nant.sourceforge.net

Buildfile: http://www.jpboodhoo.com/dotnetrocks.build
Target framework: Microsoft .NET Framework 2.0
Target(s) specified: clean

     [echo] Loading local.properties.xml

clean:


BUILD SUCCEEDED

Total time: 0.2 seconds.


D:\Development\dotnetrocks\2006\testDrivenDevelopment>

With this setup in place I can quickly execute any of the targets in my build file with ease. Ok, I am quickly seeing that all of this information is probably going to be too much for this one blog post, so I will span this over a couple of more entries. Tomorrow we’ll pick up the process by compiling the application and linking targets!!

 

TODO