Setting up an Ant build script for your Scala project

May 3rd, 2010 and revised July 20th, 2010    , ,     2 Comments

Introduction

This is a small writeup which gives one way of setting up a build system for your Scala project. Here Apache Ant is used for managing this process, where the whole configuration is contained within a single build.xml file placed in the project’s root. Execution is done from command line or within your IDE environment.

Prerequisites

Install and configure Scala:

  • Define and set the SCALA_HOME variable in the OS environment
  • Update the PATH variable in the OS environment to include Scala’s bin directory

Install and configure Ant:

  • Define and set the ANT_HOME variable in the OS environment
  • Update the PATH variable in the OS environment to include Ant’s bin directory
  • Optional: If you encounter memory problems, define and set ANT_OPTS=-Xmx500M with JVM memory configuration in the OS environment

Install and configure Java:

  • Define and set the JAVA_HOME variable in the OS environment
  • Update the PATH variable in the OS environment to include Java’s bin directory

Find a suitable file structure for the project:

project-name/
  build/
  lib/
  src/
  test/
  build.xml

The Ant build script

Order of Ant targets:

  • build <- package <- doc <- compile <- init
  • clean <- init

Using project-name/build.xml:

<?xml version="1.0" encoding="UTF-8"?>
 
<project name="ProjectName" default="build" basedir=".">
  <description>Project Build Script</description>
 
  <!-- Targets -->
  <target name="build" depends="package" description="Build complete project"/>
 
  <target name="clean" depends="init" description="Remove previously built files">
    <delete dir="${build.dir}" includeemptydirs="true" quiet="true"/>
  </target>
 
  <target name="init">
    <property environment="env"/>
 
    <!-- check for required tools -->
    <fail message="Missing SCALA_HOME variable in OS environment">
      <condition><isset property="${env.SCALA_HOME}"/></condition>
    </fail>
    <fail message="Missing JAVA_HOME variable in OS environment">
      <condition><isset property="${env.JAVA_HOME}"/></condition>
    </fail>
 
    <!-- Paths -->
    <property name="src.dir" location="${basedir}/src"/>
    <property name="lib.dir" location="${basedir}/lib"/>
    <property name="build.dir" location="${basedir}/build"/>
    <property name="build-classes.dir" location="${build.dir}/classes"/>
    <property name="build-lib.dir" location="${build.dir}/lib"/>
    <property name="build-doc.dir" location="${build.dir}/doc"/>
    <property name="java.dir" location="${env.JAVA_HOME}"/>
    <property name="scala.dir" location="${env.SCALA_HOME}"/>
    <property name="scala-library.jar" location="${scala.dir}/lib/scala-library.jar"/>
    <property name="scala-compiler.jar" location="${scala.dir}/lib/scala-compiler.jar"/>
 
    <path id="project.classpath">
      <pathelement location="${scala-library.jar}"/>
      <pathelement location="${build-classes.dir}"/> <!-- used during recompilation -->
    </path>
 
    <path id="scala.classpath">
      <pathelement location="${scala-compiler.jar}"/>
      <pathelement location="${scala-library.jar}"/>
    </path>	
 
    <taskdef resource="scala/tools/ant/antlib.xml" classpathref="scala.classpath"/>
 
    <echo message="Init project"/>
    <echo message=" with Scala path = ${scala.dir}"/>
    <echo message=" with Java path = ${java.dir}"/>
 
    <uptodate property="build.uptodate" targetfile="${build.dir}/build.done">
      <srcfiles dir= "${src.dir}" includes="**"/>
      <srcfiles dir= "${lib.dir}" includes="**"/>
    </uptodate>
  </target>
 
  <target name="compile" depends="init" unless="build.uptodate">
    <mkdir dir="${build-classes.dir}"/>
    <scalac
      destdir="${build-classes.dir}"
      classpathref="project.classpath">
      <include name="**/*.scala"/>
      <src><pathelement location="${src.dir}"/></src>
    </scalac>
  </target>
 
  <target name="doc" depends="compile" unless="build.uptodate">
    <mkdir dir="${build-doc.dir}"/>
    <scaladoc
      srcdir="${src.dir}"
      destdir="${build-doc.dir}"
      doctitle="Project API documentation"
      classpathref="project.classpath">
      <include name="**/*.scala"/>
    </scaladoc>
  </target>
 
  <target name="package" depends="doc" unless="build.uptodate">
    <mkdir dir="${build-lib.dir}"/>
    <jar destfile="${build-lib.dir}/project.jar">
      <fileset dir="${build-classes.dir}"/>
    </jar>
    <touch file="${build.dir}/build.done"/> <!-- mark build as up-to-date -->
  </target>
</project>

Reference for Scalac Ant task

Arguments: srcdir, srcref, destdir, classpath, classpathref, sourcepath, sourcepathref, bootclasspath, bootclasspathref, extdirs, extdirsref, encoding, target={jvm-1.5, msil}, force={yes,no}, fork={yes,no}, logging={none,verbose,debug}, debuginfo={none,source,line,vars,notailcalls}, addparams, scalacdebugging, deprecation={yes,no}, optimise={yes,no}, unchecked={yes,no}, failonerror={yes,no}

Nested arguments: src,classpath,sourcepath,bootclasspath,extdirs

Alternative build systems

Simple Build Tool (SBT) - a Scala-centric build system
Maven - a build system aimed at larger projects with many external dependencies

Testing frameworks

Scalatest.org: ScalaTest - dsl-driven framework that supports various testing methodologies
ScalaCheck - functional programming oriented with automatic test-case generation

References

2 Responses to “Setting up an Ant build script for your Scala project”

  1. Eli Gottlieb says:

    Strange, my system’s installation of Scala doesn’t have a “scala/tools/ant/antlib.xml” anywhere. Where are we supposed to find that?

  2. Trond says:

    The “scala/tools/ant/antlib.xml” is located within the scala-compiler.jar, which itself is located at %SCALA_HOME%/lib/. Might be related to a problem with the script. I updated the check in init to reference env.SCALA_HOME and env.JAVA_HOME properly, and verified it that it ran when everything is configured correctly.

Leave a Reply

Available formating tags: <blockquote></blockquote> <code></code> <em></em> <strong></strong>