Scala projects with Eclipse PDE Build

PDE Build is the stand­ard build tool from Ec­lipse. It is used to ex­port OSGi bundles, plu­gins, fea­tures or products. Run­ning in head­less mode, PDE Build can be used for auto­matic builds without a GUI. The Scala IDE does not sup­port PDE Build yet. In or­der to com­pile Scala pro­jects you have to do some manual work.

This art­icle relates to an old ver­sion of the Scala IDE for Ec­lipse. In­form­a­tion about the latest ver­sion can be found in a newer post!

First of all, you need an Ant script that can be hooked into the build pro­cess. The script’s name should be customBuildCallbacks.xml and it should be loc­ated at the pro­ject’s root:

de.michel-kraemer.myplugin/
  |- bin
  |- META-INF
  |- src
  |- build.properties
  |- customBuildCallbacks.xml

The same dir­ect­ory con­tains the plu­gin’s build.properties file. (Please do not mix this one up with the more gen­eral build.properties file used for head­less builds!) The fol­low­ing lines have to be ad­ded to this file to hook the new Ant script into the build pro­cess:

customBuildCallbacks=customBuildCallbacks.xml
customBuildCallbacks.inheritall=true

The second line en­ables ac­cess to global prop­er­ties like ${build.result.folder}.

The Ant script can con­tain tar­gets with pre­defined names. They will be called by PDE Build even­tu­ally dur­ing the build pro­cess. You can copy a tem­plate, that already con­tains all pre­defined tar­gets (but empty) from the fol­low­ing dir­ect­ory: ${ec­lipse.home}/­plu­gins/­org.­ec­lipse.­pde.­build_*/­tem­plates/­plu­gins/

The post.compile.@dot tar­get will be called when the source files are about to be com­piled, so that’s the best point to ex­ecute the Scala com­piler manu­ally. There­fore, some ad­di­tional Ant tasks have to be defined. These can be found in the Scala Lib­rary which is de­livered with the Scala IDE. You can auto­mat­ic­ally search for the re­quired jar files us­ing the fol­low­ing snip­pet:

<!-- find eclipse.home -->
<pathconvert property="eclipse.home">
    <path location="${eclipse.launcher}" />
    <mapper>
        <!-- map "${eclipse.home}/eclipse.exe" to "${eclipse.home}" -->
        <globmapper from="*/eclipse.exe" to="*" handledirsep="true" />
    </mapper>
</pathconvert>

<!-- find scala bundle -->
<pathconvert property="scala_bundle">
    <path>
        <fileset dir="${eclipse.home}/plugins">
            <include name="scala.library_*" />
        </fileset>
    </path>
</pathconvert>

<!-- find scala tools -->
<pathconvert property="scala_tools_jar">
    <path>
        <fileset dir="${eclipse.home}/plugins">
            <include name="scala.tools.nsc_*" />
        </fileset>
    </path>
</pathconvert>

This places the path to the Scala OSGi bundle in the vari­able ${scala_bundle}. The vari­able ${scala_tools_jar} will point to the jar file that con­tains the Scala Tools and, thus, the Ant tasks.

The lib­rary bundle has to be ex­trac­ted first, so the ac­tual Scala lib­rary scala-library.jar can be used in the classpath dur­ing the build. There­fore, you can use the tem­por­ary build dir­ect­ory ${build.result.folder}:

<unjar dest="${build.result.folder}/scala-library" src="${scala_bundle}" />
<property name="scala_library_jar"
    location="${build.result.folder}/scala-library/lib/scala-library.jar" />

After this, the Ant tar­gets can be defined:

<!-- define scalac task -->
<taskdef resource="scala/tools/ant/antlib.xml">
    <classpath>
        <pathelement location="${scala_tools_jar}" />
        <pathelement location="${scala_library_jar}" />
    </classpath>
</taskdef>

Be­fore the source files can be com­piled, a valid classpath has to be cre­ated. It con­sists of the classpath defined by PDE Build @dot.classpath and the Scala lib­rary:

<pathconvert property="my.classpath">
    <restrict>
        <path>
            <path refid="@dot.classpath" />
            <pathelement location="${scala_library_jar}" />
        </path>
        <!-- remove libraries from classpath that don't exist (optional) -->
        <rsel:exists />
    </restrict>
</pathconvert>

Re­mov­ing non-ex­ist­ing lib­rar­ies us­ing <rsel:exists /> is op­tional. To make it work, you have to add the fol­low­ing namespace to the Ant script’s root node:

<project name="Build specific targets and properties"
    xmlns:rsel="antlib:org.apache.tools.ant.types.resources.selectors">
    ...

Fi­nally, the source code can be com­piled:

<!-- compile scala source files -->
<mkdir dir="${target.folder}" />
<scalac srcdir="${source.folder1}"
    destdir="${target.folder}"
    classpath="${my.classpath}">
    <include name="**/*.scala" />
</scalac>

For pro­duc­tion use, it is also a good idea to de­lete the source files from the tar­get folder, so they are not de­ployed to­gether with the bin­ar­ies:

<!-- delete scala source files in output folder -->
<delete>
    <fileset dir="${target.folder}" includes="**/*.scala" />
</delete>

Conclusion

The method presen­ted here uses the pos­sib­il­ity to hook cus­tom Ant tar­gets into the PDE build pro­cess. The scripts try to find the Scala lib­rary and tools de­livered with the IDE. If you don’t like that, you may also copy the files scala-library.jar and scala-compiler.jar (con­tains the Ant task) from the Scala dis­tri­bu­tion into some dir­ect­ory of your pro­ject and change the classpath re­spect­ively.

The com­plete source of the gen­eric customBuildCallbacks.xml file can be down­loaded with the fol­low­ing link:

cus­tom­Build­Call­backs-old.xml (3.8 KiB)

This art­icle relates to an old ver­sion of the Scala IDE for Ec­lipse. An up­dated Ant script can be found in a newer post!

This file can be copied without changes into every OSGi bundle that should be com­piled with PDE and that con­tains Scala code. You only have to change the build.properties file as de­scribed above.


Posted by Michel Krämer
on March, 30th 2010.