oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Using NAnt to Build .NET Projects

by Jeffrey McManus

With Visual Studio .NET, you can easily build and compile .NET projects that contain any number of subprojects -- collections of interdependent web pages, executables, DLL assemblies, and so forth -- with a single menu command. But relying on a single programmer hitting the "compile" button doesn't always work for large and complicated projects. What if you don't care to install VS.NET on every machine you own? Wouldn't it be nice if you had a way to automate the software build process so nobody ever has to hit the compile button? There are many benefits to an automated build process, but to make it happen, you've got to have a build tool.

Build tools solve problems associated with the process of compiling software. Simple software projects written by small development teams may not need a build tool -- you fire up the compiler, it builds your code into a binary executable, and you're done. But modern software is typically componentized, with each project dependent on one or more subprojects. The set of dependent components upon which your project relies may be written by many different people, who may check in different versions of their code at different times.

If one component fails to compile, or an out-of-date version of a component is used in a build, it can throw your whole project off track. Developers of complex projects typically use build tools to help manage this aspect of team development.

It's common for compilers to spew forth error messages if there's something in your code that causes compiler errors. But in a project that is comprised of several binary executables and several more dependent components, it may be difficult to pin down exactly where the failure took place. Ideally, you want a tool that builds the external dependencies required by your application, providing logs and notifications when something goes kablooey.

Enter Ant. The original Ant tool was originally created by the Apache Jakarta Project. It was created to overcome a number of frustrating aspects of existing build tools (such as the make tool that's commonly used on Unix and elsewhere). One imporant shortcoming addressed by Ant is the fact that build tools are commonly bound to a particular operating system, development environment, or language. Ant, in contrast, is designed to be platform-independent. To facilitate platform independence, the file you use to tell Ant how to compile your project is in XML format. This means that there are no operating system dependencies (aside from your development framework of choice -- Java, .NET, or whatever -- and Ant itself).

In addition to its cross-platform goodness, Ant build files are declarative. This means that you can accomplish a great deal without having to write code -- most of the heavy lifting is done by declarations you include in the XML file. (If your build process is complicated enough that you need to execute code, Ant gives you the flexibility to do that as well, by writing code to extend the tool.) And because the build file is in XML, you can use your favorite editor to create it.

Ant Comes to the .NET Framework

NAnt is a .NET implementation of Ant. It is written in C#, but is designed to work with any .NET language (the NAnt distribution contains examples for C#, VB.NET, and JScript.NET). You can even combine projects written in different .NET languages in one build, so if you need to build a VB.NET client application that has several dependent assemblies written in both VB.NET and C#, NAnt can deal with it easily. If that isn't enough, NAnt can even run multiple compilers, so if you want to use Microsoft's tools alongside the Mono C# compiler, NAnt can handle that, too.

To use NAnt, it helps to have a handle on how the command-line .NET compilers work. In this article, I'll use csc, the C# compiler, for the examples, but you can just as easily use vbc or another compiler -- or several compilers at the same time, if you prefer.

Hello, NAnt

The first step to using NAnt is to download it from the NAnt web site. The most recent "stable" build of NAnt as of this writing is, but the more recent nightly builds are solid, as well. Importantly for developers who are using NAnt as part of a continuous integration and build process, the most recent builds of NAnt contain integration with the excellent NUnit 2.0 unit testing tool. Because NUnit was significantly re-engineered from version 1 to version 2, if you use NUnit 2 you'll want to use a recent build of NAnt to take advantage of its features.

To see how NAnt works, let's take a look at one of the simplest possible scenarios -- building a single binary executable written in C# that runs in the console. Here is the code for the application:

  public class HelloWorld {
    static void Main() {
      System.Console.WriteLine("Hello world.");

Of course, you could just compile your simple project using the C# command line compiler. The command to do this is simplicity itself:

  csc *.cs
The output of this command is the executable binary HelloWorld.exe. To do the same thing using NAnt, you first create an XML file that ends in the extension .build. Here's an NAnt build file called that does the same thing as the single command line above:
<?xml version="1.0"?>
  <project name="Hello World" default="build" basedir=".">
    <target name="build">
      <csc target="exe" output="HelloWorld.exe">
          <includes name="HelloWorld.cs"/>

Listing 1. Basic NAnt build script to create a single executable

Once you've created a build file, to build your project, you simply execute the command line:


As long as the current directory contains the .build file, and the NAnt executable itself is in your current PATH, that's all you need to type. NAnt will parse the contents of and perform the tasks specified in the file.

Of course, using a tool like NAnt for a project comprised of a single class like this is massive overkill. But what if you were interested in first building the executable, and then running it? Or what if you want to build one or more dependencies and then build the main executable? This is where a build tool like NAnt can save loads of time.

An NAnt build file is primarily comprised of targets, tasks, and dependencies. A task is a single action you want NAnt to perform. Examples of tasks supported by NAnt include running a compiler, copying or deleting files, sending email, even zipping up sets of files (a complete list of tasks supported by NAnt is here).

A target represents a set of tasks you want NAnt to perform. Targets enable you to group tasks together logically. So if you want NAnt to delete the contents of the \bin directory, compile five executables, and copy the resulting binaries somewhere, those actions could be grouped together into a single target.

You can think of a dependency as a relationship between two targets. For example, in Listing 1 there is a single target. Its name is build; it runs the compiler against a single source file. Setting the default attribute of the <project> tag to build causes the build target to be processed by NAnt.

Within the csc task is a subnode called <sources> that indicates the source code file to be compiled.

Pages: 1, 2

Next Pagearrow