key tool in any software development arsenal is a structured build process. NAnt is a tool for building Visual Studio .NET applications that you can incorporate into your development process and that provides something greater than simply compiling code.
In teams of developers, there is always going to be a need for a structured build process. This can be a manual process, but most likely you’ll want to automate this process as much as possible. In today’s ultra-fast world, continuous integration is key to determining where you are in your development project. If multiple developers check in code at various times, it is always a good thing to have an “integration check”?something to make sure all the code gels together.
The idea behind continuous integration is that when a developer checks code in, a process is triggered to perform a system build to make sure the code doesn’t break the build. This action usually involves the execution of unit tests as well. If the build, along with the unit tests, succeeds, the developer has immediate feedback that the check-in didn’t break the build. No one wants to be the person who broke the build!
The typical build process involves actions like these:
- Pulling source updates from the source code repository
- Preparing the build directories
- Compiling the source code
- Running the unit tests
- Creating the setup packages
- Deploying the output binaries
- Notifying the team that a new build is available
If you incorporated Visual Studio .NET into a build process such as this, you would create an elaborate batch file that calls out to Visual Studio .NET’s command-line (devenv.exe) along with the additional tools to handle the tasks that .NET couldn’t. Another way to attack it may be to write some hooks into the .NET IDE automation model to handle some of these tasks during a build, but who has the time? The good news is that there are tools available built specifically to handle these types of build process requirements. One of the more popular build tools in the .NET community is NAnt.
NAnt
NAnt is an open-source build automation tool that works off of an XML document to execute a sequence of defined tasks that build .NET applications. NAnt is a port of the popular Ant build tool from the Java community. Ant was created to address some of the deficiencies of older shell-based build tools such as make and nmake. If you’ve ever written make scripts, you will appreciate NAnt’s ease of use and its extensible architecture.
NAnt works well as an automated build tool. It supports compiling C#, Visual Basic .NET, C++, and J# files. It can compile these files against the .NET Framework platform [v1.x, V2.0 (Beta 1)] and Mono.
Installing NAnt
The first thing to incorporate NAnt into your build process is to get NAnt up and running on your computer. You can download the latest stable release or a recent nightly build from the project site. The nightly builds are typically very stable, but for the purposes of this article, I will work with the latest stable release at the time of this writing, NAnt v.0.85-rc1.
Once you’ve downloaded the zip package, unzip the contents into a directory on your file system. To make it easier for you to execute your NAnt build scripts, place the location of NAnt’s in directory into your system’s PATH environment variable. You can test your installation by opening a command shell and typing nant -help at the command prompt. If everything is successful, you will see a list of command-line options for the NAnt build tool.
The NAnt Build Script
Executing the build script is as simple as typing in “nant” at the command prompt. NAnt probes its current directory (the directory from which it was executed) for any file ending in .build, and attempts to execute it. If more than one file within the directory ends in .build, NAnt throws an exception unless one of the files is named default.build. You can also inform NAnt which script you wish to execute by specifying the -f flag:
C:> nant -f:MyApp.build
The NAnt build script is an XML document comprised of one
Each element type in a NAnt build script (the project, target, tasks, etc.) has a defined set of attributes associated with that particular type. Some of these attributes are required and others are optional. These attributes provide additional details about how to execute each particular type.
To better understand the build script, it is wise to get a better understanding of the main parts of any build script.
Properties
A build script can contain zero to many property definitions. A property in NAnt is analogous to a variable. You define a property by the use of a
To access a property value, you place the name of the property between the identifiers ${“ and “}. For example, to access the src.dir property declared earlier, specify the following:
Default property values are defined within the build script. If you need to override any property value, you can specify the -D command-line flag and supply the new property value.
C:> Nant ?D:src.dir=NotTheDefaultSourceDirectory
Properties can be set as read only by setting the Readonly attribute on the
You can create property values that are global to all build scripts on your computer by defining the property definitions in NAnt’s configuration file (nant.exe.config, found in the NAnt in directory) under the
... ...
NAnt has a few built-in properties that can be used within your build script; a sampling of these properties can be found in Table 1.
Table 1: These are a sampling of built-in NAnt properties.
Property |
Description |
nant.project.basedir |
The absolute path of the project’s basedir |
nant.project.buildfile |
The absolute path of the buildfile |
nant.settings.currentframework |
The current target framework |
nant.settings.currentframework.sdkdirectory |
The SDK directory of the current target framework |
Tasks
Tasks define a command to be executed. Tasks are XML elements with a set of defined attributes and child elements that prescribe the options for the task. For example, if you want to execute a command to delete a directory, use the
The dir attribute is specific to the
If you want your build script to send an e-mail to the development team when the build completes, you could use the
Tasks define the power of NAnt. There are over 70 tasks included in the NAnt core tool. A small sampling of some the available tasks is listed in Table 2. Additional tasks are available through external libraries, such as NAntContrib. If the available tasks don’t quite get the job done, you can create custom tasks through the extensible architecture.
|
Table 2: These are just some of the tasks available in the NAnt core tool.
File System Tasks |
Description |
|
Copies a file or set of files to a new file or directory |
|
Deletes a file, a set of files or a directory |
|
Creates a directory |
|
Modifies file attributes |
?.NET Tasks |
Description |
|
Compiles Visual Basic .NET files |
|
Compiles C# files |
|
Compiles Visual Studio .NET solutions (or sets of projects). Determines project dependencies from inter-project references |
|
Imports a type-library to a .NET assembly |
|
Installs or removes .NET Services |
?Misc Tasks |
Description |
|
Sends an STMP message |
|
Creates a zip file from the specified file list |
|
Extracts a zip package |
|
Runs NDoc to create the documentation |
|
Runs tests using the NUnit v2.2 framework |
Although each task has its own custom attributes defined to support its execution, every task has a common set of attributes. These are listed in Table 3.
Table 3: These are task common attributes.
Attributes |
Description |
failonerror |
If set to True, stops the build if this task fails. Otherwise, it just reports. |
if |
An expression that should evaluate to True for this target to execute |
unless |
An expression that causes the target to be skipped when it evaluates to True |
verbose |
Determines whether the task will report detailed log messages |
Targets
The
Targets can be dependent on other targets. For example, if within the build script you want to clean out the output directory before the build, you might define something like this:
By specifying a dependency with the Depends attribute, the target will not execute until all of its dependency targets have executed first. One of the nice features of NAnt is that it executes a target only once. So if multiple targets have a dependency on the same target, that dependent target executes only once.
...
Table 4 lists the attributes and the descriptions for the
Table 4: Here’s a list of
Attributes |
Description |
name |
The name of the target |
depends |
A comma-separated list of names and targets on which the target depends |
if |
An expression that should evaluate to True for this target to execute |
unless |
An expression that causes the target to be skipped when it evaluates to True |
description |
A short description of the target’s purpose |
Projects
The
... ...
Table 5: Here’s a list of
Attributes |
Description |
name |
The name of the project |
default |
An expression that should evaluate to True for this target to execute |
basedir |
The base directory from which all paths are determined. If it isn’t specified, the build script’s parent directory is used. |