diff options
author | Gilles Dubochet <gilles.dubochet@epfl.ch> | 2005-12-23 18:17:24 +0000 |
---|---|---|
committer | Gilles Dubochet <gilles.dubochet@epfl.ch> | 2005-12-23 18:17:24 +0000 |
commit | eb94d965c95024670e48f96abcb75394caf4e083 (patch) | |
tree | 5b1e8f14f12f13226289470cf2e4be9f4f204f74 | |
parent | 35915d3420ae6a7ffa53be40f2c14b0ba97a1be7 (diff) | |
download | scala-eb94d965c95024670e48f96abcb75394caf4e083.tar.gz scala-eb94d965c95024670e48f96abcb75394caf4e083.tar.bz2 scala-eb94d965c95024670e48f96abcb75394caf4e083.zip |
1.
2. Modified the build script to use the new optional Ant tasks that have
been added to 'lib/', which is much cleaner.
-rw-r--r-- | build.xml | 267 | ||||
-rw-r--r-- | lib/ant-contrib.jar.desired.sha1 | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/ant/Scalac.scala | 454 |
3 files changed, 595 insertions, 127 deletions
@@ -10,11 +10,9 @@ <echo>Running Sabbus for Scala-core</echo> - <!-- - ############################################################################## - PROPERTIES - ############################################################################## - --> +<!-- =========================================================================== +PROPERTIES +============================================================================ --> <property environment="env"/> <condition property="memory.set"> @@ -24,9 +22,6 @@ Sabbus requires additional memory. Please set the 'ANT_OPTS' environment property to '-Xmx256M' or more. </fail> - <condition property="os.win"> - <os family="windows"/> - </condition> <!-- Prevents system classpath from being used --> <property name="build.sysclasspath" value="ignore"/> @@ -42,7 +37,7 @@ <property name="copyright" value="(c) 2002-06 LAMP/EPFL"/> <!-- NSC configuration properties --> <property name="nsc.logging" value="none"/> - <property name="nsc.debug-info" value="true"/> + <property name="nsc.debug-info" value="yes"/> <property name="nsc.excludes" value="build.excludes"/> <!-- Location of pre-compiled libraries properties --> <property name="starr.lib.jar" value="${lib.dir}/scala-library.jar"/> @@ -54,6 +49,7 @@ <property name="msil.jar" value="${lib.dir}/${msil.name}"/> <property name="scala.dll" value="${lib.dir}/scala.dll"/> <property name="ant.jar" value="${ant.home}/lib/ant.jar"/> + <property name="ant-contrib.jar" value="${lib.dir}/ant-contrib.jar"/> <!-- Location of build products properties --> <property name="build.dir" value="${basedir}/build"/> <property name="locker.dir" value="${build.dir}/locker"/> @@ -81,26 +77,11 @@ <property name="strap.lib.dir" value="${strap.dir}/${lib.dir.name}"/> <property name="strap.comp.dir" value="${strap.dir}/${comp.dir.name}"/> - <!-- - ############################################################################## - INITIALISATION - ############################################################################## - --> - - <target name="init.cygwin" if="os.win"> - <exec executable="cygpath" vmlauncher="false" errorproperty="err"> - <arg value="--windir"/> - </exec> - <condition property="os.cygwin"> - <equals arg1="${err}" arg2=""/> - </condition> - </target> +<!-- =========================================================================== +INITIALISATION +============================================================================ --> - <target name="init" depends="init.cygwin"> - <condition property="os.unix"><or> - <os family="unix"/><os family="mac"/> - <isset property="os.cygwin"/> - </or></condition> + <target name="init"> <!-- Testing if everything is in place --> <echo level="verbose">starr.lib.jar=${starr.lib.jar}</echo> <fail message="STARR library in 'lib/' is not available"> @@ -141,6 +122,35 @@ </not></condition> </fail> <echo level="verbose">ant.jar=${ant.jar}</echo> + <echo level="verbose">ant-contrib.jar=${ant-contrib.jar}</echo> + <fail message="Additional Ant tasks in 'lib/' is not available"> + <condition><not> + <available classname="net.sf.antcontrib.AntContribVersion" + classpath="${ant-contrib.jar}"/> + </not></condition> + </fail> + <!-- Creating class-pathes --> + <path id="common.classpath"> + <pathelement location="${fjbg.jar}"/> + <pathelement location="${msil.jar}"/> + </path> + <path id="starr.classpath"> + <pathelement location="${starr.lib.jar}"/> + <pathelement location="${starr.comp.jar}"/> + <path refid="common.classpath"/> + </path> + <!-- Creating boot-level tasks --> + <taskdef name="starr" + classname="scala.tools.nsc.ant.NSC" + classpathref="starr.classpath"/> + <taskdef name="pico" + classname="jaco.pizza.ant.Pico" + classpath="${jaco.jar}"/> + <taskdef resource="net/sf/antcontrib/antlib.xml"> + <classpath> + <pathelement location="${ant-contrib.jar}" /> + </classpath> + </taskdef> <!-- Finding out what is available --> <available property="excludes.avail" file="${nsc.excludes}"/> <condition property="locker.avail"> @@ -154,28 +164,47 @@ <available file="${locker.dir}/${exec.dir.name}/${scalac.exec.name}"/> </and> </condition> - <!-- Creating class-pathes --> - <path id="common.classpath"> - <pathelement location="${fjbg.jar}"/> - <pathelement location="${msil.jar}"/> - </path> - <path id="starr.classpath"> - <pathelement location="${starr.lib.jar}"/> - <pathelement location="${starr.comp.jar}"/> - <path refid="common.classpath"/> - </path> + <!-- Finding out what system architecture is being used --> + <condition property="os.win"> + <os family="windows"/> + </condition> + <if><isset property="os.win"/> + <then> + <exec executable="cygpath" + vmlauncher="no" + errorproperty="cygpath.err" + outputproperty="cygpath.out"> + <arg value="--windir"/> + </exec> + <condition property="os.cygwin"> + <equals arg1="${cygpath.err}" arg2=""/> + </condition> + </then> + </if> + <condition property="os.unix"> + <or> + <os family="unix"/> + <os family="mac"/> + <isset property="os.cygwin"/> + </or> + </condition> + <if><isset property="os.cygwin"/> + <then><echo>Sabbus detected a Cygwin environnement</echo></then> + <elseif><isset property="os.win"/> + <then><echo>Sabbus detected a Windows environnement</echo></then> + </elseif> + <elseif><isset property="os.unix"/> + <then><echo>Sabbus detected a UNIX environnement</echo></then> + </elseif> + <else> + <fail>System environment could not be determined</fail> + </else> + </if> <!-- Defining version number --> <tstamp prefix="start"/> <property name="version.number" value="${start.DSTAMP}-${start.TSTAMP}"/> <property name="dist.current.dir" value="${dist.dir}/${dist.name}-${version.number}"/> - <!-- Creating boot-level tasks --> - <taskdef name="starr" - classname="scala.tools.nsc.ant.NSC" - classpathref="starr.classpath"/> - <taskdef name="pico" - classname="jaco.pizza.ant.Pico" - classpath="${jaco.jar}"/> </target> <target name="init.locker" depends="init, build.locker"> @@ -185,7 +214,7 @@ <path refid="common.classpath"/> </path> <taskdef name="locker" - classname="scala.tools.nsc.ant.NSC" + classname="scala.tools.ant.Scalac" classpathref="locker.classpath"/> </target> @@ -196,17 +225,15 @@ <path refid="common.classpath"/> </path> <taskdef name="quick" - classname="scala.tools.nsc.ant.NSC" + classname="scala.tools.ant.Scalac" classpathref="quick.classpath"/> </target> + +<!-- =========================================================================== +BUILD SUPPORT MACROS +============================================================================ --> - <!-- - ############################################################################## - BUILD SUPPORT MACROS - ############################################################################## - --> - - <macrodef name="build.exec"> + <macrodef name="build.exec.unix"> <attribute name="lib.path"/> <attribute name="comp.path"/> <attribute name="fjbg.path"/> @@ -271,18 +298,17 @@ </sequential> </macrodef> - <!-- - ############################################################################## - BUILD LOCAL REFERENCE (LOCKER) LAYER - ############################################################################## - --> +<!-- =========================================================================== +BUILD LOCAL REFERENCE (LOCKER) LAYER +============================================================================ --> <target name="build.locker" depends="init" unless="locker.avail"> + <property name="built.locker" value="yes"/> <!-- Build library --> <mkdir dir="${locker.lib.dir}"/> <pico srcdir="${src.dir}/${lib.dir.name}" destdir="${locker.lib.dir}" - scalahack="true"> + scalahack="yes"> <classpath> <pathelement location="${locker.lib.dir}"/> </classpath> @@ -290,8 +316,7 @@ </pico> <starr srcdir="${src.dir}/${lib.dir.name}" destdir="${locker.lib.dir}" - usepredefs="false" - debuginfo="${nsc.debug-info}"> + usepredefs="no"> <classpath> <pathelement location="${locker.lib.dir}"/> </classpath> @@ -299,8 +324,7 @@ <include name="scala/runtime/ScalaRunTime.scala"/> </starr> <starr srcdir="${src.dir}/${lib.dir.name}" - destdir="${locker.lib.dir}" - debuginfo="${nsc.debug-info}"> + destdir="${locker.lib.dir}"> <classpath> <pathelement location="${locker.lib.dir}"/> </classpath> @@ -313,7 +337,7 @@ <mkdir dir="${locker.comp.dir}"/> <pico srcdir="${src.dir}/${comp.dir.name}" destdir="${locker.comp.dir}" - scalahack="true"> + scalahack="yes"> <classpath> <pathelement location="${locker.lib.dir}"/> <pathelement location="${locker.comp.dir}"/> @@ -321,8 +345,7 @@ <include name="**/*.java"/> </pico> <starr srcdir="${src.dir}/${comp.dir.name}" - destdir="${locker.comp.dir}" - debuginfo="${nsc.debug-info}"> + destdir="${locker.comp.dir}"> <classpath> <pathelement location="${locker.lib.dir}"/> <pathelement location="${locker.comp.dir}"/> @@ -333,7 +356,7 @@ <excludesfile name="${nsc.excludes}" if="excludes.avail"/> </starr> <!-- Build executable files --> - <build.exec lib.path="$$PREFIX/${lib.dir.name}" + <build.exec.unix lib.path="$$PREFIX/${lib.dir.name}" comp.path="$$PREFIX/${comp.dir.name}" fjbg.path="../../../lib/${fjbg.name}" msil.path="../../../lib/${msil.name}" @@ -344,19 +367,17 @@ msil.path="..\..\..\lib\${msil.name}" exec.dir="${locker.dir}\${exec.dir.name}"/> </target> - - <!-- - ############################################################################## - BUILD QUICK-TEST LAYER - ############################################################################## - --> + +<!-- =========================================================================== +BUILD QUICK-TEST LAYER +============================================================================ --> <target name="build" depends="init.locker"> <!-- Build library --> <mkdir dir="${quick.lib.dir}"/> <pico srcdir="${src.dir}/${lib.dir.name}" destdir="${quick.lib.dir}" - scalahack="true"> + scalahack="yes"> <classpath> <pathelement location="${quick.lib.dir}"/> </classpath> @@ -364,8 +385,7 @@ </pico> <locker srcdir="${src.dir}/${lib.dir.name}" destdir="${quick.lib.dir}" - usepredefs="false" - debuginfo="${nsc.debug-info}"> + usepredefs="no"> <classpath> <pathelement location="${quick.lib.dir}"/> </classpath> @@ -373,8 +393,7 @@ <include name="scala/runtime/ScalaRunTime.scala"/> </locker> <locker srcdir="${src.dir}/${lib.dir.name}" - destdir="${quick.lib.dir}" - debuginfo="${nsc.debug-info}"> + destdir="${quick.lib.dir}"> <classpath> <pathelement location="${quick.lib.dir}"/> </classpath> @@ -387,7 +406,7 @@ <mkdir dir="${quick.comp.dir}"/> <pico srcdir="${src.dir}/${comp.dir.name}" destdir="${quick.comp.dir}" - scalahack="true"> + scalahack="yes"> <classpath> <pathelement location="${quick.lib.dir}"/> <pathelement location="${quick.comp.dir}"/> @@ -395,8 +414,7 @@ <include name="**/*.java"/> </pico> <locker srcdir="${src.dir}/${comp.dir.name}" - destdir="${quick.comp.dir}" - debuginfo="${nsc.debug-info}"> + destdir="${quick.comp.dir}"> <classpath> <pathelement location="${quick.lib.dir}"/> <pathelement location="${quick.comp.dir}"/> @@ -407,7 +425,7 @@ <excludesfile name="${nsc.excludes}" if="excludes.avail"/> </locker> <!-- Build executable files --> - <build.exec lib.path="$$PREFIX/${lib.dir.name}" + <build.exec.unix lib.path="$$PREFIX/${lib.dir.name}" comp.path="$$PREFIX/${comp.dir.name}" fjbg.path="../../../lib/${fjbg.name}" msil.path="../../../lib/${msil.name}" @@ -419,11 +437,9 @@ exec.dir="${quick.dir}\${exec.dir.name}"/> </target> - <!-- - ############################################################################## - TEST - ############################################################################## - --> +<!-- =========================================================================== +TEST +============================================================================ --> <target name="test" depends="init.quick"> <!-- Build the bootstrap layer --> @@ -431,7 +447,7 @@ <mkdir dir="${strap.lib.dir}"/> <pico srcdir="${src.dir}/${lib.dir.name}" destdir="${strap.lib.dir}" - scalahack="true"> + scalahack="yes"> <classpath> <pathelement location="${strap.lib.dir}"/> </classpath> @@ -439,8 +455,7 @@ </pico> <quick srcdir="${src.dir}/${lib.dir.name}" destdir="${strap.lib.dir}" - usepredefs="false" - debuginfo="${nsc.debug-info}"> + usepredefs="no"> <classpath> <pathelement location="${strap.lib.dir}"/> </classpath> @@ -448,8 +463,7 @@ <include name="scala/runtime/ScalaRunTime.scala"/> </quick> <quick srcdir="${src.dir}/${lib.dir.name}" - destdir="${strap.lib.dir}" - debuginfo="${nsc.debug-info}"> + destdir="${strap.lib.dir}"> <classpath> <pathelement location="${strap.lib.dir}"/> </classpath> @@ -462,7 +476,7 @@ <mkdir dir="${strap.comp.dir}"/> <pico srcdir="${src.dir}/${comp.dir.name}" destdir="${strap.comp.dir}" - scalahack="true"> + scalahack="yes"> <classpath> <pathelement location="${strap.lib.dir}"/> <pathelement location="${strap.comp.dir}"/> @@ -470,8 +484,7 @@ <include name="**/*.java"/> </pico> <quick srcdir="${src.dir}/${comp.dir.name}" - destdir="${strap.comp.dir}" - debuginfo="${nsc.debug-info}"> + destdir="${strap.comp.dir}"> <classpath> <pathelement location="${strap.lib.dir}"/> <pathelement location="${strap.comp.dir}"/> @@ -482,7 +495,7 @@ <excludesfile name="${nsc.excludes}" if="excludes.avail"/> </quick> <!-- Build executable files --> - <build.exec lib.path="$$$PREFIX/${lib.dir.name}" + <build.exec.unix lib.path="$$$PREFIX/${lib.dir.name}" comp.path="$$PREFIX/${comp.dir.name}" fjbg.path="../../../lib/${fjbg.name}" msil.path="../../../lib/${msil.name}" @@ -499,7 +512,7 @@ <include name="${comp.dir.name}/**"/> </fileset> </checksum> - <delete quiet="true" failonerror="false"> + <delete quiet="yes" failonerror="no"> <fileset dir="${quick.dir}"><include name="**/*.MD5"/></fileset> </delete> <checksum totalproperty="strap.md5"> @@ -508,7 +521,7 @@ <include name="${comp.dir.name}/**"/> </fileset> </checksum> - <delete quiet="true" failonerror="false"> + <delete quiet="yes" failonerror="no"> <fileset dir="${strap.dir}"><include name="**/*.MD5"/></fileset> </delete> <fail message="Build is not stable"> @@ -519,45 +532,39 @@ <echo>Build is stable</echo> </target> - <!-- - ############################################################################## - DOCUMENT - ############################################################################## - --> +<!-- =========================================================================== +DOCUMENT +============================================================================ --> <target name="docs"> <echo>Docs is not available yet.</echo> </target> - <!-- - ############################################################################## - GENERATES A DISTRIBUTION - ############################################################################## - --> +<!-- =========================================================================== +GENERATES A DISTRIBUTION +============================================================================ --> - <target name="init.dist" if="os.unix"> - <mkdir dir="${dist.current.dir}"/> - <symlink link="${dist.latest.dir}" - resource="${dist.current.dir}" - overwrite="yes"/> - </target> - - <target name="dist" depends="test, init.dist"> + <target name="dist" depends="test"> <mkdir dir="${dist.current.dir}"/> <mkdir dir="${dist.current.dir}/lib"/> <jar destfile="${dist.current.dir}/lib/${comp.jar.name}" basedir="${strap.comp.dir}"> <manifest> + <attribute name="Signature-Version" value="${version.number}"/> <attribute name="Main-Class" value="scala.tools.nsc.Main"/> + <attribute name="Class-Path" value="${lib.jar.name}"/> </manifest> </jar> <jar destfile="${dist.current.dir}/lib/${lib.jar.name}" basedir="${strap.lib.dir}"> + <manifest> + <attribute name="Signature-Version" value="${version.number}"/> + </manifest> </jar> <copy file="${fjbg.jar}" todir="${dist.current.dir}/lib"/> <copy file="${msil.jar}" todir="${dist.current.dir}/lib"/> <mkdir dir="${dist.current.dir}/bin"/> - <build.exec lib.path="$$PREFIX/lib/${lib.jar.name}" + <build.exec.unix lib.path="$$PREFIX/lib/${lib.jar.name}" comp.path="$$PREFIX/lib/${comp.jar.name}" fjbg.path="$$PREFIX/lib/${fjbg.name}" msil.path="$$PREFIX/lib/${msil.name}" @@ -567,21 +574,27 @@ fjbg.path="%SCALA_HOME%\lib\${fjbg.name}" msil.path="%SCALA_HOME%\lib\${msil.name}" exec.dir="${dist.current.dir}\bin"/> + <if><isset property="os.unix"/> + <then> + <symlink link="${dist.latest.dir}" + resource="${dist.current.dir}" + overwrite="yes" + failonerror="no"/> + </then> + </if> </target> - - <!-- - ############################################################################## - CLEAN - ############################################################################## - --> + +<!-- =========================================================================== +CLEAN +============================================================================ --> <macrodef name="remove"> <attribute name="dir"/> <sequential> <delete dir="@{dir}" - includeemptydirs="true" - quiet="true" - failonerror="false"/> + includeemptydirs="yes" + quiet="yes" + failonerror="no"/> </sequential> </macrodef> diff --git a/lib/ant-contrib.jar.desired.sha1 b/lib/ant-contrib.jar.desired.sha1 new file mode 100644 index 0000000000..05723e152e --- /dev/null +++ b/lib/ant-contrib.jar.desired.sha1 @@ -0,0 +1 @@ +6f02b1db445a31020e3fe0a137bc819595dbc387 ?ant-contrib.jar diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala new file mode 100644 index 0000000000..6967e7d794 --- /dev/null +++ b/src/compiler/scala/tools/ant/Scalac.scala @@ -0,0 +1,454 @@ +/* __ ______________ *\ +** / |/ / ____/ ____/ ** +** / | | /___ / /___ ** +** /_/|__/_____/_____/ Copyright 2005-2006 LAMP/EPFL ** +** +** $Id$ +\* */ + +package scala.tools.ant { + + import java.io.File + import java.net.{URL, URLClassLoader} + import java.util.{ArrayList, Vector} + + import org.apache.tools.ant.{AntClassLoader, BuildException, + DirectoryScanner, Project} + import org.apache.tools.ant.taskdefs.MatchingTask + import org.apache.tools.ant.types.Path + import org.apache.tools.ant.util.{FileUtils, GlobPatternMapper, + SourceFileScanner} + import org.apache.tools.ant.types.{EnumeratedAttribute, Reference} + + import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} + import scala.tools.nsc.{Global, FatalError, Settings} + + /** An Ant task to compile with the new Scala compiler (NSC). + * This task can take the following parameters as attributes:<ul> + * <li>srcdir (mandatory),</li> + * <li>srcref,</li> + * <li>destdir,</li> + * <li>classpath,</li> + * <li>classpathref,</li> + * <li>sourcepath,</li> + * <li>sourcepathref,</li> + * <li>bootclasspath,</li> + * <li>bootclasspathref,</li> + * <li>extdirs,</li> + * <li>extdirsref,</li> + * <li>encoding,</li> + * <li>force,</li> + * <li>logging,</li> + * <li>logphase,</li> + * <li>usepredefs,</li> + * <li>debugcode.</li> + * </ul> + * It also takes the following parameters as nested elements:<ul> + * <li>src (for srcdir),</li> + * <li>classpath,</li> + * <li>sourcepath,</li> + * <li>bootclasspath,</li> + * <li>extdirs.</li> + * </ul> + * + * @author Gilles Dubochet */ + class Scalac extends MatchingTask { + + private val SCALA_PRODUCT: String = + System.getProperty("scala.product", "scalac") + private val SCALA_VERSION: String = + System.getProperty("scala.version", "Unknown version") + + /** The unique Ant file utilities instance to use in this task. */ + private val fileUtils = FileUtils.newFileUtils() + +/******************************************************************************\ +** Ant user-properties ** +\******************************************************************************/ + + abstract class PermissibleValue { + val values: List[String] + def isPermissible(value: String): Boolean = + (value == "") || values.exists(.startsWith(value)) + } + + /** Defines valid values for the logging property. */ + object LoggingLevel extends PermissibleValue { + val values = List("none", "verbose", "debug") + } + + /** Defines valid values for properties that refer to compiler phases. */ + object CompilerPhase extends PermissibleValue { + val values = List("namer", "typer", "pickler", "uncurry", "tailcalls", + "transmatch", "explicitouter", "erasure", "lambdalift", + "flatten", "constructors", "mixin", "icode", "jvm", + "terminal") + } + + /** The directories that contain source files to compile. */ + private var origin: Option[Path] = None + /** The directory to put the compiled files in. */ + private var destination: Option[File] = None + + /** The class path to use for this compilation. */ + private var classpath: Option[Path] = None + /** The source path to use for this compilation. */ + private var sourcepath: Option[Path] = None + /** The boot class path to use for this compilation. */ + private var bootclasspath: Option[Path] = None + /** The external extensions path to use for this compilation. */ + private var extdirs: Option[Path] = None + + /** The character encoding of the files to compile. */ + private var encoding: Option[String] = None + + /** Whether to force compilation of all files or not. */ + private var force: Boolean = false + /** How much logging output to print. Either none (default), + * verbose or debug. */ + private var logging: Option[String] = None + /** Which compilation phases should be logged during compilation. */ + private var logPhase: List[String] = Nil + + /** Whether to use implicit predefined values or not. */ + private var usepredefs: Boolean = true; + /** Instruct the compiler to generate debugging information */ + private var debugCode: Boolean = false + +/******************************************************************************\ +** Properties setters ** +\******************************************************************************/ + + /** Sets the srcdir attribute. Used by Ant. + * @param input The value of <code>origin</code>. */ + def setSrcdir(input: Path) = + if (origin.isEmpty) origin = Some(input) + else origin.get.append(input) + + /** Sets the <code>origin</code> as a nested src Ant parameter. + * @return An origin path to be configured. */ + def createSrc(): Path = { + if (origin.isEmpty) origin = Some(new Path(getProject())) + origin.get.createPath() + } + + /** Sets the <code>origin</code> as an external reference Ant parameter. + * @param input A reference to an origin path. */ + def setSrcref(input: Reference) = + createSrc().setRefid(input) + + /** Sets the destdir attribute. Used by Ant. + * @param input The value of <code>destination</code>. */ + def setDestdir(input: File) = + destination = Some(input) + + /** Sets the classpath attribute. Used by Ant. + * @param input The value of <code>classpath</code>. */ + def setClasspath(input: Path) = + if (classpath.isEmpty) classpath = Some(input) + else classpath.get.append(input) + + /** Sets the <code>classpath</code> as a nested classpath Ant parameter. + * @return A class path to be configured. */ + def createClasspath(): Path = { + if (classpath.isEmpty) classpath = Some(new Path(getProject())) + classpath.get.createPath() + } + + /** Sets the <code>classpath</code> as an external reference Ant parameter. + * @param input A reference to a class path. */ + def setClasspathref(input: Reference) = + createClasspath().setRefid(input) + + /** Sets the sourcepath attribute. Used by Ant. + * @param input The value of <code>sourcepath</code>. */ + def setSourcepath(input: Path) = + if (sourcepath.isEmpty) sourcepath = Some(input) + else sourcepath.get.append(input) + + /** Sets the <code>sourcepath</code> as a nested sourcepath Ant parameter. + * @return A source path to be configured. */ + def createSourcepath(): Path = { + if (sourcepath.isEmpty) sourcepath = Some(new Path(getProject())) + sourcepath.get.createPath() + } + + /** Sets the <code>sourcepath</code> as an external reference Ant parameter. + * @param input A reference to a source path. */ + def setSourcepathref(input: Reference) = + createSourcepath().setRefid(input) + + /** Sets the boot classpath attribute. Used by Ant. + * @param input The value of <code>bootclasspath</code>. */ + def setBootclasspath(input: Path) = + if (bootclasspath.isEmpty) bootclasspath = Some(input) + else bootclasspath.get.append(input) + + /** Sets the <code>bootclasspath</code> as a nested sourcepath Ant + * parameter. + * @return A source path to be configured. */ + def createBootclasspath(): Path = { + if (bootclasspath.isEmpty) bootclasspath = Some(new Path(getProject())) + bootclasspath.get.createPath() + } + + /** Sets the <code>bootclasspath</code> as an external reference Ant + * parameter. + * @param input A reference to a source path. */ + def setBootclasspathref(input: Reference) = + createBootclasspath().setRefid(input) + + /** Sets the external extensions path attribute. Used by Ant. + * @param input The value of <code>extdirs</code>. */ + def setExtdirs(input: Path) = + if (extdirs.isEmpty) extdirs = Some(input) + else extdirs.get.append(input) + + /** Sets the <code>extdirs</code> as a nested sourcepath Ant parameter. + * @return An extensions path to be configured. */ + def createExtdirs(): Path = { + if (extdirs.isEmpty) extdirs = Some(new Path(getProject())) + extdirs.get.createPath() + } + + /** Sets the <code>extdirs</code> as an external reference Ant parameter. + * @param input A reference to an extensions path. */ + def setExtdirsref(input: Reference) = + createExtdirs().setRefid(input) + + /** Sets the encoding attribute. Used by Ant. + * @param input The value of <code>encoding</code>. */ + def setEncoding(input: String): Unit = + encoding = Some(input) + + /** Sets the force attribute. Used by Ant. + * @param input The value for <code>force</code>. */ + def setForce(input: Boolean): Unit = + force = input + + /** Sets the logging level attribute. Used by Ant. + * @param input The value for <code>logging</code>. */ + def setLogging(input: String) = + if (LoggingLevel.isPermissible(input)) logging = Some(input) + else error("Logging level '" + input + "' does not exist.") + + /** Sets the log attribute. Used by Ant. + * @param input The value for <code>logPhase</code>. */ + def setLogPhase(input: String) = { + logPhase = List.fromArray(input.split(",")).flatMap(s: String => { + val st = s.trim() + if (CompilerPhase.isPermissible(st)) + (if (input != "") List(st) else Nil) + else { + error("Phase " + st + " in log does not exist.") + Nil + } + }) + } + + /** Sets the use predefs attribute. Used by Ant. + * @param input The value for <code>usepredefs</code>. */ + def setUsepredefs(input: Boolean): Unit = + usepredefs = input; + + /** Set the debug info attribute. */ + def setDebugCode(input: Boolean): Unit = + debugCode = input + +/******************************************************************************\ +** Properties getters ** +\******************************************************************************/ + + /** Gets the value of the classpath attribute in a Scala-friendly form. + * @returns The class path as a list of files. */ + private def getClasspath: List[File] = + if (classpath.isEmpty) error("Member 'classpath' is empty.") + else + List.fromArray(classpath.get.list()).map(nameToFile) + + /** Gets the value of the origin attribute in a Scala-friendly form. + * @returns The origin path as a list of files. */ + private def getOrigin: List[File] = + if (origin.isEmpty) error("Member 'origin' is empty.") + else List.fromArray(origin.get.list()).map(nameToFile) + + /** Gets the value of the destination attribute in a Scala-friendly form. + * @returns The destination as a file. */ + private def getDestination: File = + if (destination.isEmpty) error("Member 'destination' is empty.") + else existing(getProject().resolveFile(destination.get.toString())) + + /** Gets the value of the sourcepath attribute in a Scala-friendly form. + * @returns The source path as a list of files. */ + private def getSourcepath: List[File] = + if (sourcepath.isEmpty) error("Member 'sourcepath' is empty.") + else + List.fromArray(sourcepath.get.list()).map(nameToFile) + + /** Gets the value of the bootclasspath attribute in a Scala-friendly form. + * @returns The boot class path as a list of files. */ + private def getBootclasspath: List[File] = + if (bootclasspath.isEmpty) error("Member 'bootclasspath' is empty.") + else + List.fromArray(bootclasspath.get.list()).map(nameToFile) + + /** Gets the value of the extdirs attribute in a Scala-friendly form. + * @returns The extensions path as a list of files. */ + private def getExtdirs: List[File] = + if (extdirs.isEmpty) error("Member 'extdirs' is empty.") + else List.fromArray(extdirs.get.list()).map(nameToFile) + +/******************************************************************************\ +** Compilation and support methods ** +\******************************************************************************/ + + /** This is forwarding method to circumvent bug #281 in Scala 2. Remove when + * bug has been corrected. */ + override protected def getDirectoryScanner(baseDir: java.io.File) = + super.getDirectoryScanner(baseDir) + + /** Transforms a string name into a file relative to the provided base + * directory. + * @param base A file pointing to the location relative to which the name + * will be resolved. + * @param name A relative or absolute path to the file as a string. + * @return A file created from the name and the base file. */ + private def nameToFile(base: File)(name: String): File = + existing(fileUtils.resolveFile(base, name)) + + /** Transforms a string name into a file relative to the build root + * directory. + * @param name A relative or absolute path to the file as a string. + * @return A file created from the name. */ + private def nameToFile(name: String): File = + existing(getProject().resolveFile(name)) + + /** Tests if a file exists and prints a warning in case it doesn't. Always + * returns the file, even if it doesn't exist. + * @param file A file to test for existance. + * @return The same file. */ + private def existing(file: File): File = { + if (!file.exists()) + log("Element '" + file.toString() + "' does not exist.", + Project.MSG_WARN) + file + } + + /** Transforms a path into a Scalac-readable string. + * @param path A path to convert. + * @return A string-representation of the path like 'a.jar:b.jar'. */ + private def asString(path: List[File]): String = + path.map(asString).mkString("", File.pathSeparator, "") + + /** Transforms a file into a Scalac-readable string. + * @param path A file to convert. + * @return A string-representation of the file like '/x/k/a.scala'. */ + private def asString(file: File): String = + file.getAbsolutePath() + + /** Generates a build error. Error location will be the current task in the + * ant file. + * @param message A message describing the error. + * @throws BuildException A build error exception thrown in every case. */ + private def error(message: String): All = + throw new BuildException(message, getLocation()) + +/******************************************************************************\ +** The big execute method ** +\******************************************************************************/ + + /** Performs the compilation. */ + override def execute() = { + + // Tests if all mandatory attributes are set and valid. + if (origin.isEmpty) error("Attribute 'srcdir' is not set.") + if (getOrigin.isEmpty) error("Attribute 'srcdir' is not set.") + if (!destination.isEmpty && !destination.get.isDirectory()) + error("Attribute 'destdir' does not refer to an existing directory.") + if (destination.isEmpty) destination = Some(getOrigin.head) + + val mapper = new GlobPatternMapper() + mapper.setTo("*.class") + mapper.setFrom("*.scala") + + // Scans source directories to build up a compile lists. + // If force is false, only files were the .class file in destination is + // older than the .scala file will be used. + val sourceFiles: List[File] = + for (val originDir <- getOrigin; + val originFile <- { + var includedFiles = + getDirectoryScanner(originDir).getIncludedFiles() + if (!force) { + includedFiles = new SourceFileScanner(this). + restrict(includedFiles, originDir, destination.get, mapper) + } + (List.fromArray(includedFiles)). + map(nameToFile(originDir)) + }) + yield { + log(originFile.toString(), Project.MSG_DEBUG) + originFile + } + + if (sourceFiles.length == 0) log("No files selected for compilation") + else log("Compiling " + sourceFiles.length + " source file" + + (if (sourceFiles.length > 1) "s" else "") + + (" to " + getDestination.toString())) + + // Builds-up the compilation settings for Scalac with the existing Ant + // parameters. + val reporter = new ConsoleReporter() + val settings = new Settings(error) + settings.outdir.value = asString(destination.get) + if (!classpath.isEmpty) + settings.classpath.value = asString(getClasspath) + if (!sourcepath.isEmpty) + settings.sourcepath.value = asString(getSourcepath) + else if (origin.get.size() > 0) + settings.sourcepath.value = origin.get.list()(0) + if (!bootclasspath.isEmpty) + settings.bootclasspath.value = asString(getBootclasspath) + if (!extdirs.isEmpty) settings.extdirs.value = asString(getExtdirs) + if (!encoding.isEmpty) settings.encoding.value = encoding.get + if (!logging.isEmpty && logging.get == "verbose") + settings.verbose.value = true + else if (!logging.isEmpty && logging.get == "debug") { + settings.verbose.value = true + settings.debug.value = true + } + if (!logPhase.isEmpty) settings.log.value = logPhase + settings.nopredefs.value = !usepredefs; + settings.debuginfo.value = debugCode + + // Compiles the actual code + val compiler = new Global(settings, reporter) + try { + (new compiler.Run).compile(sourceFiles.map(f:File=>f.toString())) + if (reporter.errors > 0) + error("Compile failed with " + + reporter.errors + " error" + + (if (reporter.errors > 1) "s" else "") + + "; see the compiler error output for details." + ) + } + catch { + case exception @ FatalError(msg) => { + exception.printStackTrace() + if (settings.debug.value) exception.printStackTrace() + error("Compile failed because of an internal compiler error (" + msg + + "); see the error output for details.") + } + } + if (reporter.warnings > 0) + log("Compile suceeded with " + + reporter.errors + " warning" + + (if (reporter.warnings > 1) "s" else "") + + "; see the compiler output for details." + ) + reporter.printSummary() + } + + } + +} |