WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Using NAnt to Build .NET Projects
Pages: 1, 2

Adding Dependencies

Now let's add a second target, one that will execute HelloWorld.exe after it is compiled. The new version of the build file looks like this:



<?xml version="1.0"?>
<project name="Hello World" default="run" basedir=".">
<target name="build">
<csc target="exe" output="HelloWorld.exe"> <sources>
<includes name="HelloWorld.cs"/>
</sources> </csc> </target> <target name="run" depends="build"> <exec program="HelloWorld.exe"/> </target>
</project>

Listing 2. Build script containing two dependent targets

The new run target contains a single action, exec, which executes a program. It also contains a dependency on the build target. This means that before the run target will be executed, the build target must also be executed, and it must execute successfully. Notice that in the project node, we also changed the default attribute to point to the run target instead of the build target. Because run depends on build, this ensures that the application will be built before it is run.

If the build target fails for some reason (most likely due to an error in your code caught by the compiler), the run target won't be executed. You can test this by intentionally inserting a syntax error in your HelloWorld code and then running NAnt again on your modified version of default.build. NAnt will display the compiler's error messages to the console so you can see what went wrong.

Creating Clean Builds

NAnt won't run the compiler if you have a compiled binary that's newer than the the source code -- in other words, it doesn't compile anything it doesn't have to. In addition, if multiple dependencies exist in a build file (that is, two or more components both depend on another component that is to be built), NAnt is smart enough to only build the dependent component once. This efficient method can make building large projects compile much more quickly. But in some cases you may want to have a way to say "build everything regardless of what I may have" -- in other words, wipe out all existing compiled binaries and do a clean build. For this reason, many build files contain a clean target so developers have the option of wiping out everything they've built and starting with a clean slate. Here's what a build file with a clean target looks like:


<?xml version="1.0"?>
<project name="Hello World" default="run" basedir=".">
  <target name="build">
    <mkdir dir="bin" />
    
    <csc target="exe" output="bin\HelloWorld.exe">
      <sources>
        <includes name="HelloWorld.cs"/>
      </sources>
    </csc>
  </target>

  <target name="clean">
    <delete dir="bin" failonerror="false"/>
  </target>	  

  <target name="run" depends="build">
    <exec program="bin\HelloWorld.exe"/>
  </target>
</project>

Listing 3. Build script containing a clean target

You probably don't want to run the clean target every time you build, just every once in a while. To execute the clean target, use the command line:

  nant clean

This causes NAnt to execute only the clean target (in other words, your project won't actually be built, it'll only clean out the contents of \bin). You can also see that in this version of the build script we've added a mkdir action to create a separate \bin subdirectory, into which compiled binaries are deposited. To clean the contents of the \bin subdirectory and build your project, simply use the command line

  nant clean build

Integration with Unit Testing

NAnt really shines in situations when you need to integrate your build process with other processes, such as email notifications or automated unit testing. A complete discussion of the NUnit unit testing framework is way beyond the scope of this article, but suffice it to say that NAnt plays very nicely with it. Listing 4 shows an example of a build file that builds an application and executes NUnit as a seamless part of the build process.

<?xml version="1.0"?>
<project name="NUnit Integration" default="test">
  <property name="build.dir" value="\dev\src\myproject\" />

  <target name="build">
    <csc target="library" output="account.dll">
      <sources>
        <includes name="account.cs" />
      </sources>
    </csc>
  </target>

  <target name="test" depends="build">
    <csc target="library" output="account-test.dll">
      <sources>
        <includes name="account-test.cs" />
      </sources>
      <references>
        <includes name="nunit.framework.dll" />
        <includes name="account.dll" />
      </references>
    </csc>
  
    <nunit2>
      <test assemblyname="${build.dir}account-test.dll" />
    </nunit2>
  </target>
</project>

Listing 4. Building components and integrating with NUnit 2.0

This build file first specifies the location of the project file in the form of a property. It's useful, but not required, to put values that might change or be reused in a property variable; properties are usually included at the top of the build file but can be supplied at the command line instead, if needed. In this case, specifying the project file as a property is useful because that information needs to be passed to NUnit later in the build process.

Next, the build file builds both the component (account.dll) and the test fixture (account-test.dll), in order. Both builds include the target="library" attribute so the compiler knows to build a component assembly rather than an .exe. You can also see in the listing that the test fixture references two dependent assemblies -- your business logic component and the NUnit framework -- using the references node. This is required any time you build a project that depends on an external library.

Finally, after the test fixture and project have been built, the build script calls NUnit, passing in the name of the assembly that contains your tests and generating an output file in XML format that lets you know the results of the tests that were run.

One note regarding NUnit integration -- be sure to use a recent snapshot of NAnt if you're using NUnit 2.0! Because of significant changes in the most recent version of NUnit, the current "stable" build won't work with NUnit 2.0 at all. More recent versions of NAnt are quite stable and support NUnit 2.0 well.

Hopefuly this article will serve as a useful introduction to NAnt. To learn more about what NAnt can do, check out NAnt's documentation, particularly the task reference, which contains a concise list of the tasks NAnt supports. There's also a mailing list, if you need additional help; more info on that is on the NAnt web site. Happy building!

The sample code can be downloaded here.

Jeffrey McManus is eBay's Senior Manager of Developer Relations and is the author of several books on software development.


Return to ONDotnet.com