How to build a Scala project with Apache Ant

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 18.18, “Building a Scala Project with Apache Ant.”

Problem

You want to use Apache Ant to build your Scala project.

Solution

Assuming you have a Maven- and SBT-like project directory structure as described in Recipe 18.1, create the following Ant build.xml file in the root directory of your project:

<project name="AntCompileTest" default="compile" basedir=".">

  <!-- mostly from: http://www.scala-lang.org/node/98 -->

  <property name="sources.dir" value="src" />
  <property name="scala-source.dir" value="main/scala" />
  <property name="scala-test.dir" value="main/test" />
  <property name="build.dir" value="classes" />
  
  <!-- set scala.home -->
  <property environment="env" />
  <property name="scala.home" value="${env.SCALA_HOME}" />
  
  <target name="init">
    <property name="scala-library.jar" 
              value="${scala.home}/lib/scala-library.jar" />
    <property name="scala-compiler.jar" 
              value="${scala.home}/lib/scala-compiler.jar" /> 
    <property name="scala.reflect" 
              value="${scala.home}/lib/scala-reflect.jar"/>
    <path id="build.classpath">
      <pathelement location="${scala-library.jar}" />
      <pathelement location="${build.dir}" />
    </path>
    <taskdef resource="scala/tools/ant/antlib.xml">
      <classpath>
        <pathelement location="${scala-compiler.jar}" />
        <pathelement location="${scala-library.jar}" />
        <pathelement location="${scala.reflect}"/>
      </classpath>
    </taskdef>
  </target>

  <target name="compile" depends="init">
    <mkdir dir="${build.dir}" />
    <scalac srcdir="${sources.dir}"
            destdir="${build.dir}"
            classpathref="build.classpath"
            deprecation="on">
      <include name="${scala-source.dir}/**/*.scala" />
      <exclude name="${scala-test.dir}/**/*.scala" />
    </scalac>
  </target>

</project>

You can then run the usual ant command, which by default will compile your files to a new classes folder under the root directory of your project. Running ant on a small project produces output like this:

$ ant
Buildfile: /Users/Al/Projects/AntExample/build.xml

init:

compile:
 [scalac] Compiling 1 source file to /Users/Al/Projects/AntExample/classes

BUILD SUCCESSFUL
Total time: 5 seconds

Discussion

In general, when learning a new technology it’s best to learn the tools of that technology, and in this case the preferred build tool for Scala projects is SBT. (As a friend once said, when we went from C to Java we didn’t attempt to bring make along with us.) Once you grasp the SBT concepts, you’ll find that it’s both a simple and powerful tool, especially for basic projects, and you can find a lot of support in the Scala community.

That being said, you’re also hit with a lot of changes when first learning a new technology, and at the beginning it can be helpful to use the tools you’re already comfortable with, so this recipe demonstrates how to use Ant to compile a Scala project to help you get into Scala in a comfortable way.

Recommendation: If someone brought me into their organization to help them adopt Scala, SBT is one of the first things I’d teach. In this case I think you’re better off just diving into the water, so to speak. It doesn’t take that long to grasp the SBT basics.

The build.xml code

The secret sauce to this Ant recipe is the init target, whose source code can be found on the official Scala website at www.scala-lang.org/node/98. This target does the work necessary to make the scalac Ant task available to you.

As you can see from the code, the build target depends on the init target, and uses scalac to compile all the files in the source directory, while skipping the files in the test directory. Of course that approach is completely optional, and you can adjust it to meet your needs.

The antlib.xml file referred to in the taskdef tag is shipped with the Scala distribution. You can demonstrate this on a Unix system with the following command:

$ jar tvf ${SCALA_HOME}/lib/scala-compiler.jar | grep -i antlib

The build.xml file shown here is slightly different than the file shown on the Scala website. Specifically, I found that the scala.home property needed to be set manually, and with Scala 2.10 it’s also necessary to add the scala.reflect lines to the build file. The compilation process worked fine with Ant 1.8.4 once I made those changes.

In addition to this scalac Ant task, there are also fsc and scaladoc tasks. See the Scala Ant Tasks page on the official Scala website for more information.

Creating a JAR file with Ant

Once you’ve compiled your Scala classes, you can treat them as normal Java class files. For instance, you can create a JAR file from them using the following simplified Ant task. This task shows how to create a JAR file named hello.jar from the compiled classes in the classes directory, and a simple manifest in a Manifest.txt file. Here’s the create-jar task, which you can add to the earlier build.xml file:

<target name="create-jar" depends="compile">
  <jar basedir="classes" 
       jarfile="hello.jar" 
       manifest="Manifest.txt"/>
</target>

Assuming the Hello class in the hello package has the main method for your application (or extends the App trait), place this line in the Manifest.txt file:

Main-Class: hello.Hello

After adding this task to your build.xml file, you can run it as follows from the root directory of your project:

$ ant create-jar

That command creates a JAR file named hello.jar in the root directory. You can then run the JAR file with this scala command:

$ scala hello.jar

This is similar to running java -jar on a JAR file created by a Java application, but because a Scala application has dependencies on its own JAR files, such as $SCALA_HOME/lib/scala-library.jar, you need to run the JAR file with the scala interpreter, as shown. You can run the JAR file with the Java interpreter, but this takes a bit more work. See Recipe 18.14, “Deploy a Single, Executable JAR File,” for details on that process.

See Also

The Scala Cookbook

This tutorial is sponsored by the Scala Cookbook, which I wrote for O’Reilly:

You can find the Scala Cookbook at these locations: