Save This Page
Home » apache-ant-1.8.1 » org.apache.tools » ant » taskdefs » [javadoc | source]
    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    *
   17    */
   18   
   19   package org.apache.tools.ant.taskdefs;
   20   
   21   import java.io.File;
   22   import java.io.FileOutputStream;
   23   import java.io.IOException;
   24   import java.io.OutputStream;
   25   import java.util.HashMap;
   26   import java.util.Iterator;
   27   import java.util.Map;
   28   
   29   import org.apache.tools.ant.BuildException;
   30   import org.apache.tools.ant.DirectoryScanner;
   31   import org.apache.tools.ant.MagicNames;
   32   import org.apache.tools.ant.Project;
   33   import org.apache.tools.ant.taskdefs.compilers.CompilerAdapter;
   34   import org.apache.tools.ant.taskdefs.compilers.CompilerAdapterFactory;
   35   import org.apache.tools.ant.types.Path;
   36   import org.apache.tools.ant.types.Reference;
   37   import org.apache.tools.ant.util.FileUtils;
   38   import org.apache.tools.ant.util.GlobPatternMapper;
   39   import org.apache.tools.ant.util.JavaEnvUtils;
   40   import org.apache.tools.ant.util.SourceFileScanner;
   41   import org.apache.tools.ant.util.facade.FacadeTaskHelper;
   42   
   43   /**
   44    * Compiles Java source files. This task can take the following
   45    * arguments:
   46    * <ul>
   47    * <li>sourcedir
   48    * <li>destdir
   49    * <li>deprecation
   50    * <li>classpath
   51    * <li>bootclasspath
   52    * <li>extdirs
   53    * <li>optimize
   54    * <li>debug
   55    * <li>encoding
   56    * <li>target
   57    * <li>depend
   58    * <li>verbose
   59    * <li>failonerror
   60    * <li>includeantruntime
   61    * <li>includejavaruntime
   62    * <li>source
   63    * <li>compiler
   64    * </ul>
   65    * Of these arguments, the <b>sourcedir</b> and <b>destdir</b> are required.
   66    * <p>
   67    * When this task executes, it will recursively scan the sourcedir and
   68    * destdir looking for Java source files to compile. This task makes its
   69    * compile decision based on timestamp.
   70    *
   71    *
   72    * @since Ant 1.1
   73    *
   74    * @ant.task category="java"
   75    */
   76   
   77   public class Javac extends MatchingTask {
   78   
   79       private static final String FAIL_MSG
   80           = "Compile failed; see the compiler error output for details.";
   81   
   82       private static final String JAVAC16 = "javac1.6";
   83       private static final String JAVAC15 = "javac1.5";
   84       private static final String JAVAC14 = "javac1.4";
   85       private static final String JAVAC13 = "javac1.3";
   86       private static final String JAVAC12 = "javac1.2";
   87       private static final String JAVAC11 = "javac1.1";
   88       private static final String MODERN = "modern";
   89       private static final String CLASSIC = "classic";
   90       private static final String EXTJAVAC = "extJavac";
   91   
   92       private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
   93   
   94       private Path src;
   95       private File destDir;
   96       private Path compileClasspath;
   97       private Path compileSourcepath;
   98       private String encoding;
   99       private boolean debug = false;
  100       private boolean optimize = false;
  101       private boolean deprecation = false;
  102       private boolean depend = false;
  103       private boolean verbose = false;
  104       private String targetAttribute;
  105       private Path bootclasspath;
  106       private Path extdirs;
  107       private Boolean includeAntRuntime;
  108       private boolean includeJavaRuntime = false;
  109       private boolean fork = false;
  110       private String forkedExecutable = null;
  111       private boolean nowarn = false;
  112       private String memoryInitialSize;
  113       private String memoryMaximumSize;
  114       private FacadeTaskHelper facade = null;
  115   
  116       // CheckStyle:VisibilityModifier OFF - bc
  117       protected boolean failOnError = true;
  118       protected boolean listFiles = false;
  119       protected File[] compileList = new File[0];
  120       private Map/*<String,Long>*/ packageInfos = new HashMap();
  121       // CheckStyle:VisibilityModifier ON
  122   
  123       private String source;
  124       private String debugLevel;
  125       private File tmpDir;
  126       private String updatedProperty;
  127       private String errorProperty;
  128       private boolean taskSuccess = true; // assume the best
  129       private boolean includeDestClasses = true;
  130       private CompilerAdapter nestedAdapter = null;
  131   
  132       /**
  133        * Javac task for compilation of Java files.
  134        */
  135       public Javac() {
  136           facade = new FacadeTaskHelper(assumedJavaVersion());
  137       }
  138   
  139       private String assumedJavaVersion() {
  140           if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_4)) {
  141               return JAVAC14;
  142           } else if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_5)) {
  143               return JAVAC15;
  144           } else if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_6)) {
  145               return JAVAC16;
  146           } else {
  147               return CLASSIC;
  148           }
  149       }
  150   
  151       /**
  152        * Get the value of debugLevel.
  153        * @return value of debugLevel.
  154        */
  155       public String getDebugLevel() {
  156           return debugLevel;
  157       }
  158   
  159       /**
  160        * Keyword list to be appended to the -g command-line switch.
  161        *
  162        * This will be ignored by all implementations except modern
  163        * and classic(ver >= 1.2). Legal values are none or a
  164        * comma-separated list of the following keywords: lines, vars,
  165        * and source. If debuglevel is not specified, by default, :none
  166        * will be appended to -g. If debug is not turned on, this attribute
  167        * will be ignored.
  168        *
  169        * @param v  Value to assign to debugLevel.
  170        */
  171       public void setDebugLevel(String  v) {
  172           this.debugLevel = v;
  173       }
  174   
  175       /**
  176        * Get the value of source.
  177        * @return value of source.
  178        */
  179       public String getSource() {
  180           return source != null
  181               ? source : getProject().getProperty(MagicNames.BUILD_JAVAC_SOURCE);
  182       }
  183   
  184       /**
  185        * Value of the -source command-line switch; will be ignored by
  186        * all implementations except modern, jikes and gcj (gcj uses
  187        * -fsource).
  188        *
  189        * <p>If you use this attribute together with jikes or gcj, you
  190        * must make sure that your version of jikes supports the -source
  191        * switch.</p>
  192        *
  193        * <p>Legal values are 1.3, 1.4, 1.5, and 5 - by default, no
  194        * -source argument will be used at all.</p>
  195        *
  196        * @param v  Value to assign to source.
  197        */
  198       public void setSource(String  v) {
  199           this.source = v;
  200       }
  201   
  202       /**
  203        * Adds a path for source compilation.
  204        *
  205        * @return a nested src element.
  206        */
  207       public Path createSrc() {
  208           if (src == null) {
  209               src = new Path(getProject());
  210           }
  211           return src.createPath();
  212       }
  213   
  214       /**
  215        * Recreate src.
  216        *
  217        * @return a nested src element.
  218        */
  219       protected Path recreateSrc() {
  220           src = null;
  221           return createSrc();
  222       }
  223   
  224       /**
  225        * Set the source directories to find the source Java files.
  226        * @param srcDir the source directories as a path
  227        */
  228       public void setSrcdir(Path srcDir) {
  229           if (src == null) {
  230               src = srcDir;
  231           } else {
  232               src.append(srcDir);
  233           }
  234       }
  235   
  236       /**
  237        * Gets the source dirs to find the source java files.
  238        * @return the source directories as a path
  239        */
  240       public Path getSrcdir() {
  241           return src;
  242       }
  243   
  244       /**
  245        * Set the destination directory into which the Java source
  246        * files should be compiled.
  247        * @param destDir the destination director
  248        */
  249       public void setDestdir(File destDir) {
  250           this.destDir = destDir;
  251       }
  252   
  253       /**
  254        * Gets the destination directory into which the java source files
  255        * should be compiled.
  256        * @return the destination directory
  257        */
  258       public File getDestdir() {
  259           return destDir;
  260       }
  261   
  262       /**
  263        * Set the sourcepath to be used for this compilation.
  264        * @param sourcepath the source path
  265        */
  266       public void setSourcepath(Path sourcepath) {
  267           if (compileSourcepath == null) {
  268               compileSourcepath = sourcepath;
  269           } else {
  270               compileSourcepath.append(sourcepath);
  271           }
  272       }
  273   
  274       /**
  275        * Gets the sourcepath to be used for this compilation.
  276        * @return the source path
  277        */
  278       public Path getSourcepath() {
  279           return compileSourcepath;
  280       }
  281   
  282       /**
  283        * Adds a path to sourcepath.
  284        * @return a sourcepath to be configured
  285        */
  286       public Path createSourcepath() {
  287           if (compileSourcepath == null) {
  288               compileSourcepath = new Path(getProject());
  289           }
  290           return compileSourcepath.createPath();
  291       }
  292   
  293       /**
  294        * Adds a reference to a source path defined elsewhere.
  295        * @param r a reference to a source path
  296        */
  297       public void setSourcepathRef(Reference r) {
  298           createSourcepath().setRefid(r);
  299       }
  300   
  301       /**
  302        * Set the classpath to be used for this compilation.
  303        *
  304        * @param classpath an Ant Path object containing the compilation classpath.
  305        */
  306       public void setClasspath(Path classpath) {
  307           if (compileClasspath == null) {
  308               compileClasspath = classpath;
  309           } else {
  310               compileClasspath.append(classpath);
  311           }
  312       }
  313   
  314       /**
  315        * Gets the classpath to be used for this compilation.
  316        * @return the class path
  317        */
  318       public Path getClasspath() {
  319           return compileClasspath;
  320       }
  321   
  322       /**
  323        * Adds a path to the classpath.
  324        * @return a class path to be configured
  325        */
  326       public Path createClasspath() {
  327           if (compileClasspath == null) {
  328               compileClasspath = new Path(getProject());
  329           }
  330           return compileClasspath.createPath();
  331       }
  332   
  333       /**
  334        * Adds a reference to a classpath defined elsewhere.
  335        * @param r a reference to a classpath
  336        */
  337       public void setClasspathRef(Reference r) {
  338           createClasspath().setRefid(r);
  339       }
  340   
  341       /**
  342        * Sets the bootclasspath that will be used to compile the classes
  343        * against.
  344        * @param bootclasspath a path to use as a boot class path (may be more
  345        *                      than one)
  346        */
  347       public void setBootclasspath(Path bootclasspath) {
  348           if (this.bootclasspath == null) {
  349               this.bootclasspath = bootclasspath;
  350           } else {
  351               this.bootclasspath.append(bootclasspath);
  352           }
  353       }
  354   
  355       /**
  356        * Gets the bootclasspath that will be used to compile the classes
  357        * against.
  358        * @return the boot path
  359        */
  360       public Path getBootclasspath() {
  361           return bootclasspath;
  362       }
  363   
  364       /**
  365        * Adds a path to the bootclasspath.
  366        * @return a path to be configured
  367        */
  368       public Path createBootclasspath() {
  369           if (bootclasspath == null) {
  370               bootclasspath = new Path(getProject());
  371           }
  372           return bootclasspath.createPath();
  373       }
  374   
  375       /**
  376        * Adds a reference to a classpath defined elsewhere.
  377        * @param r a reference to a classpath
  378        */
  379       public void setBootClasspathRef(Reference r) {
  380           createBootclasspath().setRefid(r);
  381       }
  382   
  383       /**
  384        * Sets the extension directories that will be used during the
  385        * compilation.
  386        * @param extdirs a path
  387        */
  388       public void setExtdirs(Path extdirs) {
  389           if (this.extdirs == null) {
  390               this.extdirs = extdirs;
  391           } else {
  392               this.extdirs.append(extdirs);
  393           }
  394       }
  395   
  396       /**
  397        * Gets the extension directories that will be used during the
  398        * compilation.
  399        * @return the extension directories as a path
  400        */
  401       public Path getExtdirs() {
  402           return extdirs;
  403       }
  404   
  405       /**
  406        * Adds a path to extdirs.
  407        * @return a path to be configured
  408        */
  409       public Path createExtdirs() {
  410           if (extdirs == null) {
  411               extdirs = new Path(getProject());
  412           }
  413           return extdirs.createPath();
  414       }
  415   
  416       /**
  417        * If true, list the source files being handed off to the compiler.
  418        * @param list if true list the source files
  419        */
  420       public void setListfiles(boolean list) {
  421           listFiles = list;
  422       }
  423   
  424       /**
  425        * Get the listfiles flag.
  426        * @return the listfiles flag
  427        */
  428       public boolean getListfiles() {
  429           return listFiles;
  430       }
  431   
  432       /**
  433        * Indicates whether the build will continue
  434        * even if there are compilation errors; defaults to true.
  435        * @param fail if true halt the build on failure
  436        */
  437       public void setFailonerror(boolean fail) {
  438           failOnError = fail;
  439       }
  440   
  441       /**
  442        * @ant.attribute ignore="true"
  443        * @param proceed inverse of failoferror
  444        */
  445       public void setProceed(boolean proceed) {
  446           failOnError = !proceed;
  447       }
  448   
  449       /**
  450        * Gets the failonerror flag.
  451        * @return the failonerror flag
  452        */
  453       public boolean getFailonerror() {
  454           return failOnError;
  455       }
  456   
  457       /**
  458        * Indicates whether source should be
  459        * compiled with deprecation information; defaults to off.
  460        * @param deprecation if true turn on deprecation information
  461        */
  462       public void setDeprecation(boolean deprecation) {
  463           this.deprecation = deprecation;
  464       }
  465   
  466       /**
  467        * Gets the deprecation flag.
  468        * @return the deprecation flag
  469        */
  470       public boolean getDeprecation() {
  471           return deprecation;
  472       }
  473   
  474       /**
  475        * The initial size of the memory for the underlying VM
  476        * if javac is run externally; ignored otherwise.
  477        * Defaults to the standard VM memory setting.
  478        * (Examples: 83886080, 81920k, or 80m)
  479        * @param memoryInitialSize string to pass to VM
  480        */
  481       public void setMemoryInitialSize(String memoryInitialSize) {
  482           this.memoryInitialSize = memoryInitialSize;
  483       }
  484   
  485       /**
  486        * Gets the memoryInitialSize flag.
  487        * @return the memoryInitialSize flag
  488        */
  489       public String getMemoryInitialSize() {
  490           return memoryInitialSize;
  491       }
  492   
  493       /**
  494        * The maximum size of the memory for the underlying VM
  495        * if javac is run externally; ignored otherwise.
  496        * Defaults to the standard VM memory setting.
  497        * (Examples: 83886080, 81920k, or 80m)
  498        * @param memoryMaximumSize string to pass to VM
  499        */
  500       public void setMemoryMaximumSize(String memoryMaximumSize) {
  501           this.memoryMaximumSize = memoryMaximumSize;
  502       }
  503   
  504       /**
  505        * Gets the memoryMaximumSize flag.
  506        * @return the memoryMaximumSize flag
  507        */
  508       public String getMemoryMaximumSize() {
  509           return memoryMaximumSize;
  510       }
  511   
  512       /**
  513        * Set the Java source file encoding name.
  514        * @param encoding the source file encoding
  515        */
  516       public void setEncoding(String encoding) {
  517           this.encoding = encoding;
  518       }
  519   
  520       /**
  521        * Gets the java source file encoding name.
  522        * @return the source file encoding name
  523        */
  524       public String getEncoding() {
  525           return encoding;
  526       }
  527   
  528       /**
  529        * Indicates whether source should be compiled
  530        * with debug information; defaults to off.
  531        * @param debug if true compile with debug information
  532        */
  533       public void setDebug(boolean debug) {
  534           this.debug = debug;
  535       }
  536   
  537       /**
  538        * Gets the debug flag.
  539        * @return the debug flag
  540        */
  541       public boolean getDebug() {
  542           return debug;
  543       }
  544   
  545       /**
  546        * If true, compiles with optimization enabled.
  547        * @param optimize if true compile with optimization enabled
  548        */
  549       public void setOptimize(boolean optimize) {
  550           this.optimize = optimize;
  551       }
  552   
  553       /**
  554        * Gets the optimize flag.
  555        * @return the optimize flag
  556        */
  557       public boolean getOptimize() {
  558           return optimize;
  559       }
  560   
  561       /**
  562        * Enables dependency-tracking for compilers
  563        * that support this (jikes and classic).
  564        * @param depend if true enable dependency-tracking
  565        */
  566       public void setDepend(boolean depend) {
  567           this.depend = depend;
  568       }
  569   
  570       /**
  571        * Gets the depend flag.
  572        * @return the depend flag
  573        */
  574       public boolean getDepend() {
  575           return depend;
  576       }
  577   
  578       /**
  579        * If true, asks the compiler for verbose output.
  580        * @param verbose if true, asks the compiler for verbose output
  581        */
  582       public void setVerbose(boolean verbose) {
  583           this.verbose = verbose;
  584       }
  585   
  586       /**
  587        * Gets the verbose flag.
  588        * @return the verbose flag
  589        */
  590       public boolean getVerbose() {
  591           return verbose;
  592       }
  593   
  594       /**
  595        * Sets the target VM that the classes will be compiled for. Valid
  596        * values depend on the compiler, for jdk 1.4 the valid values are
  597        * "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "5" and "6".
  598        * @param target the target VM
  599        */
  600       public void setTarget(String target) {
  601           this.targetAttribute = target;
  602       }
  603   
  604       /**
  605        * Gets the target VM that the classes will be compiled for.
  606        * @return the target VM
  607        */
  608       public String getTarget() {
  609           return targetAttribute != null
  610               ? targetAttribute
  611               : getProject().getProperty(MagicNames.BUILD_JAVAC_TARGET);
  612       }
  613   
  614       /**
  615        * If true, includes Ant's own classpath in the classpath.
  616        * @param include if true, includes Ant's own classpath in the classpath
  617        */
  618       public void setIncludeantruntime(boolean include) {
  619           includeAntRuntime = Boolean.valueOf(include);
  620       }
  621   
  622       /**
  623        * Gets whether or not the ant classpath is to be included in the classpath.
  624        * @return whether or not the ant classpath is to be included in the classpath
  625        */
  626       public boolean getIncludeantruntime() {
  627           return includeAntRuntime != null ? includeAntRuntime.booleanValue() : true;
  628       }
  629   
  630       /**
  631        * If true, includes the Java runtime libraries in the classpath.
  632        * @param include if true, includes the Java runtime libraries in the classpath
  633        */
  634       public void setIncludejavaruntime(boolean include) {
  635           includeJavaRuntime = include;
  636       }
  637   
  638       /**
  639        * Gets whether or not the java runtime should be included in this
  640        * task's classpath.
  641        * @return the includejavaruntime attribute
  642        */
  643       public boolean getIncludejavaruntime() {
  644           return includeJavaRuntime;
  645       }
  646   
  647       /**
  648        * If true, forks the javac compiler.
  649        *
  650        * @param f "true|false|on|off|yes|no"
  651        */
  652       public void setFork(boolean f) {
  653           fork = f;
  654       }
  655   
  656       /**
  657        * Sets the name of the javac executable.
  658        *
  659        * <p>Ignored unless fork is true or extJavac has been specified
  660        * as the compiler.</p>
  661        * @param forkExec the name of the executable
  662        */
  663       public void setExecutable(String forkExec) {
  664           forkedExecutable = forkExec;
  665       }
  666   
  667       /**
  668        * The value of the executable attribute, if any.
  669        *
  670        * @since Ant 1.6
  671        * @return the name of the java executable
  672        */
  673       public String getExecutable() {
  674           return forkedExecutable;
  675       }
  676   
  677       /**
  678        * Is this a forked invocation of JDK's javac?
  679        * @return true if this is a forked invocation
  680        */
  681       public boolean isForkedJavac() {
  682           return fork || EXTJAVAC.equalsIgnoreCase(getCompiler());
  683       }
  684   
  685       /**
  686        * The name of the javac executable to use in fork-mode.
  687        *
  688        * <p>This is either the name specified with the executable
  689        * attribute or the full path of the javac compiler of the VM Ant
  690        * is currently running in - guessed by Ant.</p>
  691        *
  692        * <p>You should <strong>not</strong> invoke this method if you
  693        * want to get the value of the executable command - use {@link
  694        * #getExecutable getExecutable} for this.</p>
  695        * @return the name of the javac executable
  696        */
  697       public String getJavacExecutable() {
  698           if (forkedExecutable == null && isForkedJavac()) {
  699               forkedExecutable = getSystemJavac();
  700           } else if (forkedExecutable != null && !isForkedJavac()) {
  701               forkedExecutable = null;
  702           }
  703           return forkedExecutable;
  704       }
  705   
  706       /**
  707        * If true, enables the -nowarn option.
  708        * @param flag if true, enable the -nowarn option
  709        */
  710       public void setNowarn(boolean flag) {
  711           this.nowarn = flag;
  712       }
  713   
  714       /**
  715        * Should the -nowarn option be used.
  716        * @return true if the -nowarn option should be used
  717        */
  718       public boolean getNowarn() {
  719           return nowarn;
  720       }
  721   
  722       /**
  723        * Adds an implementation specific command-line argument.
  724        * @return a ImplementationSpecificArgument to be configured
  725        */
  726       public ImplementationSpecificArgument createCompilerArg() {
  727           ImplementationSpecificArgument arg =
  728               new ImplementationSpecificArgument();
  729           facade.addImplementationArgument(arg);
  730           return arg;
  731       }
  732   
  733       /**
  734        * Get the additional implementation specific command line arguments.
  735        * @return array of command line arguments, guaranteed to be non-null.
  736        */
  737       public String[] getCurrentCompilerArgs() {
  738           String chosen = facade.getExplicitChoice();
  739           try {
  740               // make sure facade knows about magic properties and fork setting
  741               String appliedCompiler = getCompiler();
  742               facade.setImplementation(appliedCompiler);
  743   
  744               String[] result = facade.getArgs();
  745   
  746               String altCompilerName = getAltCompilerName(facade.getImplementation());
  747   
  748               if (result.length == 0 && altCompilerName != null) {
  749                   facade.setImplementation(altCompilerName);
  750                   result = facade.getArgs();
  751               }
  752   
  753               return result;
  754   
  755           } finally {
  756               facade.setImplementation(chosen);
  757           }
  758       }
  759   
  760       private String getAltCompilerName(String anImplementation) {
  761           if (JAVAC16.equalsIgnoreCase(anImplementation)
  762                   || JAVAC15.equalsIgnoreCase(anImplementation)
  763                   || JAVAC14.equalsIgnoreCase(anImplementation)
  764                   || JAVAC13.equalsIgnoreCase(anImplementation)) {
  765               return MODERN;
  766           }
  767           if (JAVAC12.equalsIgnoreCase(anImplementation)
  768                   || JAVAC11.equalsIgnoreCase(anImplementation)) {
  769               return CLASSIC;
  770           }
  771           if (MODERN.equalsIgnoreCase(anImplementation)) {
  772               String nextSelected = assumedJavaVersion();
  773               if (JAVAC16.equalsIgnoreCase(nextSelected)
  774                       || JAVAC15.equalsIgnoreCase(nextSelected)
  775                       || JAVAC14.equalsIgnoreCase(nextSelected)
  776                       || JAVAC13.equalsIgnoreCase(nextSelected)) {
  777                   return nextSelected;
  778               }
  779           }
  780           if (CLASSIC.equalsIgnoreCase(anImplementation)) {
  781               return assumedJavaVersion();
  782           }
  783           if (EXTJAVAC.equalsIgnoreCase(anImplementation)) {
  784               return assumedJavaVersion();
  785           }
  786           return null;
  787       }
  788   
  789       /**
  790        * Where Ant should place temporary files.
  791        *
  792        * @since Ant 1.6
  793        * @param tmpDir the temporary directory
  794        */
  795       public void setTempdir(File tmpDir) {
  796           this.tmpDir = tmpDir;
  797       }
  798   
  799       /**
  800        * Where Ant should place temporary files.
  801        *
  802        * @since Ant 1.6
  803        * @return the temporary directory
  804        */
  805       public File getTempdir() {
  806           return tmpDir;
  807       }
  808   
  809       /**
  810        * The property to set on compliation success.
  811        * This property will not be set if the compilation
  812        * fails, or if there are no files to compile.
  813        * @param updatedProperty the property name to use.
  814        * @since Ant 1.7.1.
  815        */
  816       public void setUpdatedProperty(String updatedProperty) {
  817           this.updatedProperty = updatedProperty;
  818       }
  819   
  820       /**
  821        * The property to set on compliation failure.
  822        * This property will be set if the compilation
  823        * fails.
  824        * @param errorProperty the property name to use.
  825        * @since Ant 1.7.1.
  826        */
  827       public void setErrorProperty(String errorProperty) {
  828           this.errorProperty = errorProperty;
  829       }
  830   
  831       /**
  832        * This property controls whether to include the
  833        * destination classes directory in the classpath
  834        * given to the compiler.
  835        * The default value is "true".
  836        * @param includeDestClasses the value to use.
  837        */
  838       public void setIncludeDestClasses(boolean includeDestClasses) {
  839           this.includeDestClasses = includeDestClasses;
  840       }
  841   
  842       /**
  843        * Get the value of the includeDestClasses property.
  844        * @return the value.
  845        */
  846       public boolean isIncludeDestClasses() {
  847           return includeDestClasses;
  848       }
  849   
  850       /**
  851        * Get the result of the javac task (success or failure).
  852        * @return true if compilation succeeded, or
  853        *         was not neccessary, false if the compilation failed.
  854        */
  855       public boolean getTaskSuccess() {
  856           return taskSuccess;
  857       }
  858   
  859       /**
  860        * The classpath to use when loading the compiler implementation
  861        * if it is not a built-in one.
  862        *
  863        * @since Ant 1.8.0
  864        */
  865       public Path createCompilerClasspath() {
  866           return facade.getImplementationClasspath(getProject());
  867       }
  868   
  869       /**
  870        * Set the compiler adapter explicitly.
  871        * @since Ant 1.8.0
  872        */
  873       public void add(CompilerAdapter adapter) {
  874           if (nestedAdapter != null) {
  875               throw new BuildException("Can't have more than one compiler"
  876                                        + " adapter");
  877           }
  878           nestedAdapter = adapter;
  879       }
  880   
  881       /**
  882        * Executes the task.
  883        * @exception BuildException if an error occurs
  884        */
  885       public void execute() throws BuildException {
  886           checkParameters();
  887           resetFileLists();
  888   
  889           // scan source directories and dest directory to build up
  890           // compile lists
  891           String[] list = src.list();
  892           for (int i = 0; i < list.length; i++) {
  893               File srcDir = getProject().resolveFile(list[i]);
  894               if (!srcDir.exists()) {
  895                   throw new BuildException("srcdir \""
  896                                            + srcDir.getPath()
  897                                            + "\" does not exist!", getLocation());
  898               }
  899   
  900               DirectoryScanner ds = this.getDirectoryScanner(srcDir);
  901               String[] files = ds.getIncludedFiles();
  902   
  903               scanDir(srcDir, destDir != null ? destDir : srcDir, files);
  904           }
  905   
  906           compile();
  907           if (updatedProperty != null
  908               && taskSuccess
  909               && compileList.length != 0) {
  910               getProject().setNewProperty(updatedProperty, "true");
  911           }
  912       }
  913   
  914       /**
  915        * Clear the list of files to be compiled and copied..
  916        */
  917       protected void resetFileLists() {
  918           compileList = new File[0];
  919           packageInfos = new HashMap();
  920       }
  921   
  922       /**
  923        * Scans the directory looking for source files to be compiled.
  924        * The results are returned in the class variable compileList
  925        *
  926        * @param srcDir   The source directory
  927        * @param destDir  The destination directory
  928        * @param files    An array of filenames
  929        */
  930       protected void scanDir(File srcDir, File destDir, String[] files) {
  931           GlobPatternMapper m = new GlobPatternMapper();
  932           m.setFrom("*.java");
  933           m.setTo("*.class");
  934           SourceFileScanner sfs = new SourceFileScanner(this);
  935           File[] newFiles = sfs.restrictAsFiles(files, srcDir, destDir, m);
  936   
  937           if (newFiles.length > 0) {
  938               lookForPackageInfos(srcDir, newFiles);
  939               File[] newCompileList
  940                   = new File[compileList.length + newFiles.length];
  941               System.arraycopy(compileList, 0, newCompileList, 0,
  942                       compileList.length);
  943               System.arraycopy(newFiles, 0, newCompileList,
  944                       compileList.length, newFiles.length);
  945               compileList = newCompileList;
  946           }
  947       }
  948   
  949       /**
  950        * Gets the list of files to be compiled.
  951        * @return the list of files as an array
  952        */
  953       public File[] getFileList() {
  954           return compileList;
  955       }
  956   
  957       /**
  958        * Is the compiler implementation a jdk compiler
  959        *
  960        * @param compilerImpl the name of the compiler implementation
  961        * @return true if compilerImpl is "modern", "classic",
  962        * "javac1.1", "javac1.2", "javac1.3", "javac1.4", "javac1.5" or
  963        * "javac1.6".
  964        */
  965       protected boolean isJdkCompiler(String compilerImpl) {
  966           return MODERN.equals(compilerImpl)
  967               || CLASSIC.equals(compilerImpl)
  968               || JAVAC16.equals(compilerImpl)
  969               || JAVAC15.equals(compilerImpl)
  970               || JAVAC14.equals(compilerImpl)
  971               || JAVAC13.equals(compilerImpl)
  972               || JAVAC12.equals(compilerImpl)
  973               || JAVAC11.equals(compilerImpl);
  974       }
  975   
  976       /**
  977        * @return the executable name of the java compiler
  978        */
  979       protected String getSystemJavac() {
  980           return JavaEnvUtils.getJdkExecutable("javac");
  981       }
  982   
  983       /**
  984        * Choose the implementation for this particular task.
  985        * @param compiler the name of the compiler
  986        * @since Ant 1.5
  987        */
  988       public void setCompiler(String compiler) {
  989           facade.setImplementation(compiler);
  990       }
  991   
  992       /**
  993        * The implementation for this particular task.
  994        *
  995        * <p>Defaults to the build.compiler property but can be overridden
  996        * via the compiler and fork attributes.</p>
  997        *
  998        * <p>If fork has been set to true, the result will be extJavac
  999        * and not classic or java1.2 - no matter what the compiler
 1000        * attribute looks like.</p>
 1001        *
 1002        * @see #getCompilerVersion
 1003        * @return the compiler.
 1004        * @since Ant 1.5
 1005        */
 1006       public String getCompiler() {
 1007           String compilerImpl = getCompilerVersion();
 1008           if (fork) {
 1009               if (isJdkCompiler(compilerImpl)) {
 1010                   compilerImpl = EXTJAVAC;
 1011               } else {
 1012                   log("Since compiler setting isn't classic or modern, "
 1013                       + "ignoring fork setting.", Project.MSG_WARN);
 1014               }
 1015           }
 1016           return compilerImpl;
 1017       }
 1018   
 1019       /**
 1020        * The implementation for this particular task.
 1021        *
 1022        * <p>Defaults to the build.compiler property but can be overridden
 1023        * via the compiler attribute.</p>
 1024        *
 1025        * <p>This method does not take the fork attribute into
 1026        * account.</p>
 1027        *
 1028        * @see #getCompiler
 1029        * @return the compiler.
 1030        *
 1031        * @since Ant 1.5
 1032        */
 1033       public String getCompilerVersion() {
 1034           facade.setMagicValue(getProject().getProperty("build.compiler"));
 1035           return facade.getImplementation();
 1036       }
 1037   
 1038       /**
 1039        * Check that all required attributes have been set and nothing
 1040        * silly has been entered.
 1041        *
 1042        * @since Ant 1.5
 1043        * @exception BuildException if an error occurs
 1044        */
 1045       protected void checkParameters() throws BuildException {
 1046           if (src == null) {
 1047               throw new BuildException("srcdir attribute must be set!",
 1048                                        getLocation());
 1049           }
 1050           if (src.size() == 0) {
 1051               throw new BuildException("srcdir attribute must be set!",
 1052                                        getLocation());
 1053           }
 1054   
 1055           if (destDir != null && !destDir.isDirectory()) {
 1056               throw new BuildException("destination directory \""
 1057                                        + destDir
 1058                                        + "\" does not exist "
 1059                                        + "or is not a directory", getLocation());
 1060           }
 1061           if (includeAntRuntime == null && getProject().getProperty("build.sysclasspath") == null) {
 1062               log(getLocation() + "warning: 'includeantruntime' was not set, " +
 1063                       "defaulting to build.sysclasspath=last; set to false for repeatable builds",
 1064                       Project.MSG_WARN);
 1065           }
 1066       }
 1067   
 1068       /**
 1069        * Perform the compilation.
 1070        *
 1071        * @since Ant 1.5
 1072        */
 1073       protected void compile() {
 1074           String compilerImpl = getCompiler();
 1075   
 1076           if (compileList.length > 0) {
 1077               log("Compiling " + compileList.length + " source file"
 1078                   + (compileList.length == 1 ? "" : "s")
 1079                   + (destDir != null ? " to " + destDir : ""));
 1080   
 1081               if (listFiles) {
 1082                   for (int i = 0; i < compileList.length; i++) {
 1083                     String filename = compileList[i].getAbsolutePath();
 1084                     log(filename);
 1085                   }
 1086               }
 1087   
 1088               CompilerAdapter adapter =
 1089                   nestedAdapter != null ? nestedAdapter :
 1090                   CompilerAdapterFactory.getCompiler(compilerImpl, this,
 1091                                                      createCompilerClasspath());
 1092   
 1093               // now we need to populate the compiler adapter
 1094               adapter.setJavac(this);
 1095   
 1096               // finally, lets execute the compiler!!
 1097               if (adapter.execute()) {
 1098                   // Success
 1099                   try {
 1100                       generateMissingPackageInfoClasses();
 1101                   } catch (IOException x) {
 1102                       // Should this be made a nonfatal warning?
 1103                       throw new BuildException(x, getLocation());
 1104                   }
 1105               } else {
 1106                   // Fail path
 1107                   this.taskSuccess = false;
 1108                   if (errorProperty != null) {
 1109                       getProject().setNewProperty(
 1110                           errorProperty, "true");
 1111                   }
 1112                   if (failOnError) {
 1113                       throw new BuildException(FAIL_MSG, getLocation());
 1114                   } else {
 1115                       log(FAIL_MSG, Project.MSG_ERR);
 1116                   }
 1117               }
 1118           }
 1119       }
 1120   
 1121       /**
 1122        * Adds an "compiler" attribute to Commandline$Attribute used to
 1123        * filter command line attributes based on the current
 1124        * implementation.
 1125        */
 1126       public class ImplementationSpecificArgument extends
 1127           org.apache.tools.ant.util.facade.ImplementationSpecificArgument {
 1128   
 1129           /**
 1130            * @param impl the name of the compiler
 1131            */
 1132           public void setCompiler(String impl) {
 1133               super.setImplementation(impl);
 1134           }
 1135       }
 1136   
 1137       private void lookForPackageInfos(File srcDir, File[] newFiles) {
 1138           for (int i = 0; i < newFiles.length; i++) {
 1139               File f = newFiles[i];
 1140               if (!f.getName().equals("package-info.java")) {
 1141                   continue;
 1142               }
 1143               String path = FILE_UTILS.removeLeadingPath(srcDir, f).
 1144                       replace(File.separatorChar, '/');
 1145               String suffix = "/package-info.java";
 1146               if (!path.endsWith(suffix)) {
 1147                   log("anomalous package-info.java path: " + path, Project.MSG_WARN);
 1148                   continue;
 1149               }
 1150               String pkg = path.substring(0, path.length() - suffix.length());
 1151               packageInfos.put(pkg, new Long(f.lastModified()));
 1152           }
 1153       }
 1154   
 1155       /**
 1156        * Ensure that every {@code package-info.java} produced a {@code package-info.class}.
 1157        * Otherwise this task's up-to-date tracking mechanisms do not work.
 1158        * @see <a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=43114">Bug #43114</a>
 1159        */
 1160       private void generateMissingPackageInfoClasses() throws IOException {
 1161           for (Iterator i = packageInfos.entrySet().iterator(); i.hasNext(); ) {
 1162               Map.Entry entry = (Map.Entry) i.next();
 1163               String pkg = (String) entry.getKey();
 1164               Long sourceLastMod = (Long) entry.getValue();
 1165               File pkgBinDir = new File(destDir, pkg.replace('/', File.separatorChar));
 1166               pkgBinDir.mkdirs();
 1167               File pkgInfoClass = new File(pkgBinDir, "package-info.class");
 1168               if (pkgInfoClass.isFile() && pkgInfoClass.lastModified() >= sourceLastMod.longValue()) {
 1169                   continue;
 1170               }
 1171               log("Creating empty " + pkgInfoClass);
 1172               OutputStream os = new FileOutputStream(pkgInfoClass);
 1173               try {
 1174                   os.write(PACKAGE_INFO_CLASS_HEADER);
 1175                   byte[] name = pkg.getBytes("UTF-8");
 1176                   int length = name.length + /* "/package-info" */ 13;
 1177                   os.write((byte) length / 256);
 1178                   os.write((byte) length % 256);
 1179                   os.write(name);
 1180                   os.write(PACKAGE_INFO_CLASS_FOOTER);
 1181               } finally {
 1182                   os.close();
 1183               }
 1184           }
 1185       }
 1186       private static final byte[] PACKAGE_INFO_CLASS_HEADER = {
 1187           (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, 0x00, 0x00, 0x00,
 1188           0x31, 0x00, 0x07, 0x07, 0x00, 0x05, 0x07, 0x00, 0x06, 0x01, 0x00, 0x0a,
 1189           0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x01, 0x00,
 1190           0x11, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2d, 0x69, 0x6e, 0x66,
 1191           0x6f, 0x2e, 0x6a, 0x61, 0x76, 0x61, 0x01
 1192       };
 1193       private static final byte[] PACKAGE_INFO_CLASS_FOOTER = {
 1194           0x2f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2d, 0x69, 0x6e, 0x66,
 1195           0x6f, 0x01, 0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e,
 1196           0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x02, 0x00, 0x00, 0x01,
 1197           0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
 1198           0x00, 0x00, 0x00, 0x02, 0x00, 0x04
 1199       };
 1200   
 1201   }

Save This Page
Home » apache-ant-1.8.1 » org.apache.tools » ant » taskdefs » [javadoc | source]