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

Tue, 25 Oct 2011 10:48:05 -0700

author
jjg
date
Tue, 25 Oct 2011 10:48:05 -0700
changeset 1116
d830d28fc72e
parent 798
4868a36f6fd8
child 1136
ae361e7f435a
permissions
-rw-r--r--

7104039: refactor/cleanup javac Paths class
Reviewed-by: mcimadamore

     1 /*
     2  * Copyright (c) 2004, 2011, Oracle and/or its affiliates. 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.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.apt.main;
    28 import java.io.File;
    29 import java.io.FileWriter;
    30 import java.io.IOException;
    31 import java.io.PrintWriter;
    32 import java.text.MessageFormat;
    33 import java.util.ResourceBundle;
    34 import java.util.MissingResourceException;
    35 import java.util.StringTokenizer;
    36 import java.util.Map;
    37 import java.util.HashMap;
    38 import java.util.Collections;
    40 import java.net.URLClassLoader;
    41 import java.net.URL;
    42 import java.net.MalformedURLException;
    44 import javax.tools.JavaFileManager;
    45 import javax.tools.StandardLocation;
    47 import com.sun.tools.javac.file.JavacFileManager;
    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 import static com.sun.tools.javac.file.Locations.pathToURLs;
    61 /** This class provides a commandline interface to the apt build-time
    62  *  tool.
    63  *
    64  *  <p><b>This is NOT part of any supported API.
    65  *  If you write code that depends on this, you do so at your own
    66  *  risk.  This code and its internal interfaces are subject to change
    67  *  or deletion without notice.</b>
    68  */
    69 @SuppressWarnings("deprecation")
    70 public class Main {
    72     /** For testing: enter any options you want to be set implicitly
    73      *  here.
    74      */
    75     static String[] forcedOpts = {
    76         // Preserve parameter names from class files if the class was
    77         // compiled with debug enabled
    78         "-XDsave-parameter-names"
    79     };
    81     /** The name of the compiler, for use in diagnostics.
    82      */
    83     String ownName;
    85     /** The writer to use for diagnostic output.
    86      */
    87     PrintWriter out;
    90     /** Instantiated factory to use in lieu of discovery process.
    91      */
    92     AnnotationProcessorFactory providedFactory = null;
    94     /** Map representing original command-line arguments.
    95      */
    96     Map<String,String> origOptions = new HashMap<String, String>();
    98     /** Classloader to use for finding factories.
    99      */
   100     ClassLoader aptCL = null;
   102     /** Result codes.
   103      */
   104     static final int
   105         EXIT_OK = 0,        // Compilation completed with no errors.
   106         EXIT_ERROR = 1,     // Completed but reported errors.
   107         EXIT_CMDERR = 2,    // Bad command-line arguments
   108         EXIT_SYSERR = 3,    // System error or resource exhaustion.
   109         EXIT_ABNORMAL = 4;  // Compiler terminated abnormally
   111     /** This class represents an option recognized by the main program
   112      */
   113     private class Option {
   114         /** Whether or not the option is used only aptOnly.
   115          */
   116         boolean aptOnly = false;
   118         /** Option string.
   119          */
   120         String name;
   122         /** Documentation key for arguments.
   123          */
   124         String argsNameKey;
   126         /** Documentation key for description.
   127          */
   128         String descrKey;
   130         /** Suffix option (-foo=bar or -foo:bar)
   131          */
   132         boolean hasSuffix;
   134         Option(String name, String argsNameKey, String descrKey) {
   135             this.name = name;
   136             this.argsNameKey = argsNameKey;
   137             this.descrKey = descrKey;
   138             char lastChar = name.charAt(name.length()-1);
   139             hasSuffix = lastChar == ':' || lastChar == '=';
   140         }
   141         Option(String name, String descrKey) {
   142             this(name, null, descrKey);
   143         }
   145         public String toString() {
   146             return name;
   147         }
   149         /** Does this option take a (separate) operand?
   150          */
   151         boolean hasArg() {
   152             return argsNameKey != null && !hasSuffix;
   153         }
   155         /** Does argument string match option pattern?
   156          *  @param arg        The command line argument string.
   157          */
   158         boolean matches(String arg) {
   159             return hasSuffix ? arg.startsWith(name) : arg.equals(name);
   160         }
   162         /** For javac-only options, print nothing.
   163          */
   164         void help() {
   165         }
   167         String helpSynopsis() {
   168             return name +
   169                 (argsNameKey == null ? "" :
   170                  ((hasSuffix ? "" : " ") +
   171                   getLocalizedString(argsNameKey)));
   172         }
   174         /** Print a line of documentation describing this option, if non-standard.
   175          */
   176         void xhelp() {}
   178         /** Process the option (with arg). Return true if error detected.
   179          */
   180         boolean process(String option, String arg) {
   181             options.put(option, arg);
   182             return false;
   183         }
   185         /** Process the option (without arg). Return true if error detected.
   186          */
   187         boolean process(String option) {
   188             if (hasSuffix)
   189                 return process(name, option.substring(name.length()));
   190             else
   191                 return process(option, option);
   192         }
   193     };
   195     private class SharedOption extends Option {
   196         SharedOption(String name, String argsNameKey, String descrKey) {
   197             super(name, argsNameKey, descrKey);
   198         }
   200         SharedOption(String name, String descrKey) {
   201             super(name, descrKey);
   202         }
   204         void help() {
   205             String s = "  " + helpSynopsis();
   206             out.print(s);
   207             for (int j = s.length(); j < 29; j++) out.print(" ");
   208             Bark.printLines(out, getLocalizedString(descrKey));
   209         }
   211     }
   213     private class AptOption extends Option {
   214         AptOption(String name, String argsNameKey, String descrKey) {
   215             super(name, argsNameKey, descrKey);
   216             aptOnly = true;
   217         }
   219         AptOption(String name, String descrKey) {
   220             super(name, descrKey);
   221             aptOnly = true;
   222         }
   224         /** Print a line of documentation describing this option, if standard.
   225          */
   226         void help() {
   227             String s = "  " + helpSynopsis();
   228             out.print(s);
   229             for (int j = s.length(); j < 29; j++) out.print(" ");
   230             Bark.printLines(out, getLocalizedString(descrKey));
   231         }
   233     }
   235     /** A nonstandard or extended (-X) option
   236      */
   237     private class XOption extends Option {
   238         XOption(String name, String argsNameKey, String descrKey) {
   239             super(name, argsNameKey, descrKey);
   240         }
   241         XOption(String name, String descrKey) {
   242             this(name, null, descrKey);
   243         }
   244         void help() {}
   245         void xhelp() {}
   246     };
   248     /** A nonstandard or extended (-X) option
   249      */
   250     private class AptXOption extends Option {
   251         AptXOption(String name, String argsNameKey, String descrKey) {
   252             super(name, argsNameKey, descrKey);
   253             aptOnly = true;
   254         }
   255         AptXOption(String name, String descrKey) {
   256             this(name, null, descrKey);
   257         }
   258         void xhelp() {
   259             String s = "  " + helpSynopsis();
   260             out.print(s);
   261             for (int j = s.length(); j < 29; j++) out.print(" ");
   262             Log.printLines(out, getLocalizedString(descrKey));
   263         }
   264     };
   266     /** A hidden (implementor) option
   267      */
   268     private class HiddenOption extends Option {
   269         HiddenOption(String name) {
   270             super(name, null, null);
   271         }
   272         HiddenOption(String name, String argsNameKey) {
   273             super(name, argsNameKey, null);
   274         }
   275         void help() {}
   276         void xhelp() {}
   277     };
   279     private class AptHiddenOption extends HiddenOption {
   280         AptHiddenOption(String name) {
   281             super(name);
   282             aptOnly = true;
   283         }
   284         AptHiddenOption(String name, String argsNameKey) {
   285             super(name, argsNameKey);
   286             aptOnly = true;
   287         }
   288     }
   290     private Option[] recognizedOptions = {
   291         new Option("-g",                                        "opt.g"),
   292         new Option("-g:none",                                   "opt.g.none") {
   293             boolean process(String option) {
   294                 options.put("-g:", "none");
   295                 return false;
   296             }
   297         },
   299         new Option("-g:{lines,vars,source}",                    "opt.g.lines.vars.source") {
   300             boolean matches(String s) {
   301                 return s.startsWith("-g:");
   302             }
   303             boolean process(String option) {
   304                 String suboptions = option.substring(3);
   305                 options.put("-g:", suboptions);
   306                 // enter all the -g suboptions as "-g:suboption"
   307                 for (StringTokenizer t = new StringTokenizer(suboptions, ","); t.hasMoreTokens(); ) {
   308                     String tok = t.nextToken();
   309                     String opt = "-g:" + tok;
   310                     options.put(opt, opt);
   311                 }
   312                 return false;
   313             }
   314         },
   316         new XOption("-Xlint",                                   "opt.Xlint"),
   317         new XOption("-Xlint:{"
   318                     + "all,"
   319                     + "cast,deprecation,divzero,empty,unchecked,fallthrough,path,serial,finally,overrides,"
   320                     + "-cast,-deprecation,-divzero,-empty,-unchecked,-fallthrough,-path,-serial,-finally,-overrides,"
   321                     + "none}",
   322                                                                 "opt.Xlint.suboptlist") {
   323             boolean matches(String s) {
   324                 return s.startsWith("-Xlint:");
   325             }
   326             boolean process(String option) {
   327                 String suboptions = option.substring(7);
   328                 options.put("-Xlint:", suboptions);
   329                 // enter all the -Xlint suboptions as "-Xlint:suboption"
   330                 for (StringTokenizer t = new StringTokenizer(suboptions, ","); t.hasMoreTokens(); ) {
   331                     String tok = t.nextToken();
   332                     String opt = "-Xlint:" + tok;
   333                     options.put(opt, opt);
   334                 }
   335                 return false;
   336             }
   337         },
   339         new Option("-nowarn",                                   "opt.nowarn"),
   340         new Option("-verbose",                                  "opt.verbose"),
   342         // -deprecation is retained for command-line backward compatibility
   343         new Option("-deprecation",                              "opt.deprecation") {
   344                 boolean process(String option) {
   345                     options.put("-Xlint:deprecation", option);
   346                     return false;
   347                 }
   348             },
   350         new SharedOption("-classpath",     "opt.arg.path",      "opt.classpath"),
   351         new SharedOption("-cp",            "opt.arg.path",      "opt.classpath") {
   352             boolean process(String option, String arg) {
   353                 return super.process("-classpath", arg);
   354             }
   355         },
   356         new Option("-sourcepath",          "opt.arg.path",      "opt.sourcepath"),
   357         new Option("-bootclasspath",       "opt.arg.path",      "opt.bootclasspath") {
   358             boolean process(String option, String arg) {
   359                 options.remove("-Xbootclasspath/p:");
   360                 options.remove("-Xbootclasspath/a:");
   361                 return super.process(option, arg);
   362             }
   363         },
   364         new XOption("-Xbootclasspath/p:",  "opt.arg.path", "opt.Xbootclasspath.p"),
   365         new XOption("-Xbootclasspath/a:",  "opt.arg.path", "opt.Xbootclasspath.a"),
   366         new XOption("-Xbootclasspath:",    "opt.arg.path", "opt.bootclasspath") {
   367             boolean process(String option, String arg) {
   368                 options.remove("-Xbootclasspath/p:");
   369                 options.remove("-Xbootclasspath/a:");
   370                 return super.process("-bootclasspath", arg);
   371             }
   372         },
   373         new Option("-extdirs",             "opt.arg.dirs",      "opt.extdirs"),
   374         new XOption("-Djava.ext.dirs=",    "opt.arg.dirs",      "opt.extdirs") {
   375             boolean process(String option, String arg) {
   376                 return super.process("-extdirs", arg);
   377             }
   378         },
   379         new Option("-endorseddirs",        "opt.arg.dirs",      "opt.endorseddirs"),
   380         new XOption("-Djava.endorsed.dirs=","opt.arg.dirs",     "opt.endorseddirs") {
   381             boolean process(String option, String arg) {
   382                 return super.process("-endorseddirs", arg);
   383             }
   384         },
   385         new Option("-proc:{none, only}",                        "opt.proc.none.only") {
   386             public boolean matches(String s) {
   387                 return s.equals("-proc:none") || s.equals("-proc:only");
   388             }
   389         },
   390         new Option("-processor",        "opt.arg.class",        "opt.processor"),
   391         new Option("-processorpath",    "opt.arg.path",         "opt.processorpath"),
   393         new SharedOption("-d",          "opt.arg.path", "opt.d"),
   394         new SharedOption("-s",          "opt.arg.path", "opt.s"),
   395         new Option("-encoding",         "opt.arg.encoding",     "opt.encoding"),
   396         new SharedOption("-source",             "opt.arg.release",      "opt.source") {
   397             boolean process(String option, String operand) {
   398                 Source source = Source.lookup(operand);
   399                 if (source == null) {
   400                     error("err.invalid.source", operand);
   401                     return true;
   402                 } else if (source.compareTo(Source.JDK1_5) > 0) {
   403                     error("err.unsupported.source.version", operand);
   404                     return true;
   405                 }
   406                 return super.process(option, operand);
   407             }
   408         },
   409         new Option("-target",           "opt.arg.release",      "opt.target") {
   410             boolean process(String option, String operand) {
   411                 Target target = Target.lookup(operand);
   412                 if (target == null) {
   413                     error("err.invalid.target", operand);
   414                     return true;
   415                 } else if (target.compareTo(Target.JDK1_5) > 0) {
   416                     error("err.unsupported.target.version", operand);
   417                     return true;
   418                 }
   419                 return super.process(option, operand);
   420             }
   421         },
   422         new AptOption("-version",               "opt.version") {
   423             boolean process(String option) {
   424                 Bark.printLines(out, ownName + " " + AptJavaCompiler.version());
   425                 return super.process(option);
   426             }
   427         },
   428         new HiddenOption("-fullversion"),
   429         new AptOption("-help",                                  "opt.help") {
   430             boolean process(String option) {
   431                 Main.this.help();
   432                 return super.process(option);
   433             }
   434         },
   435         new SharedOption("-X",                                  "opt.X") {
   436             boolean process(String option) {
   437                 Main.this.xhelp();
   438                 return super.process(option);
   439             }
   440         },
   442         // This option exists only for the purpose of documenting itself.
   443         // It's actually implemented by the launcher.
   444         new AptOption("-J",             "opt.arg.flag",         "opt.J") {
   445             String helpSynopsis() {
   446                 hasSuffix = true;
   447                 return super.helpSynopsis();
   448             }
   449             boolean process(String option) {
   450                 throw new AssertionError
   451                     ("the -J flag should be caught by the launcher.");
   452             }
   453         },
   456         new SharedOption("-A",          "opt.proc.flag",        "opt.A") {
   457                 String helpSynopsis() {
   458                     hasSuffix = true;
   459                     return super.helpSynopsis();
   460                 }
   462                 boolean matches(String arg) {
   463                     return arg.startsWith("-A");
   464                 }
   466                 boolean hasArg() {
   467                     return false;
   468                 }
   470                 boolean process(String option) {
   471                     return process(option, option);
   472                 }
   473             },
   475         new AptOption("-nocompile",     "opt.nocompile"),
   477         new AptOption("-print",         "opt.print"),
   479         new AptOption("-factorypath", "opt.arg.path", "opt.factorypath"),
   481         new AptOption("-factory",     "opt.arg.class", "opt.factory"),
   483         new AptXOption("-XListAnnotationTypes", "opt.XListAnnotationTypes"),
   485         new AptXOption("-XListDeclarations",    "opt.XListDeclarations"),
   487         new AptXOption("-XPrintAptRounds",      "opt.XPrintAptRounds"),
   489         new AptXOption("-XPrintFactoryInfo",    "opt.XPrintFactoryInfo"),
   491         /*
   492          * Option to treat both classes and source files as
   493          * declarations that can be given on the command line and
   494          * processed as the result of an apt round.
   495          */
   496         new AptXOption("-XclassesAsDecls", "opt.XClassesAsDecls"),
   498         // new Option("-moreinfo",                                      "opt.moreinfo") {
   499         new HiddenOption("-moreinfo") {
   500             boolean process(String option) {
   501                 Type.moreInfo = true;
   502                 return super.process(option);
   503             }
   504         },
   506         // treat warnings as errors
   507         new HiddenOption("-Werror"),
   509         // use complex inference from context in the position of a method call argument
   510         new HiddenOption("-complexinference"),
   512         // prompt after each error
   513         // new Option("-prompt",                                        "opt.prompt"),
   514         new HiddenOption("-prompt"),
   516         // dump stack on error
   517         new HiddenOption("-doe"),
   519         // display warnings for generic unchecked and unsafe operations
   520         new HiddenOption("-warnunchecked") {
   521             boolean process(String option) {
   522                 options.put("-Xlint:unchecked", option);
   523                 return false;
   524             }
   525         },
   527         new HiddenOption("-Xswitchcheck") {
   528             boolean process(String option) {
   529                 options.put("-Xlint:switchcheck", option);
   530                 return false;
   531             }
   532         },
   534         // generate trace output for subtyping operations
   535         new HiddenOption("-debugsubtyping"),
   537         new XOption("-Xmaxerrs",        "opt.arg.number",       "opt.maxerrs"),
   538         new XOption("-Xmaxwarns",       "opt.arg.number",       "opt.maxwarns"),
   539         new XOption("-Xstdout",         "opt.arg.file",         "opt.Xstdout") {
   540             boolean process(String option, String arg) {
   541                 try {
   542                     out = new PrintWriter(new FileWriter(arg), true);
   543                 } catch (java.io.IOException e) {
   544                     error("err.error.writing.file", arg, e);
   545                     return true;
   546                 }
   547                 return super.process(option, arg);
   548             }
   549         },
   551         new XOption("-Xprint",                                  "opt.print"),
   553         new XOption("-XprintRounds",                            "opt.printRounds"),
   555         new XOption("-XprintProcessorInfo",                     "opt.printProcessorInfo"),
   558         /* -O is a no-op, accepted for backward compatibility. */
   559         new HiddenOption("-O"),
   561         /* -Xjcov produces tables to support the code coverage tool jcov. */
   562         new HiddenOption("-Xjcov"),
   564         /* This is a back door to the compiler's option table.
   565          * -Dx=y sets the option x to the value y.
   566          * -Dx sets the option x to the value x.
   567          */
   568         new HiddenOption("-XD") {
   569             String s;
   570             boolean matches(String s) {
   571                 this.s = s;
   572                 return s.startsWith(name);
   573             }
   574             boolean process(String option) {
   575                 s = s.substring(name.length());
   576                 int eq = s.indexOf('=');
   577                 String key = (eq < 0) ? s : s.substring(0, eq);
   578                 String value = (eq < 0) ? s : s.substring(eq+1);
   579                 options.put(key, value);
   580                 return false;
   581             }
   582         },
   584         new HiddenOption("sourcefile") {
   585                 String s;
   586                 boolean matches(String s) {
   587                     this.s = s;
   588                     return s.endsWith(".java") ||
   589                         (options.get("-XclassesAsDecls") != null);
   590                 }
   591                 boolean process(String option) {
   592                     if (s.endsWith(".java")) {
   593                         if (!sourceFileNames.contains(s))
   594                             sourceFileNames.add(s);
   595                     } else if (options.get("-XclassesAsDecls") != null) {
   596                         classFileNames.add(s);
   597                     }
   598                     return false;
   599                 }
   600             },
   601     };
   603     /**
   604      * Construct a compiler instance.
   605      */
   606     public Main(String name) {
   607         this(name, new PrintWriter(System.err, true));
   608     }
   610     /**
   611      * Construct a compiler instance.
   612      */
   613     public Main(String name, PrintWriter out) {
   614         this.ownName = name;
   615         this.out = out;
   616     }
   618     /** A table of all options that's passed to the JavaCompiler constructor.  */
   619     private Options options = null;
   621     /** The list of source files to process
   622      */
   623     java.util.List<String> sourceFileNames = new java.util.LinkedList<String>();
   625     /** The list of class files to process
   626      */
   627     java.util.List<String> classFileNames = new java.util.LinkedList<String>();
   629     /** List of top level names of generated source files from most recent apt round.
   630      */
   631     java.util.Set<String> genSourceFileNames = new java.util.LinkedHashSet<String>();
   633     /** List of names of generated class files from most recent apt round.
   634      */
   635     java.util.Set<String> genClassFileNames  = new java.util.LinkedHashSet<String>();
   637     /**
   638      * List of all the generated source file names across all apt rounds.
   639      */
   640     java.util.Set<String> aggregateGenSourceFileNames = new java.util.LinkedHashSet<String>();
   642     /**
   643      * List of all the generated class file names across all apt rounds.
   644      */
   645     java.util.Set<String> aggregateGenClassFileNames  = new java.util.LinkedHashSet<String>();
   647     /**
   648      * List of all the generated file names across all apt rounds.
   649      */
   650     java.util.Set<java.io.File> aggregateGenFiles = new java.util.LinkedHashSet<java.io.File>();
   652     /**
   653      * Set of all factories that have provided a processor on some apt round.
   654      */
   655     java.util.Set<Class<? extends AnnotationProcessorFactory> > productiveFactories  =
   656         new java.util.LinkedHashSet<Class<? extends AnnotationProcessorFactory> >();
   660     /** Print a string that explains usage.
   661      */
   662     void help() {
   663         Bark.printLines(out, getLocalizedString("msg.usage.header", ownName));
   664         for (int i=0; i < recognizedOptions.length; i++) {
   665             recognizedOptions[i].help();
   666         }
   667         Bark.printLines(out, getLocalizedString("msg.usage.footer"));
   668         out.println();
   669     }
   671     /** Print a string that explains usage for X options.
   672      */
   673     void xhelp() {
   674         for (int i=0; i<recognizedOptions.length; i++) {
   675             recognizedOptions[i].xhelp();
   676         }
   677         out.println();
   678         Bark.printLines(out, getLocalizedString("msg.usage.nonstandard.footer"));
   679     }
   681     /** Report a usage error.
   682      */
   683     void error(String key, Object... args) {
   684         warning(key, args);
   685         help();
   686     }
   688     /** Report a warning.
   689      */
   690     void warning(String key, Object... args) {
   691         Bark.printLines(out, ownName + ": "
   692                        + getLocalizedString(key, args));
   693     }
   695     /** Process command line arguments: store all command line options
   696      *  in `options' table and return all source filenames.
   697      *  @param args    The array of command line arguments.
   698      */
   699     protected java.util.List<String> processArgs(String[] flags) {
   700         int ac = 0;
   701         while (ac < flags.length) {
   702             String flag = flags[ac];
   703             ac++;
   705             int j;
   706             for (j=0; j < recognizedOptions.length; j++)
   707                 if (recognizedOptions[j].matches(flag))
   708                     break;
   710             if (j == recognizedOptions.length) {
   711                 error("err.invalid.flag", flag);
   712                 return null;
   713             }
   715             Option option = recognizedOptions[j];
   716             if (option.hasArg()) {
   717                 if (ac == flags.length) {
   718                     error("err.req.arg", flag);
   719                     return null;
   720                 }
   721                 String operand = flags[ac];
   722                 ac++;
   723                 if (option.process(flag, operand))
   724                     return null;
   725             } else {
   726                 if (option.process(flag))
   727                     return null;
   728             }
   729         }
   731         String sourceString = options.get("-source");
   732         Source source = (sourceString != null)
   733             ? Source.lookup(sourceString)
   734             : Source.JDK1_5; // JDK 5 is the latest supported source version
   735         String targetString = options.get("-target");
   736         Target target = (targetString != null)
   737             ? Target.lookup(targetString)
   738             : Target.JDK1_5; // JDK 5 is the latest supported source version
   739         // We don't check source/target consistency for CLDC, as J2ME
   740         // profiles are not aligned with J2SE targets; moreover, a
   741         // single CLDC target may have many profiles.  In addition,
   742         // this is needed for the continued functioning of the JSR14
   743         // prototype.
   744         if (Character.isDigit(target.name.charAt(0)) &&
   745             target.compareTo(source.requiredTarget()) < 0) {
   746             if (targetString != null) {
   747                 if (sourceString == null) {
   748                     warning("warn.target.default.source.conflict",
   749                             targetString,
   750                             source.requiredTarget().name);
   751                 } else {
   752                     warning("warn.source.target.conflict",
   753                             sourceString,
   754                             source.requiredTarget().name);
   755                 }
   756                 return null;
   757             } else {
   758                 options.put("-target", source.requiredTarget().name);
   759             }
   760         }
   761         return sourceFileNames;
   762     }
   764     /** Programmatic interface for main function.
   765      * @param args    The command line parameters.
   766      */
   767     public int compile(String[] args, AnnotationProcessorFactory factory) {
   768         int returnCode = 0;
   769         providedFactory = factory;
   771         Context context = new Context();
   772         JavacFileManager.preRegister(context);
   773         options = Options.instance(context);
   774         Bark bark;
   776         /*
   777          * Process the command line options to create the intial
   778          * options data.  This processing is at least partially reused
   779          * by any recursive apt calls.
   780          */
   782         // For testing: assume all arguments in forcedOpts are
   783         // prefixed to command line arguments.
   784         processArgs(forcedOpts);
   786         /*
   787          * A run of apt only gets passed the most recently generated
   788          * files; the initial run of apt gets passed the files from
   789          * the command line.
   790          */
   792         java.util.List<String> origFilenames;
   793         try {
   794             // assign args the result of parse to capture results of
   795             // '@file' expansion
   796             origFilenames = processArgs((args=CommandLine.parse(args)));
   798             if (options.get("suppress-tool-api-removal-message") == null) {
   799                 Bark.printLines(out, getLocalizedString("misc.Deprecation"));
   800             }
   802             if (origFilenames == null) {
   803                 return EXIT_CMDERR;
   804             } else if (origFilenames.size() == 0) {
   805                 // it is allowed to compile nothing if just asking for help
   806                 if (options.get("-help") != null ||
   807                     options.get("-X") != null)
   808                     return EXIT_OK;
   809             }
   810         } catch (java.io.FileNotFoundException e) {
   811             Bark.printLines(out, ownName + ": " +
   812                            getLocalizedString("err.file.not.found",
   813                                               e.getMessage()));
   814             return EXIT_SYSERR;
   815         } catch (IOException ex) {
   816             ioMessage(ex);
   817             return EXIT_SYSERR;
   818         } catch (OutOfMemoryError ex) {
   819             resourceMessage(ex);
   820             return EXIT_SYSERR;
   821         } catch (StackOverflowError ex) {
   822             resourceMessage(ex);
   823             return EXIT_SYSERR;
   824         } catch (FatalError ex) {
   825             feMessage(ex);
   826             return EXIT_SYSERR;
   827         } catch (sun.misc.ServiceConfigurationError sce) {
   828             sceMessage(sce);
   829             return EXIT_ABNORMAL;
   830         } catch (Throwable ex) {
   831             bugMessage(ex);
   832             return EXIT_ABNORMAL;
   833         }
   836         boolean firstRound = true;
   837         boolean needSourcePath = false;
   838         boolean needClassPath  = false;
   839         boolean classesAsDecls = options.get("-XclassesAsDecls") != null;
   841         /*
   842          * Create augumented classpath and sourcepath values.
   843          *
   844          * If any of the prior apt rounds generated any new source
   845          * files, the n'th apt round (and any javac invocation) has the
   846          * source destination path ("-s path") as the last element of
   847          * the "-sourcepath" to the n'th call.
   848          *
   849          * If any of the prior apt rounds generated any new class files,
   850          * the n'th apt round (and any javac invocation) has the class
   851          * destination path ("-d path") as the last element of the
   852          * "-classpath" to the n'th call.
   853          */
   854         String augmentedSourcePath = "";
   855         String augmentedClassPath = "";
   856         String baseClassPath = "";
   858         try {
   859             /*
   860              * Record original options for future annotation processor
   861              * invocations.
   862              */
   863             origOptions = new HashMap<String, String>(options.size());
   864             for(String s: options.keySet()) {
   865                 String value;
   866                 if (s.equals(value = options.get(s)))
   867                     origOptions.put(s, (String)null);
   868                 else
   869                     origOptions.put(s, value);
   870             }
   871             origOptions = Collections.unmodifiableMap(origOptions);
   873             JavacFileManager fm = (JavacFileManager) context.get(JavaFileManager.class);
   874             {
   875                 // Note: it might be necessary to check for an empty
   876                 // component ("") of the source path or class path
   878                 String sourceDest = options.get("-s");
   879                 if (fm.hasLocation(StandardLocation.SOURCE_PATH)) {
   880                     for(File f: fm.getLocation(StandardLocation.SOURCE_PATH))
   881                         augmentedSourcePath += (f + File.pathSeparator);
   882                     augmentedSourcePath += (sourceDest == null)?".":sourceDest;
   883                 } else {
   884                     augmentedSourcePath = ".";
   886                     if (sourceDest != null)
   887                         augmentedSourcePath += (File.pathSeparator + sourceDest);
   888                 }
   890                 String classDest = options.get("-d");
   891                 if (fm.hasLocation(StandardLocation.CLASS_PATH)) {
   892                     for(File f: fm.getLocation(StandardLocation.CLASS_PATH))
   893                         baseClassPath += (f + File.pathSeparator);
   894                     // put baseClassPath into map to handle any
   895                     // value needed for the classloader
   896                     options.put("-classpath", baseClassPath);
   898                     augmentedClassPath = baseClassPath + ((classDest == null)?".":classDest);
   899                 } else {
   900                     baseClassPath = ".";
   901                     if (classDest != null)
   902                         augmentedClassPath = baseClassPath + (File.pathSeparator + classDest);
   903                 }
   904                 assert options.get("-classpath") != null;
   905             }
   907             /*
   908              * Create base and augmented class loaders
   909              */
   910             ClassLoader augmentedAptCL = null;
   911             {
   912             /*
   913              * Use a url class loader to look for classes on the
   914              * user-specified class path. Prepend computed bootclass
   915              * path, which includes extdirs, to the URLClassLoader apt
   916              * uses.
   917              */
   918                 String aptclasspath = "";
   919                 String bcp = "";
   920                 Iterable<? extends File> bootclasspath = fm.getLocation(StandardLocation.PLATFORM_CLASS_PATH);
   922                 if (bootclasspath != null) {
   923                     for(File f: bootclasspath)
   924                         bcp += (f + File.pathSeparator);
   925                 }
   927                 // If the factory path is set, use that path
   928                 if (providedFactory == null)
   929                     aptclasspath = options.get("-factorypath");
   930                 if (aptclasspath == null)
   931                     aptclasspath = options.get("-classpath");
   933                 assert aptclasspath != null;
   934                 aptclasspath = (bcp + aptclasspath);
   935                 aptCL = new URLClassLoader(pathToURLs(aptclasspath));
   937                 if (providedFactory == null &&
   938                     options.get("-factorypath") != null) // same CL even if new class files written
   939                     augmentedAptCL = aptCL;
   940                 else {
   941                     // Create class loader in case new class files are
   942                     // written
   943                     augmentedAptCL = new URLClassLoader(pathToURLs(augmentedClassPath.
   944                                                                    substring(baseClassPath.length())),
   945                                                         aptCL);
   946                 }
   947             }
   949             int round = 0; // For -XPrintAptRounds
   950             do {
   951                 round++;
   953                 Context newContext = new Context();
   954                 Options newOptions = Options.instance(newContext); // creates a new context
   955                 newOptions.putAll(options);
   957                 // populate with old options... don't bother reparsing command line, etc.
   959                 // if genSource files, must add destination to source path
   960                 if (genSourceFileNames.size() > 0 && !firstRound) {
   961                     newOptions.put("-sourcepath", augmentedSourcePath);
   962                     needSourcePath = true;
   963                 }
   964                 aggregateGenSourceFileNames.addAll(genSourceFileNames);
   965                 sourceFileNames.addAll(genSourceFileNames);
   966                 genSourceFileNames.clear();
   968                 // Don't really need to track this; just have to add -d
   969                 // "foo" to class path if any class files are generated
   970                 if (genClassFileNames.size() > 0) {
   971                     newOptions.put("-classpath", augmentedClassPath);
   972                     aptCL = augmentedAptCL;
   973                     needClassPath = true;
   974                 }
   975                 aggregateGenClassFileNames.addAll(genClassFileNames);
   976                 classFileNames.addAll(genClassFileNames);
   977                 genClassFileNames.clear();
   979                 options = newOptions;
   981                 if (options.get("-XPrintAptRounds") != null) {
   982                     out.println("apt Round : " + round);
   983                     out.println("filenames: " + sourceFileNames);
   984                     if (classesAsDecls)
   985                         out.println("classnames: " + classFileNames);
   986                     out.println("options: " + options);
   987                 }
   989                 returnCode = compile(args, newContext);
   990                 firstRound = false;
   992                 // Check for reported errors before continuing
   993                 bark = Bark.instance(newContext);
   994             } while(((genSourceFileNames.size() != 0 ) ||
   995                      (classesAsDecls && genClassFileNames.size() != 0)) &&
   996                     bark.nerrors == 0);
   997         } catch (UsageMessageNeededException umne) {
   998             help();
   999             return EXIT_CMDERR; // will cause usage message to be printed
  1002         /*
  1003          * Do not compile if a processor has reported an error or if
  1004          * there are no source files to process.  A more sophisticated
  1005          * test would also fail for syntax errors caught by javac.
  1006          */
  1007         if (options.get("-nocompile") == null &&
  1008             options.get("-print")     == null &&
  1009             bark.nerrors == 0 &&
  1010             (origFilenames.size() > 0 || aggregateGenSourceFileNames.size() > 0 )) {
  1011             /*
  1012              * Need to create new argument string for calling javac:
  1013              * 1. apt specific arguments (e.g. -factory) must be stripped out
  1014              * 2. proper settings for sourcepath and classpath must be used
  1015              * 3. generated class names must be added
  1016              * 4. class file names as declarations must be removed
  1017              */
  1019             int newArgsLength = args.length +
  1020                 (needSourcePath?1:0) +
  1021                 (needClassPath?1:0) +
  1022                 aggregateGenSourceFileNames.size();
  1024             // Null out apt-specific options and don't copy over into
  1025             // newArgs. This loop should be a lot faster; the options
  1026             // array should be replaced with a better data structure
  1027             // which includes a map from strings to options.
  1028             //
  1029             // If treating classes as declarations, must strip out
  1030             // class names from the javac argument list
  1031             argLoop:
  1032             for(int i = 0; i < args.length; i++) {
  1033                 int matchPosition = -1;
  1035                 // "-A" by itself is recognized by apt but not javac
  1036                 if (args[i] != null && args[i].equals("-A")) {
  1037                     newArgsLength--;
  1038                     args[i] = null;
  1039                     continue argLoop;
  1040                 } else {
  1041                     optionLoop:
  1042                     for(int j = 0; j < recognizedOptions.length; j++) {
  1043                         if (args[i] != null && recognizedOptions[j].matches(args[i])) {
  1044                             matchPosition = j;
  1045                             break optionLoop;
  1049                     if (matchPosition != -1) {
  1050                         Option op = recognizedOptions[matchPosition];
  1051                         if (op.aptOnly) {
  1052                             newArgsLength--;
  1053                             args[i] = null;
  1054                             if (op.hasArg()) {
  1055                                 newArgsLength--;
  1056                                 args[i+1] = null;
  1058                         } else {
  1059                             if (op.hasArg()) { // skip over next string
  1060                                 i++;
  1061                                 continue argLoop;
  1064                             if ((options.get("-XclassesAsDecls") != null) &&
  1065                                 (matchPosition == (recognizedOptions.length-1)) ){
  1066                                 // Remove class file names from
  1067                                 // consideration by javac.
  1068                                 if (! args[i].endsWith(".java")) {
  1069                                     newArgsLength--;
  1070                                     args[i] = null;
  1078             String newArgs[] = new String[newArgsLength];
  1080             int j = 0;
  1081             for(int i=0; i < args.length; i++) {
  1082                 if (args[i] != null)
  1083                     newArgs[j++] = args[i];
  1086             if (needClassPath)
  1087                 newArgs[j++] = "-XD-classpath=" + augmentedClassPath;
  1089             if (needSourcePath) {
  1090                 newArgs[j++] = "-XD-sourcepath=" + augmentedSourcePath;
  1092                 for(String s: aggregateGenSourceFileNames)
  1093                     newArgs[j++] = s;
  1096             returnCode = com.sun.tools.javac.Main.compile(newArgs);
  1099         return returnCode;
  1102     /** Programmatic interface for main function.
  1103      * @param args    The command line parameters.
  1104      */
  1105     int compile(String[] args, Context context) {
  1106         boolean assertionsEnabled = false;
  1107         assert assertionsEnabled = true;
  1108         if (!assertionsEnabled) {
  1109             // Bark.printLines(out, "fatal error: assertions must be enabled when running javac");
  1110             // return EXIT_ABNORMAL;
  1112         int exitCode = EXIT_OK;
  1114         AptJavaCompiler comp = null;
  1115         try {
  1116             context.put(Bark.outKey, out);
  1118             comp = AptJavaCompiler.instance(context);
  1119             if (comp == null)
  1120                 return EXIT_SYSERR;
  1122             java.util.List<String> nameList = new java.util.LinkedList<String>();
  1123             nameList.addAll(sourceFileNames);
  1124             if (options.get("-XclassesAsDecls") != null)
  1125                 nameList.addAll(classFileNames);
  1127             List<Symbol.ClassSymbol> cs
  1128                 = comp.compile(List.from(nameList.toArray(new String[0])),
  1129                                origOptions,
  1130                                aptCL,
  1131                                providedFactory,
  1132                                productiveFactories,
  1133                                aggregateGenFiles);
  1135             /*
  1136              * If there aren't new source files, we shouldn't bother
  1137              *  running javac if there were errors.
  1139              * If there are new files, we should try running javac in
  1140              * case there were typing errors.
  1142              */
  1144             if (comp.errorCount() != 0 ||
  1145                 options.get("-Werror") != null && comp.warningCount() != 0)
  1146                 return EXIT_ERROR;
  1147         } catch (IOException ex) {
  1148             ioMessage(ex);
  1149             return EXIT_SYSERR;
  1150         } catch (OutOfMemoryError ex) {
  1151             resourceMessage(ex);
  1152             return EXIT_SYSERR;
  1153         } catch (StackOverflowError ex) {
  1154             resourceMessage(ex);
  1155             return EXIT_SYSERR;
  1156         } catch (FatalError ex) {
  1157             feMessage(ex);
  1158             return EXIT_SYSERR;
  1159         } catch (UsageMessageNeededException umne) {
  1160             help();
  1161             return EXIT_CMDERR; // will cause usage message to be printed
  1162         } catch (AnnotationProcessingError ex) {
  1163             apMessage(ex);
  1164             return EXIT_ABNORMAL;
  1165         } catch (sun.misc.ServiceConfigurationError sce) {
  1166             sceMessage(sce);
  1167             return EXIT_ABNORMAL;
  1168         } catch (Throwable ex) {
  1169             bugMessage(ex);
  1170             return EXIT_ABNORMAL;
  1171         } finally {
  1172             if (comp != null) {
  1173                 comp.close();
  1174                 genSourceFileNames.addAll(comp.getSourceFileNames());
  1175                 genClassFileNames.addAll(comp.getClassFileNames());
  1177             sourceFileNames = new java.util.LinkedList<String>();
  1178             classFileNames  = new java.util.LinkedList<String>();
  1180         return exitCode;
  1183     /** Print a message reporting an internal error.
  1184      */
  1185     void bugMessage(Throwable ex) {
  1186         Bark.printLines(out, getLocalizedString("msg.bug",
  1187                                                AptJavaCompiler.version()));
  1188         ex.printStackTrace(out);
  1191     /** Print a message reporting an fatal error.
  1192      */
  1193     void apMessage(AnnotationProcessingError ex) {
  1194         Bark.printLines(out, getLocalizedString("misc.Problem"));
  1195         ex.getCause().printStackTrace(out);
  1198     /** Print a message about sun.misc.Service problem.
  1199      */
  1200     void sceMessage(sun.misc.ServiceConfigurationError ex) {
  1201         Bark.printLines(out, getLocalizedString("misc.SunMiscService"));
  1202         ex.printStackTrace(out);
  1205     /** Print a message reporting an fatal error.
  1206      */
  1207     void feMessage(Throwable ex) {
  1208         Bark.printLines(out, ex.toString());
  1211     /** Print a message reporting an input/output error.
  1212      */
  1213     void ioMessage(Throwable ex) {
  1214         Bark.printLines(out, getLocalizedString("msg.io"));
  1215         ex.printStackTrace(out);
  1218     /** Print a message reporting an out-of-resources error.
  1219      */
  1220     void resourceMessage(Throwable ex) {
  1221         Bark.printLines(out, getLocalizedString("msg.resource"));
  1222         ex.printStackTrace(out);
  1225     /* ************************************************************************
  1226      * Internationalization
  1227      *************************************************************************/
  1229     /** Find a localized string in the resource bundle.
  1230      *  @param key     The key for the localized string.
  1231      */
  1232     private static String getLocalizedString(String key, Object... args) {
  1233         return getText(key, args);
  1236     private static final String javacRB =
  1237         "com.sun.tools.javac.resources.javac";
  1239     private static final String aptRB =
  1240         "com.sun.tools.apt.resources.apt";
  1242     private static ResourceBundle messageRBjavac;
  1243     private static ResourceBundle messageRBapt;
  1245     /** Initialize ResourceBundle.
  1246      */
  1247     private static void initResource() {
  1248         try {
  1249             messageRBapt   = ResourceBundle.getBundle(aptRB);
  1250             messageRBjavac = ResourceBundle.getBundle(javacRB);
  1251         } catch (MissingResourceException e) {
  1252             Error x = new FatalError("Fatal Error: Resource for apt or javac is missing");
  1253             x.initCause(e);
  1254             throw x;
  1258     /** Get and format message string from resource.
  1259      */
  1260     private static String getText(String key, Object... _args) {
  1261         String[] args = new String[_args.length];
  1262         for (int i=0; i<_args.length; i++) {
  1263             args[i] = "" + _args[i];
  1265         if (messageRBapt == null || messageRBjavac == null )
  1266             initResource();
  1267         try {
  1268             return MessageFormat.format(messageRBapt.getString("apt." + key),
  1269                                         (Object[]) args);
  1270         } catch (MissingResourceException e) {
  1271             try {
  1272                 return MessageFormat.format(messageRBjavac.getString("javac." + key),
  1273                                             (Object[]) args);
  1274             } catch (MissingResourceException f) {
  1275                 String msg = "apt or javac message file broken: key={0} "
  1276                     + "arguments={1}, {2}";
  1277                 return MessageFormat.format(msg, (Object[]) args);

mercurial