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_HOMEvariable in the OS environment - Update the
PATHvariable in the OS environment to include Scala’s bin directory
Install and configure Ant:
- Define and set the
ANT_HOMEvariable in the OS environment - Update the
PATHvariable in the OS environment to include Ant’s bin directory - Optional: If you encounter memory problems, define and set
with JVM memory configuration in the OS environmentANT_OPTS=-Xmx500M
Install and configure Java:
- Define and set the
JAVA_HOMEvariable in the OS environment - Update the
PATHvariable 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 <- initclean <- 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
Strange, my system’s installation of Scala doesn’t have a “scala/tools/ant/antlib.xml” anywhere. Where are we supposed to find that?
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.