/* * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Ant", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ package org.apache.tools.ant.taskdefs; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.util.GlobPatternMapper; import org.apache.tools.ant.util.JavaEnvUtils; import org.apache.tools.ant.util.SourceFileScanner; import org.apache.tools.ant.taskdefs.compilers.CompilerAdapter; import org.apache.tools.ant.taskdefs.compilers.CompilerAdapterFactory; import java.io.File; import java.util.Enumeration; import java.util.Vector; /** * Task to compile Java source files. This task can take the following * arguments: * * Of these arguments, the sourcedir and destdir are required. *

* When this task executes, it will recursively scan the sourcedir and * destdir looking for Java source files to compile. This task makes its * compile decision based on timestamp. * * @author James Davidson duncan@x180.com * @author Robin Green greenrd@hotmail.com * @author Stefan Bodewig * @author J D Glanville * * @version $Revision$ * * @since Ant 1.1 * * @ant.task category="java" */ public class Javac extends MatchingTask { private final static String FAIL_MSG = "Compile failed; see the compiler error output for details."; private Path src; private File destDir; private Path compileClasspath; private Path compileSourcepath; private String encoding; private boolean debug = false; private boolean optimize = false; private boolean deprecation = false; private boolean depend = false; private boolean verbose = false; private String target; private Path bootclasspath; private Path extdirs; private boolean includeAntRuntime = true; private boolean includeJavaRuntime = false; private boolean fork = false; private String forkedExecutable = null; private boolean nowarn = false; private String memoryInitialSize; private String memoryMaximumSize; private Vector implementationSpecificArgs = new Vector(); protected boolean failOnError = true; protected boolean listFiles = false; protected File[] compileList = new File[0]; private String source; private String debugLevel; /** * The compiler set via the compiler attribute. * *

default is null

* * @since Ant 1.5 */ private String compiler = null; /** * Get the value of debugLevel. * @return value of debugLevel. */ public String getDebugLevel() { return debugLevel; } /** * Set the value of debugLevel. * @param v Value to assign to debugLevel. */ public void setDebugLevel(String v) { this.debugLevel = v; } /** * Get the value of source. * @return value of source. */ public String getSource() { return source; } /** * Set the value of source. * @param v Value to assign to source. */ public void setSource(String v) { this.source = v; } /** * Create a nested src element for multiple source path * support. * * @return a nested src element. */ public Path createSrc() { if (src == null) { src = new Path(project); } return src.createPath(); } /** * Recreate src * * @return a nested src element. */ protected Path recreateSrc() { src = null; return createSrc(); } /** * Set the source dirs to find the source Java files. */ public void setSrcdir(Path srcDir) { if (src == null) { src = srcDir; } else { src.append(srcDir); } } /** Gets the source dirs to find the source java files. */ public Path getSrcdir() { return src; } /** * Set the destination directory into which the Java source * files should be compiled. */ public void setDestdir(File destDir) { this.destDir = destDir; } /** * Gets the destination directory into which the java source files * should be compiled. */ public File getDestdir() { return destDir; } /** * Set the sourcepath to be used for this compilation. */ public void setSourcepath(Path sourcepath) { if (compileSourcepath == null) { compileSourcepath = sourcepath; } else { compileSourcepath.append(sourcepath); } } /** Gets the sourcepath to be used for this compilation. */ public Path getSourcepath() { return compileSourcepath; } /** * Maybe creates a nested sourcepath element. */ public Path createSourcepath() { if (compileSourcepath == null) { compileSourcepath = new Path(project); } return compileSourcepath.createPath(); } /** * Adds a reference to a CLASSPATH defined elsewhere. */ public void setSourcepathRef(Reference r) { createSourcepath().setRefid(r); } /** * Set the classpath to be used for this compilation. */ public void setClasspath(Path classpath) { if (compileClasspath == null) { compileClasspath = classpath; } else { compileClasspath.append(classpath); } } /** Gets the classpath to be used for this compilation. */ public Path getClasspath() { return compileClasspath; } /** * Maybe creates a nested classpath element. */ public Path createClasspath() { if (compileClasspath == null) { compileClasspath = new Path(project); } return compileClasspath.createPath(); } /** * Adds a reference to a CLASSPATH defined elsewhere. */ public void setClasspathRef(Reference r) { createClasspath().setRefid(r); } /** * Sets the bootclasspath that will be used to compile the classes * against. */ public void setBootclasspath(Path bootclasspath) { if (this.bootclasspath == null) { this.bootclasspath = bootclasspath; } else { this.bootclasspath.append(bootclasspath); } } /** * Gets the bootclasspath that will be used to compile the classes * against. */ public Path getBootclasspath() { return bootclasspath; } /** * Maybe creates a nested classpath element. */ public Path createBootclasspath() { if (bootclasspath == null) { bootclasspath = new Path(project); } return bootclasspath.createPath(); } /** * Adds a reference to a CLASSPATH defined elsewhere. */ public void setBootClasspathRef(Reference r) { createBootclasspath().setRefid(r); } /** * Sets the extension directories that will be used during the * compilation. */ public void setExtdirs(Path extdirs) { if (this.extdirs == null) { this.extdirs = extdirs; } else { this.extdirs.append(extdirs); } } /** * Gets the extension directories that will be used during the * compilation. */ public Path getExtdirs() { return extdirs; } /** * Maybe creates a nested classpath element. */ public Path createExtdirs() { if (extdirs == null) { extdirs = new Path(project); } return extdirs.createPath(); } /** * List the source files being handed off to the compiler */ public void setListfiles(boolean list) { listFiles = list; } /** Get the listfiles flag. */ public boolean getListfiles() { return listFiles; } /** * Throw a BuildException if compilation fails */ public void setFailonerror(boolean fail) { failOnError = fail; } /** * Proceed if compilation fails */ public void setProceed(boolean proceed) { failOnError = !proceed; } /** * Gets the failonerror flag. */ public boolean getFailonerror() { return failOnError; } /** * Set the deprecation flag. */ public void setDeprecation(boolean deprecation) { this.deprecation = deprecation; } /** Gets the deprecation flag. */ public boolean getDeprecation() { return deprecation; } /** * Set the memoryInitialSize flag. */ public void setMemoryInitialSize(String memoryInitialSize) { this.memoryInitialSize = memoryInitialSize; } /** Gets the memoryInitialSize flag. */ public String getMemoryInitialSize() { return memoryInitialSize; } /** * Set the memoryMaximumSize flag. */ public void setMemoryMaximumSize(String memoryMaximumSize) { this.memoryMaximumSize = memoryMaximumSize; } /** Gets the memoryMaximumSize flag. */ public String getMemoryMaximumSize() { return memoryMaximumSize; } /** * Set the Java source file encoding name. */ public void setEncoding(String encoding) { this.encoding = encoding; } /** Gets the java source file encoding name. */ public String getEncoding() { return encoding; } /** * Set the debug flag. */ public void setDebug(boolean debug) { this.debug = debug; } /** Gets the debug flag. */ public boolean getDebug() { return debug; } /** * Set the optimize flag. */ public void setOptimize(boolean optimize) { this.optimize = optimize; } /** Gets the optimize flag. */ public boolean getOptimize() { return optimize; } /** * Set the depend flag. */ public void setDepend(boolean depend) { this.depend = depend; } /** Gets the depend flag. */ public boolean getDepend() { return depend; } /** * Set the verbose flag. */ public void setVerbose(boolean verbose) { this.verbose = verbose; } /** Gets the verbose flag. */ public boolean getVerbose() { return verbose; } /** * Sets the target VM that the classes will be compiled for. Valid * strings are "1.1", "1.2", and "1.3". */ public void setTarget(String target) { this.target = target; } /** Gets the target VM that the classes will be compiled for. */ public String getTarget() { return target; } /** * Include ant's own classpath in this task's classpath? */ public void setIncludeantruntime(boolean include) { includeAntRuntime = include; } /** * Gets whether or not the ant classpath is to be included in the * task's classpath. */ public boolean getIncludeantruntime() { return includeAntRuntime; } /** * Sets whether or not to include the java runtime libraries to this * task's classpath. */ public void setIncludejavaruntime(boolean include) { includeJavaRuntime = include; } /** * Gets whether or not the java runtime should be included in this * task's classpath. */ public boolean getIncludejavaruntime() { return includeJavaRuntime; } /** * Sets whether to fork the javac compiler. * * @param f "true|false|on|off|yes|no" */ public void setFork(boolean f) { fork = f; } /** * Sets the the name of the javac executable. * *

Ignored unless fork is true or extJavac has been specified * as the compiler.

*/ public void setExecutable(String forkExec) { forkedExecutable = forkExec; } /** * Is this a forked invocation of JDK's javac? */ public boolean isForkedJavac() { return fork || "extJavac".equals(getCompiler()); } /** * The name of the javac executable to use in fork-mode. */ public String getJavacExecutable() { if (forkedExecutable == null && isForkedJavac()) { forkedExecutable = getSystemJavac(); } else if (forkedExecutable != null && !isForkedJavac()) { forkedExecutable = null; } return forkedExecutable; } /** * Sets whether the -nowarn option should be used. */ public void setNowarn(boolean flag) { this.nowarn = flag; } /** * Should the -nowarn option be used. */ public boolean getNowarn() { return nowarn; } /** * Adds an implementation specific command line argument. */ public ImplementationSpecificArgument createCompilerArg() { ImplementationSpecificArgument arg = new ImplementationSpecificArgument(); implementationSpecificArgs.addElement(arg); return arg; } /** * Get the additional implementation specific command line arguments. * @return array of command line arguments, guaranteed to be non-null. */ public String[] getCurrentCompilerArgs() { Vector args = new Vector(); for (Enumeration enum = implementationSpecificArgs.elements(); enum.hasMoreElements();) { ImplementationSpecificArgument arg = ((ImplementationSpecificArgument) enum.nextElement()); String[] curr = arg.getParts(); for (int i = 0; i < curr.length; i++) { args.addElement(curr[i]); } } String[] res = new String[args.size()]; args.copyInto(res); return res; } /** * Executes the task. */ public void execute() throws BuildException { checkParameters(); resetFileLists(); // scan source directories and dest directory to build up // compile lists String[] list = src.list(); for (int i = 0; i < list.length; i++) { File srcDir = project.resolveFile(list[i]); if (!srcDir.exists()) { throw new BuildException("srcdir \"" + srcDir.getPath() + "\" does not exist!", location); } DirectoryScanner ds = this.getDirectoryScanner(srcDir); String[] files = ds.getIncludedFiles(); scanDir(srcDir, destDir != null ? destDir : srcDir, files); } compile(); } /** * Clear the list of files to be compiled and copied.. */ protected void resetFileLists() { compileList = new File[0]; } /** * Scans the directory looking for source files to be compiled. * The results are returned in the class variable compileList */ protected void scanDir(File srcDir, File destDir, String[] files) { GlobPatternMapper m = new GlobPatternMapper(); m.setFrom("*.java"); m.setTo("*.class"); SourceFileScanner sfs = new SourceFileScanner(this); File[] newFiles = sfs.restrictAsFiles(files, srcDir, destDir, m); if (newFiles.length > 0) { File[] newCompileList = new File[compileList.length + newFiles.length]; System.arraycopy(compileList, 0, newCompileList, 0, compileList.length); System.arraycopy(newFiles, 0, newCompileList, compileList.length, newFiles.length); compileList = newCompileList; } } /** Gets the list of files to be compiled. */ public File[] getFileList() { return compileList; } protected boolean isJdkCompiler(String compilerImpl) { return "modern".equals(compilerImpl) || "classic".equals(compilerImpl) || "javac1.1".equals(compilerImpl) || "javac1.2".equals(compilerImpl) || "javac1.3".equals(compilerImpl) || "javac1.4".equals(compilerImpl); } protected String getSystemJavac() { return JavaEnvUtils.getJdkExecutable("javac"); } /** * Choose the implementation for this particular task. * * @since Ant 1.5 */ public void setCompiler(String compiler) { this.compiler = compiler; } /** * The implementation for this particular task. * *

Defaults to the build.compiler property but can be overriden * via the compiler and fork attributes.

* * @since Ant 1.5 */ public String getCompiler() { String compilerImpl = this.compiler != null ? this.compiler : project.getProperty("build.compiler"); if (fork) { if (compilerImpl != null) { if (isJdkCompiler(compilerImpl)) { log("Since fork is true, ignoring compiler setting.", Project.MSG_WARN); compilerImpl = "extJavac"; } else { log("Since compiler setting isn't classic or modern," + "ignoring fork setting.", Project.MSG_WARN); } } else { compilerImpl = "extJavac"; } } if (compilerImpl == null) { if (JavaEnvUtils.getJavaVersion() != JavaEnvUtils.JAVA_1_1 && JavaEnvUtils.getJavaVersion() != JavaEnvUtils.JAVA_1_2) { compilerImpl = "modern"; } else { compilerImpl = "classic"; } } return compilerImpl; } /** * Check that all required attributes have been set and nothing * silly has been entered. * * @since Ant 1.5 */ protected void checkParameters() throws BuildException { if (src == null) { throw new BuildException("srcdir attribute must be set!", location); } if (src.size() == 0) { throw new BuildException("srcdir attribute must be set!", location); } if (destDir != null && !destDir.isDirectory()) { throw new BuildException("destination directory \"" + destDir + "\" does not exist " + "or is not a directory", location); } } /** * Perform the compilation. * * @since Ant 1.5 */ protected void compile() { String compilerImpl = getCompiler(); if (compileList.length > 0) { log("Compiling " + compileList.length + " source file" + (compileList.length == 1 ? "" : "s") + (destDir != null ? " to " + destDir : "")); if (listFiles) { for (int i = 0 ; i < compileList.length ; i++) { String filename = compileList[i].getAbsolutePath(); log(filename) ; } } CompilerAdapter adapter = CompilerAdapterFactory.getCompiler(compilerImpl, this); // now we need to populate the compiler adapter adapter.setJavac(this); // finally, lets execute the compiler!! if (!adapter.execute()) { if (failOnError) { throw new BuildException(FAIL_MSG, location); } else { log(FAIL_MSG, Project.MSG_ERR); } } } } /** * Adds an "implementation" attribute to Commandline$Attribute * used to filter command line attributes based on the current * implementation. */ public class ImplementationSpecificArgument extends Commandline.Argument { private String impl; public void setCompiler(String impl) { this.impl = impl; } public String[] getParts() { if (impl == null || impl.equals(getCompiler())) { return super.getParts(); } else { return new String[0]; } } } }