Question

I'm new to NAnt but have some experience with Ant and CruiseControl.

What I want to do is have my SVN project include all tools needed (like NUnit and Mocks etc) so I can check out onto a fresh machine and build. This strategy is outlined by J.P Boodhoo here.

So far so good if I only want to run on Windows, but I want to be able to check out onto Linux and build/test/run against Mono too. I want no dependencies external to the SVN project. I don't mind having two sets of tools in the project but want only one NAnt build file

This must be possible - but how? what are the tricks / 'traps for young players'

Was it helpful?

Solution

This shouldn't be a particularly difficult excercise. We do some fairly similar stuff on one of my projects since half of it runs on Java using Ant to run relevant targets, and the other half is .Net (C#) for the UI. The projects get run on windows machines for development, but the servers (Java) run linux, but in the UAT environment (linux) we need to run the nunits (integration tests). The real trick (not really a difficult trick) behind this is having a NAnt build file that can run in both environments which seems to be the same thing you're trying to do here.

Of course you realise you'll need to install NAnt on Mono first:

$ export MONO_NO_UNLOAD=1
$ make clean
$ make
$ mono bin/NAnt.exe clean build

And then your build file needs to be written in such a way that it seperates concerns. Some parts of the build file written for windows will not work in linux for example. So you really just need to divide it up ito specific targets in the build file. After that, there are a number of ways you can run a specific targets from the command line. An example might look like this:

<project name="DualBuild">
  <property name="windowsDotNetPath" value="C:\WINDOWS\Microsoft.NET\Framework\v3.5" />
  <property name="windowsSolutionPath" value="D:\WorkingDirectory\branches\1234\source" />
  <property name="windowsNUnitPath" value="C:\Program Files\NUnit-Net-2.0 2.2.8\bin" />
  <property name="monoPath" value="You get the idea..." />

  <target name="BuildAndTestOnWindows" depends="WinUpdateRevision, WinBuild, WinTest" />
  <target name="BuildAndTestOnLinux" depends="MonoUpdateRevision, MonoBuild, MonoTest" />

  <target name="WinUpdateRevision">
    <delete file="${windowsSolutionPath}\Properties\AssemblyInfo.cs" />
    <exec program="subwcrev.exe" basedir="C:\Program Files\TortoiseSVN\bin\"
          workingdir="${windowsSolutionPath}\Properties"
          commandline="${windowsSolutionPath} .\AssemblyInfoTemplate.cs
                       .\AssemblyInfo.cs" />
    <delete file="${windowsSolutionPath}\Properties\AssemblyInfo.cs" />
    <exec program="subwcrev.exe" basedir="C:\Program Files\TortoiseSVN\bin\"
          workingdir="${windowsSolutionPath}\Properties"
          commandline="${windowsSolutionPath} .\AssemblyInfoTemplate.cs 
                       .\AssemblyInfo.cs" />
  </target>

  <target name="WinBuild">
    <exec program="msbuild.exe"
          basedir="${windowsDotNetPath}"
          workingdir="${windowsSolutionPath}"
          commandline="MySolution.sln /logger:ThoughtWorks.CruiseControl.MsBuild.XmlLogger,
                       ThoughtWorks.CruiseControl.MsBuild.dll;msbuild-output.xml 
                       /nologo /verbosity:normal /noconsolelogger 
                       /p:Configuration=Debug /target:Rebuild" />
  </target>

  <target name="WinTest">
    <exec program="NCover.Console.exe"
          basedir="C:\Program Files\NCover"
          workingdir="${windowsSolutionPath}">
      <arg value="//x &quot;ClientCoverage.xml&quot;" />
      <arg value="&quot;C:\Program Files\NUnit-Net-2.0 2.2.8\bin
                       \nunit-console.exe&quot; 
                       MySolution.nunit /xml=nunit-output.xml /nologo" />
    </exec>
  </target>

  <target name="MonoUpdateRevision">
    You get the idea...
  </target>


  <target name="MonoBuild">
    You get the idea...
  </target>

  <target name="MonoTest">
    You get the idea...
  </target>

</project>

For brevity, I've left both sides out. The neat thing is you can use NUnit as well as NAnt on both environments and that makes things really easy from a dependency point of view. And for each executable you can swap out for others that work in that environment, for example (xBuild for MSBuild, and svn for tortoise etc)

For more help on Nunit etc on Mono, check out this fantastic post.

Hope that helps,

Cheers,

Rob G

OTHER TIPS

@Rob G - Hey! That's my post! ;)

For some other good examples, be sure to browse the NUnit source code. I work closely with Charlie whenever I can to make sure it is building and testing on Mono. He tries to run whenever he can as well.

It is worth noting that a lot of tools like Nant run on mono 'out of the box', i.e.

mono nant.exe

works

I use the following template. It allows simple building on any platform (build on Win or ./build.sh on linux) and minimises duplication in the build scripts.


The NAnt executable is stored with the project in tools\nant.

The build config file determines which build tool to use, either MSBuild or xbuild (in this case, for Windows I require the VS2015 MSBuild version, change the path as required).

The build-csproj build target can be reused for when you have multiple projects within a solution.

The test-project target would need to be expanded upon for your needs.

build.bat

@tools\nant\nant.exe %*

build.sh

#!/bin/sh

/usr/bin/cli tools/nant/NAnt.exe "$@"

default.build

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

  <if test="${not property::exists('configuration')}">
    <property name="configuration" value="release" readonly="true" />
  </if>

  <if test="${platform::is-windows()}">
    <property name="BuildTool" value="C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" readonly="true"/>
  </if>
  <if test="${platform::is-unix()}">
    <property name="BuildTool" value="xbuild" readonly="true"/>
  </if>

  <property name="TestTool" value="tools/mytesttool.exe"/>

  <target name="all" depends="myproject myprojectlib" />

  <target name="build-csproj" description="Build a given csproj">
    <!-- Must not be called standalone as it requires some properties set. -->
    <exec program="${BuildTool}">
      <arg path="src/${ProjectName}/${ProjectName}.csproj" />
      <arg line="/property:Configuration=${configuration}" />
      <arg value="/target:Rebuild" />
      <arg value="/verbosity:normal" />
      <arg value="/nologo" />
    </exec>
  </target>

  <target name="test-project">
    <!-- Must not be called standalone as it requires some properties set. -->
    <exec program="${TestTool}">
      <arg path="my/${ProjectName}/tests/path/for/tool" />
      <arg value="/aproperty=value" />
    </exec>
  </target>

  <target name="myproject" description="Build the project">
    <property name="ProjectName" value="MyProject"/>
    <call target="build-csproj" />
    <call target="test-project" />
  </target>

  <target name="myprojectlib" description="Build the project's library dll">
    <property name="ProjectName" value="MyProjectLib"/>
    <call target="build-csproj" />
    <call target="test-project" />
  </target>

</project>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top