src/share/classes/com/sun/tools/apt/main/Main.java

Wed, 02 Jul 2008 12:56:02 -0700

author
xdono
date
Wed, 02 Jul 2008 12:56:02 -0700
changeset 54
eaf608c64fec
parent 50
b9bcea8bbe24
child 285
4ce1c1400334
permissions
-rw-r--r--

6719955: Update copyright year
Summary: Update copyright year for files that have been modified in 2008
Reviewed-by: ohair, tbell

     1 /*
     2  * Copyright 2004-2008 Sun Microsystems, Inc.  All Rights Reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Sun designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Sun in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
    23  * have any questions.
    24  */
    26 package com.sun.tools.apt.main;
    28 import java.io.File;
    29 import java.io.FileOutputStream;
    30 import java.io.FileWriter;
    31 import java.io.IOException;
    32 import java.io.PrintWriter;
    33 import java.text.MessageFormat;
    34 import java.util.ResourceBundle;
    35 import java.util.MissingResourceException;
    36 import java.util.StringTokenizer;
    37 import java.util.Map;
    38 import java.util.HashMap;
    39 import java.util.Collections;
    40 import java.util.Collection;
    42 import java.net.URLClassLoader;
    43 import java.net.URL;
    44 import java.io.File;
    45 import java.net.MalformedURLException;
    47 import com.sun.tools.javac.file.Paths;
    48 import com.sun.tools.javac.code.Source;
    49 import com.sun.tools.javac.code.Symbol;
    50 import com.sun.tools.javac.code.Type;
    51 import com.sun.tools.javac.jvm.Target;
    52 import com.sun.tools.javac.util.*;
    54 import com.sun.tools.apt.comp.AnnotationProcessingError;
    55 import com.sun.tools.apt.comp.UsageMessageNeededException;
    56 import com.sun.tools.apt.util.Bark;
    57 import com.sun.mirror.apt.AnnotationProcessorFactory;
    59 /** This class provides a commandline interface to the apt build-time
    60  *  tool.
    61  *
    62  *  <p><b>This is NOT part of any API supported by Sun Microsystems.
    63  *  If you write code that depends on this, you do so at your own
    64  *  risk.  This code and its internal interfaces are subject to change
    65  *  or deletion without notice.</b>
    66  */
    67 public class Main {
    69     /** For testing: enter any options you want to be set implicitly
    70      *  here.
    71      */
    72     static String[] forcedOpts = {
    73         // Preserve parameter names from class files if the class was
    74         // compiled with debug enabled
    75         "-XDsave-parameter-names"
    76     };
    78     /** The name of the compiler, for use in diagnostics.
    79      */
    80     String ownName;
    82     /** The writer to use for diagnostic output.
    83      */
    84     PrintWriter out;
    87     /** Instantiated factory to use in lieu of discovery process.
    88      */
    89     AnnotationProcessorFactory providedFactory = null;
    91     /** Map representing original command-line arguments.
    92      */
    93     Map<String,String> origOptions = new HashMap<String, String>();
    95     /** Classloader to use for finding factories.
    96      */
    97     ClassLoader aptCL = null;
    99     /** Result codes.
   100      */
   101     static final int
   102         EXIT_OK = 0,        // Compilation completed with no errors.
   103         EXIT_ERROR = 1,     // Completed but reported errors.
   104         EXIT_CMDERR = 2,    // Bad command-line arguments
   105         EXIT_SYSERR = 3,    // System error or resource exhaustion.
   106         EXIT_ABNORMAL = 4;  // Compiler terminated abnormally
   108     /** This class represents an option recognized by the main program
   109      */
   110     private class Option {
   111         /** Whether or not the option is used only aptOnly.
   112          */
   113         boolean aptOnly = false;
   115         /** Option string.
   116          */
   117         String name;
   119         /** Documentation key for arguments.
   120          */
   121         String argsNameKey;
   123         /** Documentation key for description.
   124          */
   125         String descrKey;
   127         /** Suffix option (-foo=bar or -foo:bar)
   128          */
   129         boolean hasSuffix;
   131         Option(String name, String argsNameKey, String descrKey) {
   132             this.name = name;
   133             this.argsNameKey = argsNameKey;
   134             this.descrKey = descrKey;
   135             char lastChar = name.charAt(name.length()-1);
   136             hasSuffix = lastChar == ':' || lastChar == '=';
   137         }
   138         Option(String name, String descrKey) {
   139             this(name, null, descrKey);
   140         }
   142         public String toString() {
   143             return name;
   144         }
   146         /** Does this option take a (separate) operand?
   147          */
   148         boolean hasArg() {
   149             return argsNameKey != null && !hasSuffix;
   150         }
   152         /** Does argument string match option pattern?
   153          *  @param arg        The command line argument string.
   154          */
   155         boolean matches(String arg) {
   156             return hasSuffix ? arg.startsWith(name) : arg.equals(name);
   157         }
   159         /** For javac-only options, print nothing.
   160          */
   161         void help() {
   162         }
   164         String helpSynopsis() {
   165             return name +
   166                 (argsNameKey == null ? "" :
   167                  ((hasSuffix ? "" : " ") +
   168                   getLocalizedString(argsNameKey)));
   169         }
   171         /** Print a line of documentation describing this option, if non-standard.
   172          */
   173         void xhelp() {}
   175         /** Process the option (with arg). Return true if error detected.
   176          */
   177         boolean process(String option, String arg) {
   178             options.put(option, arg);
   179             return false;
   180         }
   182         /** Process the option (without arg). Return true if error detected.
   183          */
   184         boolean process(String option) {
   185             if (hasSuffix)
   186                 return process(name, option.substring(name.length()));
   187             else
   188                 return process(option, option);
   189         }
   190     };
   192     private class SharedOption extends Option {
   193         SharedOption(String name, String argsNameKey, String descrKey) {
   194             super(name, argsNameKey, descrKey);
   195         }
   197         SharedOption(String name, String descrKey) {
   198             super(name, descrKey);
   199         }
   201         void help() {
   202             String s = "  " + helpSynopsis();
   203             out.print(s);
   204             for (int j = s.length(); j < 29; j++) out.print(" ");
   205             Bark.printLines(out, getLocalizedString(descrKey));
   206         }
   208     }
   210     private class AptOption extends Option {
   211         AptOption(String name, String argsNameKey, String descrKey) {
   212             super(name, argsNameKey, descrKey);
   213             aptOnly = true;
   214         }
   216         AptOption(String name, String descrKey) {
   217             super(name, descrKey);
   218             aptOnly = true;
   219         }
   221         /** Print a line of documentation describing this option, if standard.
   222          */
   223         void help() {
   224             String s = "  " + helpSynopsis();
   225             out.print(s);
   226             for (int j = s.length(); j < 29; j++) out.print(" ");
   227             Bark.printLines(out, getLocalizedString(descrKey));
   228         }
   230     }
   232     /** A nonstandard or extended (-X) option
   233      */
   234     private class XOption extends Option {
   235         XOption(String name, String argsNameKey, String descrKey) {
   236             super(name, argsNameKey, descrKey);
   237         }
   238         XOption(String name, String descrKey) {
   239             this(name, null, descrKey);
   240         }
   241         void help() {}
   242         void xhelp() {}
   243     };
   245     /** A nonstandard or extended (-X) option
   246      */
   247     private class AptXOption extends Option {
   248         AptXOption(String name, String argsNameKey, String descrKey) {
   249             super(name, argsNameKey, descrKey);
   250             aptOnly = true;
   251         }
   252         AptXOption(String name, String descrKey) {
   253             this(name, null, descrKey);
   254         }
   255         void xhelp() {
   256             String s = "  " + helpSynopsis();
   257             out.print(s);
   258             for (int j = s.length(); j < 29; j++) out.print(" ");
   259             Log.printLines(out, getLocalizedString(descrKey));
   260         }
   261     };
   263     /** A hidden (implementor) option
   264      */
   265     private class HiddenOption extends Option {
   266         HiddenOption(String name) {
   267             super(name, null, null);
   268         }
   269         HiddenOption(String name, String argsNameKey) {
   270             super(name, argsNameKey, null);
   271         }
   272         void help() {}
   273         void xhelp() {}
   274     };
   276     private class AptHiddenOption extends HiddenOption {
   277         AptHiddenOption(String name) {
   278             super(name);
   279             aptOnly = true;
   280         }
   281         AptHiddenOption(String name, String argsNameKey) {
   282             super(name, argsNameKey);
   283             aptOnly = true;
   284         }
   285     }
   287     private Option[] recognizedOptions = {
   288         new Option("-g",                                        "opt.g"),
   289         new Option("-g:none",                                   "opt.g.none") {
   290             boolean process(String option) {
   291                 options.put("-g:", "none");
   292                 return false;
   293             }
   294         },
   296         new Option("-g:{lines,vars,source}",                    "opt.g.lines.vars.source") {
   297             boolean matches(String s) {
   298                 return s.startsWith("-g:");
   299             }
   300             boolean process(String option) {
   301                 String suboptions = option.substring(3);
   302                 options.put("-g:", suboptions);
   303                 // enter all the -g suboptions as "-g:suboption"
   304                 for (StringTokenizer t = new StringTokenizer(suboptions, ","); t.hasMoreTokens(); ) {
   305                     String tok = t.nextToken();
   306                     String opt = "-g:" + tok;
   307                     options.put(opt, opt);
   308                 }
   309                 return false;
   310             }
   311         },
   313         new XOption("-Xlint",                                   "opt.Xlint"),
   314         new XOption("-Xlint:{"
   315                     + "all,"
   316                     + "cast,deprecation,divzero,empty,unchecked,fallthrough,path,serial,finally,overrides,"
   317                     + "-cast,-deprecation,-divzero,-empty,-unchecked,-fallthrough,-path,-serial,-finally,-overrides,"
   318                     + "none}",
   319                                                                 "opt.Xlint.suboptlist") {
   320             boolean matches(String s) {
   321                 return s.startsWith("-Xlint:");
   322             }
   323             boolean process(String option) {
   324                 String suboptions = option.substring(7);
   325                 options.put("-Xlint:", suboptions);
   326                 // enter all the -Xlint suboptions as "-Xlint:suboption"
   327                 for (StringTokenizer t = new StringTokenizer(suboptions, ","); t.hasMoreTokens(); ) {
   328                     String tok = t.nextToken();
   329                     String opt = "-Xlint:" + tok;
   330                     options.put(opt, opt);
   331                 }
   332                 return false;
   333             }
   334         },
   336         new Option("-nowarn",                                   "opt.nowarn"),
   337         new Option("-verbose",                                  "opt.verbose"),
   339         // -deprecation is retained for command-line backward compatibility
   340         new Option("-deprecation",                              "opt.deprecation") {
   341                 boolean process(String option) {
   342                     options.put("-Xlint:deprecation", option);
   343                     return false;
   344                 }
   345             },
   347         new SharedOption("-classpath",     "opt.arg.path",      "opt.classpath"),
   348         new SharedOption("-cp",            "opt.arg.path",      "opt.classpath") {
   349             boolean process(String option, String arg) {
   350                 return super.process("-classpath", arg);
   351             }
   352         },
   353         new Option("-sourcepath",          "opt.arg.path",      "opt.sourcepath"),
   354         new Option("-bootclasspath",       "opt.arg.path",      "opt.bootclasspath") {
   355             boolean process(String option, String arg) {
   356                 options.remove("-Xbootclasspath/p:");
   357                 options.remove("-Xbootclasspath/a:");
   358                 return super.process(option, arg);
   359             }
   360         },
   361         new XOption("-Xbootclasspath/p:",  "opt.arg.path", "opt.Xbootclasspath.p"),
   362         new XOption("-Xbootclasspath/a:",  "opt.arg.path", "opt.Xbootclasspath.a"),
   363         new XOption("-Xbootclasspath:",    "opt.arg.path", "opt.bootclasspath") {
   364             boolean process(String option, String arg) {
   365                 options.remove("-Xbootclasspath/p:");
   366                 options.remove("-Xbootclasspath/a:");
   367                 return super.process("-bootclasspath", arg);
   368             }
   369         },
   370         new Option("-extdirs",             "opt.arg.dirs",      "opt.extdirs"),
   371         new XOption("-Djava.ext.dirs=",    "opt.arg.dirs",      "opt.extdirs") {
   372             boolean process(String option, String arg) {
   373                 return super.process("-extdirs", arg);
   374             }
   375         },
   376         new Option("-endorseddirs",        "opt.arg.dirs",      "opt.endorseddirs"),
   377         new XOption("-Djava.endorsed.dirs=","opt.arg.dirs",     "opt.endorseddirs") {
   378             boolean process(String option, String arg) {
   379                 return super.process("-endorseddirs", arg);
   380             }
   381         },
   382         new Option("-proc:{none, only}",                        "opt.proc.none.only") {
   383             public boolean matches(String s) {
   384                 return s.equals("-proc:none") || s.equals("-proc:only");
   385             }
   386         },
   387         new Option("-processor",        "opt.arg.class",        "opt.processor"),
   388         new Option("-processorpath",    "opt.arg.path",         "opt.processorpath"),
   390         new SharedOption("-d",          "opt.arg.path", "opt.d"),
   391         new SharedOption("-s",          "opt.arg.path", "opt.s"),
   392         new Option("-encoding",         "opt.arg.encoding",     "opt.encoding"),
   393         new SharedOption("-source",             "opt.arg.release",      "opt.source") {
   394             boolean process(String option, String operand) {
   395                 Source source = Source.lookup(operand);
   396                 if (source == null) {
   397                     error("err.invalid.source", operand);
   398                     return true;
   399                 } else if (source.compareTo(Source.JDK1_5) > 0) {
   400                     error("err.unsupported.source.version", operand);
   401                     return true;
   402                 }
   403                 return super.process(option, operand);
   404             }
   405         },
   406         new Option("-target",           "opt.arg.release",      "opt.target") {
   407             boolean process(String option, String operand) {
   408                 Target target = Target.lookup(operand);
   409                 if (target == null) {
   410                     error("err.invalid.target", operand);
   411                     return true;
   412                 } else if (target.compareTo(Target.JDK1_5) > 0) {
   413                     error("err.unsupported.target.version", operand);
   414                     return true;
   415                 }
   416                 return super.process(option, operand);
   417             }
   418         },
   419         new AptOption("-version",               "opt.version") {
   420             boolean process(String option) {
   421                 Bark.printLines(out, ownName + " " + JavaCompiler.version());
   422                 return super.process(option);
   423             }
   424         },
   425         new HiddenOption("-fullversion"),
   426         new AptOption("-help",                                  "opt.help") {
   427             boolean process(String option) {
   428                 Main.this.help();
   429                 return super.process(option);
   430             }
   431         },
   432         new SharedOption("-X",                                  "opt.X") {
   433             boolean process(String option) {
   434                 Main.this.xhelp();
   435                 return super.process(option);
   436             }
   437         },
   439         // This option exists only for the purpose of documenting itself.
   440         // It's actually implemented by the launcher.
   441         new AptOption("-J",             "opt.arg.flag",         "opt.J") {
   442             String helpSynopsis() {
   443                 hasSuffix = true;
   444                 return super.helpSynopsis();
   445             }
   446             boolean process(String option) {
   447                 throw new AssertionError
   448                     ("the -J flag should be caught by the launcher.");
   449             }
   450         },
   453         new SharedOption("-A",          "opt.proc.flag",        "opt.A") {
   454                 String helpSynopsis() {
   455                     hasSuffix = true;
   456                     return super.helpSynopsis();
   457                 }
   459                 boolean matches(String arg) {
   460                     return arg.startsWith("-A");
   461                 }
   463                 boolean hasArg() {
   464                     return false;
   465                 }
   467                 boolean process(String option) {
   468                     return process(option, option);
   469                 }
   470             },
   472         new AptOption("-nocompile",     "opt.nocompile"),
   474         new AptOption("-print",         "opt.print"),
   476         new AptOption("-factorypath", "opt.arg.path", "opt.factorypath"),
   478         new AptOption("-factory",     "opt.arg.class", "opt.factory"),
   480         new AptXOption("-XListAnnotationTypes", "opt.XListAnnotationTypes"),
   482         new AptXOption("-XListDeclarations",    "opt.XListDeclarations"),
   484         new AptXOption("-XPrintAptRounds",      "opt.XPrintAptRounds"),
   486         new AptXOption("-XPrintFactoryInfo",    "opt.XPrintFactoryInfo"),
   488         /*
   489          * Option to treat both classes and source files as
   490          * declarations that can be given on the command line and
   491          * processed as the result of an apt round.
   492          */
   493         new AptXOption("-XclassesAsDecls", "opt.XClassesAsDecls"),
   495         // new Option("-moreinfo",                                      "opt.moreinfo") {
   496         new HiddenOption("-moreinfo") {
   497             boolean process(String option) {
   498                 Type.moreInfo = true;
   499                 return super.process(option);
   500             }
   501         },
   503         // treat warnings as errors
   504         new HiddenOption("-Werror"),
   506         // use complex inference from context in the position of a method call argument
   507         new HiddenOption("-complexinference"),
   509         // prompt after each error
   510         // new Option("-prompt",                                        "opt.prompt"),
   511         new HiddenOption("-prompt"),
   513         // dump stack on error
   514         new HiddenOption("-doe"),
   516         // display warnings for generic unchecked and unsafe operations
   517         new HiddenOption("-warnunchecked") {
   518             boolean process(String option) {
   519                 options.put("-Xlint:unchecked", option);
   520                 return false;
   521             }
   522         },
   524         new HiddenOption("-Xswitchcheck") {
   525             boolean process(String option) {
   526                 options.put("-Xlint:switchcheck", option);
   527                 return false;
   528             }
   529         },
   531         // generate trace output for subtyping operations
   532         new HiddenOption("-debugsubtyping"),
   534         new XOption("-Xmaxerrs",        "opt.arg.number",       "opt.maxerrs"),
   535         new XOption("-Xmaxwarns",       "opt.arg.number",       "opt.maxwarns"),
   536         new XOption("-Xstdout",         "opt.arg.file",         "opt.Xstdout") {
   537             boolean process(String option, String arg) {
   538                 try {
   539                     out = new PrintWriter(new FileWriter(arg), true);
   540                 } catch (java.io.IOException e) {
   541                     error("err.error.writing.file", arg, e);
   542                     return true;
   543                 }
   544                 return super.process(option, arg);
   545             }
   546         },
   548         new XOption("-Xprint",                                  "opt.print"),
   550         new XOption("-XprintRounds",                            "opt.printRounds"),
   552         new XOption("-XprintProcessorInfo",                     "opt.printProcessorInfo"),
   555         /* -O is a no-op, accepted for backward compatibility. */
   556         new HiddenOption("-O"),
   558         /* -Xjcov produces tables to support the code coverage tool jcov. */
   559         new HiddenOption("-Xjcov"),
   561         /* This is a back door to the compiler's option table.
   562          * -Dx=y sets the option x to the value y.
   563          * -Dx sets the option x to the value x.
   564          */
   565         new HiddenOption("-XD") {
   566             String s;
   567             boolean matches(String s) {
   568                 this.s = s;
   569                 return s.startsWith(name);
   570             }
   571             boolean process(String option) {
   572                 s = s.substring(name.length());
   573                 int eq = s.indexOf('=');
   574                 String key = (eq < 0) ? s : s.substring(0, eq);
   575                 String value = (eq < 0) ? s : s.substring(eq+1);
   576                 options.put(key, value);
   577                 return false;
   578             }
   579         },
   581         new HiddenOption("sourcefile") {
   582                 String s;
   583                 boolean matches(String s) {
   584                     this.s = s;
   585                     return s.endsWith(".java") ||
   586                         (options.get("-XclassesAsDecls") != null);
   587                 }
   588                 boolean process(String option) {
   589                     if (s.endsWith(".java")) {
   590                         if (!sourceFileNames.contains(s))
   591                             sourceFileNames.add(s);
   592                     } else if (options.get("-XclassesAsDecls") != null) {
   593                         classFileNames.add(s);
   594                     }
   595                     return false;
   596                 }
   597             },
   598     };
   600     /**
   601      * Construct a compiler instance.
   602      */
   603     public Main(String name) {
   604         this(name, new PrintWriter(System.err, true));
   605     }
   607     /**
   608      * Construct a compiler instance.
   609      */
   610     public Main(String name, PrintWriter out) {
   611         this.ownName = name;
   612         this.out = out;
   613     }
   615     /** A table of all options that's passed to the JavaCompiler constructor.  */
   616     private Options options = null;
   618     /** The list of source files to process
   619      */
   620     java.util.List<String> sourceFileNames = new java.util.LinkedList<String>();
   622     /** The list of class files to process
   623      */
   624     java.util.List<String> classFileNames = new java.util.LinkedList<String>();
   626     /** List of top level names of generated source files from most recent apt round.
   627      */
   628     java.util.Set<String> genSourceFileNames = new java.util.LinkedHashSet<String>();
   630     /** List of names of generated class files from most recent apt round.
   631      */
   632     java.util.Set<String> genClassFileNames  = new java.util.LinkedHashSet<String>();
   634     /**
   635      * List of all the generated source file names across all apt rounds.
   636      */
   637     java.util.Set<String> aggregateGenSourceFileNames = new java.util.LinkedHashSet<String>();
   639     /**
   640      * List of all the generated class file names across all apt rounds.
   641      */
   642     java.util.Set<String> aggregateGenClassFileNames  = new java.util.LinkedHashSet<String>();
   644     /**
   645      * List of all the generated file names across all apt rounds.
   646      */
   647     java.util.Set<java.io.File> aggregateGenFiles = new java.util.LinkedHashSet<java.io.File>();
   649     /**
   650      * Set of all factories that have provided a processor on some apt round.
   651      */
   652     java.util.Set<Class<? extends AnnotationProcessorFactory> > productiveFactories  =
   653         new java.util.LinkedHashSet<Class<? extends AnnotationProcessorFactory> >();
   657     /** Print a string that explains usage.
   658      */
   659     void help() {
   660         Bark.printLines(out, getLocalizedString("msg.usage.header", ownName));
   661         for (int i=0; i < recognizedOptions.length; i++) {
   662             recognizedOptions[i].help();
   663         }
   664         Bark.printLines(out, getLocalizedString("msg.usage.footer"));
   665         out.println();
   666     }
   668     /** Print a string that explains usage for X options.
   669      */
   670     void xhelp() {
   671         for (int i=0; i<recognizedOptions.length; i++) {
   672             recognizedOptions[i].xhelp();
   673         }
   674         out.println();
   675         Bark.printLines(out, getLocalizedString("msg.usage.nonstandard.footer"));
   676     }
   678     /** Report a usage error.
   679      */
   680     void error(String key, Object... args) {
   681         warning(key, args);
   682         help();
   683     }
   685     /** Report a warning.
   686      */
   687     void warning(String key, Object... args) {
   688         Bark.printLines(out, ownName + ": "
   689                        + getLocalizedString(key, args));
   690     }
   692     /** Process command line arguments: store all command line options
   693      *  in `options' table and return all source filenames.
   694      *  @param args    The array of command line arguments.
   695      */
   696     protected java.util.List<String> processArgs(String[] flags) {
   697         int ac = 0;
   698         while (ac < flags.length) {
   699             String flag = flags[ac];
   700             ac++;
   702             int j;
   703             for (j=0; j < recognizedOptions.length; j++)
   704                 if (recognizedOptions[j].matches(flag))
   705                     break;
   707             if (j == recognizedOptions.length) {
   708                 error("err.invalid.flag", flag);
   709                 return null;
   710             }
   712             Option option = recognizedOptions[j];
   713             if (option.hasArg()) {
   714                 if (ac == flags.length) {
   715                     error("err.req.arg", flag);
   716                     return null;
   717                 }
   718                 String operand = flags[ac];
   719                 ac++;
   720                 if (option.process(flag, operand))
   721                     return null;
   722             } else {
   723                 if (option.process(flag))
   724                     return null;
   725             }
   726         }
   728         String sourceString = options.get("-source");
   729         Source source = (sourceString != null)
   730             ? Source.lookup(sourceString)
   731             : Source.JDK1_5; // JDK 5 is the latest supported source version
   732         String targetString = options.get("-target");
   733         Target target = (targetString != null)
   734             ? Target.lookup(targetString)
   735             : Target.JDK1_5; // JDK 5 is the latest supported source version
   736         // We don't check source/target consistency for CLDC, as J2ME
   737         // profiles are not aligned with J2SE targets; moreover, a
   738         // single CLDC target may have many profiles.  In addition,
   739         // this is needed for the continued functioning of the JSR14
   740         // prototype.
   741         if (Character.isDigit(target.name.charAt(0)) &&
   742             target.compareTo(source.requiredTarget()) < 0) {
   743             if (targetString != null) {
   744                 if (sourceString == null) {
   745                     warning("warn.target.default.source.conflict",
   746                             targetString,
   747                             source.requiredTarget().name);
   748                 } else {
   749                     warning("warn.source.target.conflict",
   750                             sourceString,
   751                             source.requiredTarget().name);
   752                 }
   753                 return null;
   754             } else {
   755                 options.put("-target", source.requiredTarget().name);
   756             }
   757         }
   758         return sourceFileNames;
   759     }
   761     /** Programmatic interface for main function.
   762      * @param args    The command line parameters.
   763      */
   764     public int compile(String[] args, AnnotationProcessorFactory factory) {
   765         int returnCode = 0;
   766         providedFactory = factory;
   768         Context context = new Context();
   769         options = Options.instance(context);
   770         Bark bark;
   772         /*
   773          * Process the command line options to create the intial
   774          * options data.  This processing is at least partially reused
   775          * by any recursive apt calls.
   776          */
   778         // For testing: assume all arguments in forcedOpts are
   779         // prefixed to command line arguments.
   780         processArgs(forcedOpts);
   783         /*
   784          * A run of apt only gets passed the most recently generated
   785          * files; the initial run of apt gets passed the files from
   786          * the command line.
   787          */
   789         java.util.List<String> origFilenames;
   790         try {
   791             // assign args the result of parse to capture results of
   792             // '@file' expansion
   793             origFilenames = processArgs((args=CommandLine.parse(args)));
   794             if (origFilenames == null) {
   795                 return EXIT_CMDERR;
   796             } else if (origFilenames.size() == 0) {
   797                 // it is allowed to compile nothing if just asking for help
   798                 if (options.get("-help") != null ||
   799                     options.get("-X") != null)
   800                     return EXIT_OK;
   801             }
   802         } catch (java.io.FileNotFoundException e) {
   803             Bark.printLines(out, ownName + ": " +
   804                            getLocalizedString("err.file.not.found",
   805                                               e.getMessage()));
   806             return EXIT_SYSERR;
   807         } catch (IOException ex) {
   808             ioMessage(ex);
   809             return EXIT_SYSERR;
   810         } catch (OutOfMemoryError ex) {
   811             resourceMessage(ex);
   812             return EXIT_SYSERR;
   813         } catch (StackOverflowError ex) {
   814             resourceMessage(ex);
   815             return EXIT_SYSERR;
   816         } catch (FatalError ex) {
   817             feMessage(ex);
   818             return EXIT_SYSERR;
   819         } catch (sun.misc.ServiceConfigurationError sce) {
   820             sceMessage(sce);
   821             return EXIT_ABNORMAL;
   822         } catch (Throwable ex) {
   823             bugMessage(ex);
   824             return EXIT_ABNORMAL;
   825         }
   828         boolean firstRound = true;
   829         boolean needSourcePath = false;
   830         boolean needClassPath  = false;
   831         boolean classesAsDecls = options.get("-XclassesAsDecls") != null;
   833         /*
   834          * Create augumented classpath and sourcepath values.
   835          *
   836          * If any of the prior apt rounds generated any new source
   837          * files, the n'th apt round (and any javac invocation) has the
   838          * source destination path ("-s path") as the last element of
   839          * the "-sourcepath" to the n'th call.
   840          *
   841          * If any of the prior apt rounds generated any new class files,
   842          * the n'th apt round (and any javac invocation) has the class
   843          * destination path ("-d path") as the last element of the
   844          * "-classpath" to the n'th call.
   845          */
   846         String augmentedSourcePath = "";
   847         String augmentedClassPath = "";
   848         String baseClassPath = "";
   850         try {
   851             /*
   852              * Record original options for future annotation processor
   853              * invocations.
   854              */
   855             origOptions = new HashMap<String, String>(options.size());
   856             for(String s: options.keySet()) {
   857                 String value;
   858                 if (s.equals(value = options.get(s)))
   859                     origOptions.put(s, (String)null);
   860                 else
   861                     origOptions.put(s, value);
   862             }
   863             origOptions = Collections.unmodifiableMap(origOptions);
   865             {
   866                 // Note: it might be necessary to check for an empty
   867                 // component ("") of the source path or class path
   868                 Paths paths = Paths.instance(context);
   870                 String sourceDest = options.get("-s");
   871                 if (paths.sourcePath() != null) {
   872                     for(File f: paths.sourcePath())
   873                         augmentedSourcePath += (f + File.pathSeparator);
   874                     augmentedSourcePath += (sourceDest == null)?".":sourceDest;
   875                 } else {
   876                     augmentedSourcePath = ".";
   878                     if (sourceDest != null)
   879                         augmentedSourcePath += (File.pathSeparator + sourceDest);
   880                 }
   882                 String classDest = options.get("-d");
   883                 if (paths.userClassPath() != null) {
   884                     for(File f: paths.userClassPath())
   885                         baseClassPath += (f + File.pathSeparator);
   886                     // put baseClassPath into map to handle any
   887                     // value needed for the classloader
   888                     options.put("-classpath", baseClassPath);
   890                     augmentedClassPath = baseClassPath + ((classDest == null)?".":classDest);
   891                 } else {
   892                     baseClassPath = ".";
   893                     if (classDest != null)
   894                         augmentedClassPath = baseClassPath + (File.pathSeparator + classDest);
   895                 }
   896                 assert options.get("-classpath") != null;
   897             }
   899             /*
   900              * Create base and augmented class loaders
   901              */
   902             ClassLoader augmentedAptCL = null;
   903             {
   904             /*
   905              * Use a url class loader to look for classes on the
   906              * user-specified class path. Prepend computed bootclass
   907              * path, which includes extdirs, to the URLClassLoader apt
   908              * uses.
   909              */
   910                 String aptclasspath = "";
   911                 Paths paths = Paths.instance(context);
   912                 String bcp = "";
   913                 Collection<File> bootclasspath = paths.bootClassPath();
   915                 if (bootclasspath != null) {
   916                     for(File f: bootclasspath)
   917                         bcp += (f + File.pathSeparator);
   918                 }
   920                 // If the factory path is set, use that path
   921                 if (providedFactory == null)
   922                     aptclasspath = options.get("-factorypath");
   923                 if (aptclasspath == null)
   924                     aptclasspath = options.get("-classpath");
   926                 assert aptclasspath != null;
   927                 aptclasspath = (bcp + aptclasspath);
   928                 aptCL = new URLClassLoader(pathToURLs(aptclasspath));
   930                 if (providedFactory == null &&
   931                     options.get("-factorypath") != null) // same CL even if new class files written
   932                     augmentedAptCL = aptCL;
   933                 else {
   934                     // Create class loader in case new class files are
   935                     // written
   936                     augmentedAptCL = new URLClassLoader(pathToURLs(augmentedClassPath.
   937                                                                    substring(baseClassPath.length())),
   938                                                         aptCL);
   939                 }
   940             }
   942             int round = 0; // For -XPrintAptRounds
   943             do {
   944                 round++;
   946                 Context newContext = new Context();
   947                 Options newOptions = Options.instance(newContext); // creates a new context
   948                 newOptions.putAll(options);
   950                 // populate with old options... don't bother reparsing command line, etc.
   952                 // if genSource files, must add destination to source path
   953                 if (genSourceFileNames.size() > 0 && !firstRound) {
   954                     newOptions.put("-sourcepath", augmentedSourcePath);
   955                     needSourcePath = true;
   956                 }
   957                 aggregateGenSourceFileNames.addAll(genSourceFileNames);
   958                 sourceFileNames.addAll(genSourceFileNames);
   959                 genSourceFileNames.clear();
   961                 // Don't really need to track this; just have to add -d
   962                 // "foo" to class path if any class files are generated
   963                 if (genClassFileNames.size() > 0) {
   964                     newOptions.put("-classpath", augmentedClassPath);
   965                     aptCL = augmentedAptCL;
   966                     needClassPath = true;
   967                 }
   968                 aggregateGenClassFileNames.addAll(genClassFileNames);
   969                 classFileNames.addAll(genClassFileNames);
   970                 genClassFileNames.clear();
   972                 options = newOptions;
   974                 if (options.get("-XPrintAptRounds") != null) {
   975                     out.println("apt Round : " + round);
   976                     out.println("filenames: " + sourceFileNames);
   977                     if (classesAsDecls)
   978                         out.println("classnames: " + classFileNames);
   979                     out.println("options: " + options);
   980                 }
   982                 returnCode = compile(args, newContext);
   983                 firstRound = false;
   985                 // Check for reported errors before continuing
   986                 bark = Bark.instance(newContext);
   987             } while(((genSourceFileNames.size() != 0 ) ||
   988                      (classesAsDecls && genClassFileNames.size() != 0)) &&
   989                     bark.nerrors == 0);
   990         } catch (UsageMessageNeededException umne) {
   991             help();
   992             return EXIT_CMDERR; // will cause usage message to be printed
   993         }
   995         /*
   996          * Do not compile if a processor has reported an error or if
   997          * there are no source files to process.  A more sophisticated
   998          * test would also fail for syntax errors caught by javac.
   999          */
  1000         if (options.get("-nocompile") == null &&
  1001             options.get("-print")     == null &&
  1002             bark.nerrors == 0 &&
  1003             (origFilenames.size() > 0 || aggregateGenSourceFileNames.size() > 0 )) {
  1004             /*
  1005              * Need to create new argument string for calling javac:
  1006              * 1. apt specific arguments (e.g. -factory) must be stripped out
  1007              * 2. proper settings for sourcepath and classpath must be used
  1008              * 3. generated class names must be added
  1009              * 4. class file names as declarations must be removed
  1010              */
  1012             int newArgsLength = args.length +
  1013                 (needSourcePath?1:0) +
  1014                 (needClassPath?1:0) +
  1015                 aggregateGenSourceFileNames.size();
  1017             // Null out apt-specific options and don't copy over into
  1018             // newArgs. This loop should be a lot faster; the options
  1019             // array should be replaced with a better data structure
  1020             // which includes a map from strings to options.
  1021             //
  1022             // If treating classes as declarations, must strip out
  1023             // class names from the javac argument list
  1024             argLoop:
  1025             for(int i = 0; i < args.length; i++) {
  1026                 int matchPosition = -1;
  1028                 // "-A" by itself is recognized by apt but not javac
  1029                 if (args[i] != null && args[i].equals("-A")) {
  1030                     newArgsLength--;
  1031                     args[i] = null;
  1032                     continue argLoop;
  1033                 } else {
  1034                     optionLoop:
  1035                     for(int j = 0; j < recognizedOptions.length; j++) {
  1036                         if (args[i] != null && recognizedOptions[j].matches(args[i])) {
  1037                             matchPosition = j;
  1038                             break optionLoop;
  1042                     if (matchPosition != -1) {
  1043                         Option op = recognizedOptions[matchPosition];
  1044                         if (op.aptOnly) {
  1045                             newArgsLength--;
  1046                             args[i] = null;
  1047                             if (op.hasArg()) {
  1048                                 newArgsLength--;
  1049                                 args[i+1] = null;
  1051                         } else {
  1052                             if (op.hasArg()) { // skip over next string
  1053                                 i++;
  1054                                 continue argLoop;
  1057                             if ((options.get("-XclassesAsDecls") != null) &&
  1058                                 (matchPosition == (recognizedOptions.length-1)) ){
  1059                                 // Remove class file names from
  1060                                 // consideration by javac.
  1061                                 if (! args[i].endsWith(".java")) {
  1062                                     newArgsLength--;
  1063                                     args[i] = null;
  1071             String newArgs[] = new String[newArgsLength];
  1073             int j = 0;
  1074             for(int i=0; i < args.length; i++) {
  1075                 if (args[i] != null)
  1076                     newArgs[j++] = args[i];
  1079             if (needClassPath)
  1080                 newArgs[j++] = "-XD-classpath=" + augmentedClassPath;
  1082             if (needSourcePath) {
  1083                 newArgs[j++] = "-XD-sourcepath=" + augmentedSourcePath;
  1085                 for(String s: aggregateGenSourceFileNames)
  1086                     newArgs[j++] = s;
  1089             returnCode = com.sun.tools.javac.Main.compile(newArgs);
  1092         return returnCode;
  1095     /** Programmatic interface for main function.
  1096      * @param args    The command line parameters.
  1097      */
  1098     int compile(String[] args, Context context) {
  1099         boolean assertionsEnabled = false;
  1100         assert assertionsEnabled = true;
  1101         if (!assertionsEnabled) {
  1102             // Bark.printLines(out, "fatal error: assertions must be enabled when running javac");
  1103             // return EXIT_ABNORMAL;
  1105         int exitCode = EXIT_OK;
  1107         JavaCompiler comp = null;
  1108         try {
  1109             context.put(Bark.outKey, out);
  1111             comp = JavaCompiler.instance(context);
  1112             if (comp == null)
  1113                 return EXIT_SYSERR;
  1115             java.util.List<String> nameList = new java.util.LinkedList<String>();
  1116             nameList.addAll(sourceFileNames);
  1117             if (options.get("-XclassesAsDecls") != null)
  1118                 nameList.addAll(classFileNames);
  1120             List<Symbol.ClassSymbol> cs
  1121                 = comp.compile(List.from(nameList.toArray(new String[0])),
  1122                                origOptions,
  1123                                aptCL,
  1124                                providedFactory,
  1125                                productiveFactories,
  1126                                aggregateGenFiles);
  1128             /*
  1129              * If there aren't new source files, we shouldn't bother
  1130              *  running javac if there were errors.
  1132              * If there are new files, we should try running javac in
  1133              * case there were typing errors.
  1135              */
  1137             if (comp.errorCount() != 0 ||
  1138                 options.get("-Werror") != null && comp.warningCount() != 0)
  1139                 return EXIT_ERROR;
  1140         } catch (IOException ex) {
  1141             ioMessage(ex);
  1142             return EXIT_SYSERR;
  1143         } catch (OutOfMemoryError ex) {
  1144             resourceMessage(ex);
  1145             return EXIT_SYSERR;
  1146         } catch (StackOverflowError ex) {
  1147             resourceMessage(ex);
  1148             return EXIT_SYSERR;
  1149         } catch (FatalError ex) {
  1150             feMessage(ex);
  1151             return EXIT_SYSERR;
  1152         } catch (UsageMessageNeededException umne) {
  1153             help();
  1154             return EXIT_CMDERR; // will cause usage message to be printed
  1155         } catch (AnnotationProcessingError ex) {
  1156             apMessage(ex);
  1157             return EXIT_ABNORMAL;
  1158         } catch (sun.misc.ServiceConfigurationError sce) {
  1159             sceMessage(sce);
  1160             return EXIT_ABNORMAL;
  1161         } catch (Throwable ex) {
  1162             bugMessage(ex);
  1163             return EXIT_ABNORMAL;
  1164         } finally {
  1165             if (comp != null) {
  1166                 comp.close();
  1167                 genSourceFileNames.addAll(comp.getSourceFileNames());
  1168                 genClassFileNames.addAll(comp.getClassFileNames());
  1170             sourceFileNames = new java.util.LinkedList<String>();
  1171             classFileNames  = new java.util.LinkedList<String>();
  1173         return exitCode;
  1176     /** Print a message reporting an internal error.
  1177      */
  1178     void bugMessage(Throwable ex) {
  1179         Bark.printLines(out, getLocalizedString("msg.bug",
  1180                                                JavaCompiler.version()));
  1181         ex.printStackTrace(out);
  1184     /** Print a message reporting an fatal error.
  1185      */
  1186     void apMessage(AnnotationProcessingError ex) {
  1187         Bark.printLines(out, getLocalizedString("misc.Problem"));
  1188         ex.getCause().printStackTrace(out);
  1191     /** Print a message about sun.misc.Service problem.
  1192      */
  1193     void sceMessage(sun.misc.ServiceConfigurationError ex) {
  1194         Bark.printLines(out, getLocalizedString("misc.SunMiscService"));
  1195         ex.printStackTrace(out);
  1198     /** Print a message reporting an fatal error.
  1199      */
  1200     void feMessage(Throwable ex) {
  1201         Bark.printLines(out, ex.toString());
  1204     /** Print a message reporting an input/output error.
  1205      */
  1206     void ioMessage(Throwable ex) {
  1207         Bark.printLines(out, getLocalizedString("msg.io"));
  1208         ex.printStackTrace(out);
  1211     /** Print a message reporting an out-of-resources error.
  1212      */
  1213     void resourceMessage(Throwable ex) {
  1214         Bark.printLines(out, getLocalizedString("msg.resource"));
  1215         ex.printStackTrace(out);
  1218     /* ************************************************************************
  1219      * Internationalization
  1220      *************************************************************************/
  1222     /** Find a localized string in the resource bundle.
  1223      *  @param key     The key for the localized string.
  1224      */
  1225     private static String getLocalizedString(String key, Object... args) {
  1226         return getText(key, args);
  1229     private static final String javacRB =
  1230         "com.sun.tools.javac.resources.javac";
  1232     private static final String aptRB =
  1233         "com.sun.tools.apt.resources.apt";
  1235     private static ResourceBundle messageRBjavac;
  1236     private static ResourceBundle messageRBapt;
  1238     /** Initialize ResourceBundle.
  1239      */
  1240     private static void initResource() {
  1241         try {
  1242             messageRBapt   = ResourceBundle.getBundle(aptRB);
  1243             messageRBjavac = ResourceBundle.getBundle(javacRB);
  1244         } catch (MissingResourceException e) {
  1245             Error x = new FatalError("Fatal Error: Resource for apt or javac is missing");
  1246             x.initCause(e);
  1247             throw x;
  1251     /** Get and format message string from resource.
  1252      */
  1253     private static String getText(String key, Object... _args) {
  1254         String[] args = new String[_args.length];
  1255         for (int i=0; i<_args.length; i++) {
  1256             args[i] = "" + _args[i];
  1258         if (messageRBapt == null || messageRBjavac == null )
  1259             initResource();
  1260         try {
  1261             return MessageFormat.format(messageRBapt.getString("apt." + key),
  1262                                         (Object[]) args);
  1263         } catch (MissingResourceException e) {
  1264             try {
  1265                 return MessageFormat.format(messageRBjavac.getString("javac." + key),
  1266                                             (Object[]) args);
  1267             } catch (MissingResourceException f) {
  1268                 String msg = "apt or javac message file broken: key={0} "
  1269                     + "arguments={1}, {2}";
  1270                 return MessageFormat.format(msg, (Object[]) args);
  1275     // Borrowed from DocletInvoker
  1276     /**
  1277      * Utility method for converting a search path string to an array
  1278      * of directory and JAR file URLs.
  1280      * @param path the search path string
  1281      * @return the resulting array of directory and JAR file URLs
  1282      */
  1283     static URL[] pathToURLs(String path) {
  1284         StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
  1285         URL[] urls = new URL[st.countTokens()];
  1286         int count = 0;
  1287         while (st.hasMoreTokens()) {
  1288             URL url = fileToURL(new File(st.nextToken()));
  1289             if (url != null) {
  1290                 urls[count++] = url;
  1293         if (urls.length != count) {
  1294             URL[] tmp = new URL[count];
  1295             System.arraycopy(urls, 0, tmp, 0, count);
  1296             urls = tmp;
  1298         return urls;
  1301     /**
  1302      * Returns the directory or JAR file URL corresponding to the specified
  1303      * local file name.
  1305      * @param file the File object
  1306      * @return the resulting directory or JAR file URL, or null if unknown
  1307      */
  1308     static URL fileToURL(File file) {
  1309         String name;
  1310         try {
  1311             name = file.getCanonicalPath();
  1312         } catch (IOException e) {
  1313             name = file.getAbsolutePath();
  1315         name = name.replace(File.separatorChar, '/');
  1316         if (!name.startsWith("/")) {
  1317             name = "/" + name;
  1319         // If the file does not exist, then assume that it's a directory
  1320         if (!file.isFile()) {
  1321             name = name + "/";
  1323         try {
  1324             return new URL("file", "", name);
  1325         } catch (MalformedURLException e) {
  1326             throw new IllegalArgumentException("file");

mercurial