Save This Page
Home » openjdk-7 » com.sun.tools » javac » main » [javadoc | source]
    1   /*
    2    * Copyright (c) 1999, 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    */
   25   
   26   package com.sun.tools.javac.main;
   27   
   28   import java.io.File;
   29   import java.io.IOException;
   30   import java.io.PrintWriter;
   31   import java.net.URL;
   32   import java.security.DigestInputStream;
   33   import java.security.MessageDigest;
   34   import java.util.MissingResourceException;
   35   import javax.tools.JavaFileManager;
   36   import javax.tools.JavaFileObject;
   37   import javax.annotation.processing.Processor;
   38   
   39   import com.sun.tools.javac.code.Source;
   40   import com.sun.tools.javac.file.CacheFSInfo;
   41   import com.sun.tools.javac.file.JavacFileManager;
   42   import com.sun.tools.javac.jvm.Target;
   43   import com.sun.tools.javac.main.JavacOption.Option;
   44   import com.sun.tools.javac.main.RecognizedOptions.OptionHelper;
   45   import com.sun.tools.javac.util;
   46   import com.sun.tools.javac.processing.AnnotationProcessingError;
   47   
   48   import static com.sun.tools.javac.main.OptionName.*;
   49   
   50   /** This class provides a commandline interface to the GJC compiler.
   51    *
   52    *  <p><b>This is NOT part of any supported API.
   53    *  If you write code that depends on this, you do so at your own risk.
   54    *  This code and its internal interfaces are subject to change or
   55    *  deletion without notice.</b>
   56    */
   57   public class Main {
   58   
   59       /** The name of the compiler, for use in diagnostics.
   60        */
   61       String ownName;
   62   
   63       /** The writer to use for diagnostic output.
   64        */
   65       PrintWriter out;
   66   
   67       /**
   68        * If true, certain errors will cause an exception, such as command line
   69        * arg errors, or exceptions in user provided code.
   70        */
   71       boolean apiMode;
   72   
   73   
   74       /** Result codes.
   75        */
   76       static final int
   77           EXIT_OK = 0,        // Compilation completed with no errors.
   78           EXIT_ERROR = 1,     // Completed but reported errors.
   79           EXIT_CMDERR = 2,    // Bad command-line arguments
   80           EXIT_SYSERR = 3,    // System error or resource exhaustion.
   81           EXIT_ABNORMAL = 4;  // Compiler terminated abnormally
   82   
   83       private Option[] recognizedOptions = RecognizedOptions.getJavaCompilerOptions(new OptionHelper() {
   84   
   85           public void setOut(PrintWriter out) {
   86               Main.this.out = out;
   87           }
   88   
   89           public void error(String key, Object... args) {
   90               Main.this.error(key, args);
   91           }
   92   
   93           public void printVersion() {
   94               Log.printLines(out, getLocalizedString("version", ownName,  JavaCompiler.version()));
   95           }
   96   
   97           public void printFullVersion() {
   98               Log.printLines(out, getLocalizedString("fullVersion", ownName,  JavaCompiler.fullVersion()));
   99           }
  100   
  101           public void printHelp() {
  102               help();
  103           }
  104   
  105           public void printXhelp() {
  106               xhelp();
  107           }
  108   
  109           public void addFile(File f) {
  110               if (!filenames.contains(f))
  111                   filenames.append(f);
  112           }
  113   
  114           public void addClassName(String s) {
  115               classnames.append(s);
  116           }
  117   
  118       });
  119   
  120       /**
  121        * Construct a compiler instance.
  122        */
  123       public Main(String name) {
  124           this(name, new PrintWriter(System.err, true));
  125       }
  126   
  127       /**
  128        * Construct a compiler instance.
  129        */
  130       public Main(String name, PrintWriter out) {
  131           this.ownName = name;
  132           this.out = out;
  133       }
  134       /** A table of all options that's passed to the JavaCompiler constructor.  */
  135       private Options options = null;
  136   
  137       /** The list of source files to process
  138        */
  139       public ListBuffer<File> filenames = null; // XXX sb protected
  140   
  141       /** List of class files names passed on the command line
  142        */
  143       public ListBuffer<String> classnames = null; // XXX sb protected
  144   
  145       /** Print a string that explains usage.
  146        */
  147       void help() {
  148           Log.printLines(out, getLocalizedString("msg.usage.header", ownName));
  149           for (int i=0; i<recognizedOptions.length; i++) {
  150               recognizedOptions[i].help(out);
  151           }
  152           out.println();
  153       }
  154   
  155       /** Print a string that explains usage for X options.
  156        */
  157       void xhelp() {
  158           for (int i=0; i<recognizedOptions.length; i++) {
  159               recognizedOptions[i].xhelp(out);
  160           }
  161           out.println();
  162           Log.printLines(out, getLocalizedString("msg.usage.nonstandard.footer"));
  163       }
  164   
  165       /** Report a usage error.
  166        */
  167       void error(String key, Object... args) {
  168           if (apiMode) {
  169               String msg = getLocalizedString(key, args);
  170               throw new PropagatedException(new IllegalStateException(msg));
  171           }
  172           warning(key, args);
  173           Log.printLines(out, getLocalizedString("msg.usage", ownName));
  174       }
  175   
  176       /** Report a warning.
  177        */
  178       void warning(String key, Object... args) {
  179           Log.printLines(out, ownName + ": "
  180                          + getLocalizedString(key, args));
  181       }
  182   
  183       public Option getOption(String flag) {
  184           for (Option option : recognizedOptions) {
  185               if (option.matches(flag))
  186                   return option;
  187           }
  188           return null;
  189       }
  190   
  191       public void setOptions(Options options) {
  192           if (options == null)
  193               throw new NullPointerException();
  194           this.options = options;
  195       }
  196   
  197       public void setAPIMode(boolean apiMode) {
  198           this.apiMode = apiMode;
  199       }
  200   
  201       /** Process command line arguments: store all command line options
  202        *  in `options' table and return all source filenames.
  203        *  @param flags    The array of command line arguments.
  204        */
  205       public List<File> processArgs(String[] flags) { // XXX sb protected
  206           int ac = 0;
  207           while (ac < flags.length) {
  208               String flag = flags[ac];
  209               ac++;
  210   
  211               Option option = null;
  212   
  213               if (flag.length() > 0) {
  214                   // quick hack to speed up file processing:
  215                   // if the option does not begin with '-', there is no need to check
  216                   // most of the compiler options.
  217                   int firstOptionToCheck = flag.charAt(0) == '-' ? 0 : recognizedOptions.length-1;
  218                   for (int j=firstOptionToCheck; j<recognizedOptions.length; j++) {
  219                       if (recognizedOptions[j].matches(flag)) {
  220                           option = recognizedOptions[j];
  221                           break;
  222                       }
  223                   }
  224               }
  225   
  226               if (option == null) {
  227                   error("err.invalid.flag", flag);
  228                   return null;
  229               }
  230   
  231               if (option.hasArg()) {
  232                   if (ac == flags.length) {
  233                       error("err.req.arg", flag);
  234                       return null;
  235                   }
  236                   String operand = flags[ac];
  237                   ac++;
  238                   if (option.process(options, flag, operand))
  239                       return null;
  240               } else {
  241                   if (option.process(options, flag))
  242                       return null;
  243               }
  244           }
  245   
  246           if (!checkDirectory(D))
  247               return null;
  248           if (!checkDirectory(S))
  249               return null;
  250   
  251           String sourceString = options.get(SOURCE);
  252           Source source = (sourceString != null)
  253               ? Source.lookup(sourceString)
  254               : Source.DEFAULT;
  255           String targetString = options.get(TARGET);
  256           Target target = (targetString != null)
  257               ? Target.lookup(targetString)
  258               : Target.DEFAULT;
  259           // We don't check source/target consistency for CLDC, as J2ME
  260           // profiles are not aligned with J2SE targets; moreover, a
  261           // single CLDC target may have many profiles.  In addition,
  262           // this is needed for the continued functioning of the JSR14
  263           // prototype.
  264           if (Character.isDigit(target.name.charAt(0))) {
  265               if (target.compareTo(source.requiredTarget()) < 0) {
  266                   if (targetString != null) {
  267                       if (sourceString == null) {
  268                           warning("warn.target.default.source.conflict",
  269                                   targetString,
  270                                   source.requiredTarget().name);
  271                       } else {
  272                           warning("warn.source.target.conflict",
  273                                   sourceString,
  274                                   source.requiredTarget().name);
  275                       }
  276                       return null;
  277                   } else {
  278                       target = source.requiredTarget();
  279                       options.put("-target", target.name);
  280                   }
  281               } else {
  282                   if (targetString == null && !source.allowGenerics()) {
  283                       target = Target.JDK1_4;
  284                       options.put("-target", target.name);
  285                   }
  286               }
  287           }
  288   
  289           // handle this here so it works even if no other options given
  290           String showClass = options.get("showClass");
  291           if (showClass != null) {
  292               if (showClass.equals("showClass")) // no value given for option
  293                   showClass = "com.sun.tools.javac.Main";
  294               showClass(showClass);
  295           }
  296   
  297           return filenames.toList();
  298       }
  299       // where
  300           private boolean checkDirectory(OptionName optName) {
  301               String value = options.get(optName);
  302               if (value == null)
  303                   return true;
  304               File file = new File(value);
  305               if (!file.exists()) {
  306                   error("err.dir.not.found", value);
  307                   return false;
  308               }
  309               if (!file.isDirectory()) {
  310                   error("err.file.not.directory", value);
  311                   return false;
  312               }
  313               return true;
  314           }
  315   
  316       /** Programmatic interface for main function.
  317        * @param args    The command line parameters.
  318        */
  319       public int compile(String[] args) {
  320           Context context = new Context();
  321           JavacFileManager.preRegister(context); // can't create it until Log has been set up
  322           int result = compile(args, context);
  323           if (fileManager instanceof JavacFileManager) {
  324               // A fresh context was created above, so jfm must be a JavacFileManager
  325               ((JavacFileManager)fileManager).close();
  326           }
  327           return result;
  328       }
  329   
  330       public int compile(String[] args, Context context) {
  331           return compile(args, context, List.<JavaFileObject>nil(), null);
  332       }
  333   
  334       /** Programmatic interface for main function.
  335        * @param args    The command line parameters.
  336        */
  337       public int compile(String[] args,
  338                          Context context,
  339                          List<JavaFileObject> fileObjects,
  340                          Iterable<? extends Processor> processors)
  341       {
  342           if (options == null)
  343               options = Options.instance(context); // creates a new one
  344   
  345           filenames = new ListBuffer<File>();
  346           classnames = new ListBuffer<String>();
  347           JavaCompiler comp = null;
  348           /*
  349            * TODO: Logic below about what is an acceptable command line
  350            * should be updated to take annotation processing semantics
  351            * into account.
  352            */
  353           try {
  354               if (args.length == 0 && fileObjects.isEmpty()) {
  355                   help();
  356                   return EXIT_CMDERR;
  357               }
  358   
  359               List<File> files;
  360               try {
  361                   files = processArgs(CommandLine.parse(args));
  362                   if (files == null) {
  363                       // null signals an error in options, abort
  364                       return EXIT_CMDERR;
  365                   } else if (files.isEmpty() && fileObjects.isEmpty() && classnames.isEmpty()) {
  366                       // it is allowed to compile nothing if just asking for help or version info
  367                       if (options.isSet(HELP)
  368                           || options.isSet(X)
  369                           || options.isSet(VERSION)
  370                           || options.isSet(FULLVERSION))
  371                           return EXIT_OK;
  372                       if (JavaCompiler.explicitAnnotationProcessingRequested(options)) {
  373                           error("err.no.source.files.classes");
  374                       } else {
  375                           error("err.no.source.files");
  376                       }
  377                       return EXIT_CMDERR;
  378                   }
  379               } catch (java.io.FileNotFoundException e) {
  380                   Log.printLines(out, ownName + ": " +
  381                                  getLocalizedString("err.file.not.found",
  382                                                     e.getMessage()));
  383                   return EXIT_SYSERR;
  384               }
  385   
  386               boolean forceStdOut = options.isSet("stdout");
  387               if (forceStdOut) {
  388                   out.flush();
  389                   out = new PrintWriter(System.out, true);
  390               }
  391   
  392               context.put(Log.outKey, out);
  393   
  394               // allow System property in following line as a Mustang legacy
  395               boolean batchMode = (options.isUnset("nonBatchMode")
  396                           && System.getProperty("nonBatchMode") == null);
  397               if (batchMode)
  398                   CacheFSInfo.preRegister(context);
  399   
  400               fileManager = context.get(JavaFileManager.class);
  401   
  402               comp = JavaCompiler.instance(context);
  403               if (comp == null) return EXIT_SYSERR;
  404   
  405               Log log = Log.instance(context);
  406   
  407               if (!files.isEmpty()) {
  408                   // add filenames to fileObjects
  409                   comp = JavaCompiler.instance(context);
  410                   List<JavaFileObject> otherFiles = List.nil();
  411                   JavacFileManager dfm = (JavacFileManager)fileManager;
  412                   for (JavaFileObject fo : dfm.getJavaFileObjectsFromFiles(files))
  413                       otherFiles = otherFiles.prepend(fo);
  414                   for (JavaFileObject fo : otherFiles)
  415                       fileObjects = fileObjects.prepend(fo);
  416               }
  417               comp.compile(fileObjects,
  418                            classnames.toList(),
  419                            processors);
  420   
  421               if (log.expectDiagKeys != null) {
  422                   if (log.expectDiagKeys.isEmpty()) {
  423                       Log.printLines(log.noticeWriter, "all expected diagnostics found");
  424                       return EXIT_OK;
  425                   } else {
  426                       Log.printLines(log.noticeWriter, "expected diagnostic keys not found: " + log.expectDiagKeys);
  427                       return EXIT_ERROR;
  428                   }
  429               }
  430   
  431               if (comp.errorCount() != 0)
  432                   return EXIT_ERROR;
  433           } catch (IOException ex) {
  434               ioMessage(ex);
  435               return EXIT_SYSERR;
  436           } catch (OutOfMemoryError ex) {
  437               resourceMessage(ex);
  438               return EXIT_SYSERR;
  439           } catch (StackOverflowError ex) {
  440               resourceMessage(ex);
  441               return EXIT_SYSERR;
  442           } catch (FatalError ex) {
  443               feMessage(ex);
  444               return EXIT_SYSERR;
  445           } catch (AnnotationProcessingError ex) {
  446               if (apiMode)
  447                   throw new RuntimeException(ex.getCause());
  448               apMessage(ex);
  449               return EXIT_SYSERR;
  450           } catch (ClientCodeException ex) {
  451               // as specified by javax.tools.JavaCompiler#getTask
  452               // and javax.tools.JavaCompiler.CompilationTask#call
  453               throw new RuntimeException(ex.getCause());
  454           } catch (PropagatedException ex) {
  455               throw ex.getCause();
  456           } catch (Throwable ex) {
  457               // Nasty.  If we've already reported an error, compensate
  458               // for buggy compiler error recovery by swallowing thrown
  459               // exceptions.
  460               if (comp == null || comp.errorCount() == 0 ||
  461                   options == null || options.isSet("dev"))
  462                   bugMessage(ex);
  463               return EXIT_ABNORMAL;
  464           } finally {
  465               if (comp != null) {
  466                   try {
  467                       comp.close();
  468                   } catch (ClientCodeException ex) {
  469                       throw new RuntimeException(ex.getCause());
  470                   }
  471               }
  472               filenames = null;
  473               options = null;
  474           }
  475           return EXIT_OK;
  476       }
  477   
  478       /** Print a message reporting an internal error.
  479        */
  480       void bugMessage(Throwable ex) {
  481           Log.printLines(out, getLocalizedString("msg.bug",
  482                                                  JavaCompiler.version()));
  483           ex.printStackTrace(out);
  484       }
  485   
  486       /** Print a message reporting a fatal error.
  487        */
  488       void feMessage(Throwable ex) {
  489           Log.printLines(out, ex.getMessage());
  490           if (ex.getCause() != null && options.isSet("dev")) {
  491               ex.getCause().printStackTrace(out);
  492           }
  493       }
  494   
  495       /** Print a message reporting an input/output error.
  496        */
  497       void ioMessage(Throwable ex) {
  498           Log.printLines(out, getLocalizedString("msg.io"));
  499           ex.printStackTrace(out);
  500       }
  501   
  502       /** Print a message reporting an out-of-resources error.
  503        */
  504       void resourceMessage(Throwable ex) {
  505           Log.printLines(out, getLocalizedString("msg.resource"));
  506   //      System.out.println("(name buffer len = " + Name.names.length + " " + Name.nc);//DEBUG
  507           ex.printStackTrace(out);
  508       }
  509   
  510       /** Print a message reporting an uncaught exception from an
  511        * annotation processor.
  512        */
  513       void apMessage(AnnotationProcessingError ex) {
  514           Log.printLines(out,
  515                          getLocalizedString("msg.proc.annotation.uncaught.exception"));
  516           ex.getCause().printStackTrace(out);
  517       }
  518   
  519       /** Display the location and checksum of a class. */
  520       void showClass(String className) {
  521           out.println("javac: show class: " + className);
  522           URL url = getClass().getResource('/' + className.replace('.', '/') + ".class");
  523           if (url == null)
  524               out.println("  class not found");
  525           else {
  526               out.println("  " + url);
  527               try {
  528                   final String algorithm = "MD5";
  529                   byte[] digest;
  530                   MessageDigest md = MessageDigest.getInstance(algorithm);
  531                   DigestInputStream in = new DigestInputStream(url.openStream(), md);
  532                   try {
  533                       byte[] buf = new byte[8192];
  534                       int n;
  535                       do { n = in.read(buf); } while (n > 0);
  536                       digest = md.digest();
  537                   } finally {
  538                       in.close();
  539                   }
  540                   StringBuilder sb = new StringBuilder();
  541                   for (byte b: digest)
  542                       sb.append(String.format("%02x", b));
  543                   out.println("  " + algorithm + " checksum: " + sb);
  544               } catch (Exception e) {
  545                   out.println("  cannot compute digest: " + e);
  546               }
  547           }
  548       }
  549   
  550       private JavaFileManager fileManager;
  551   
  552       /* ************************************************************************
  553        * Internationalization
  554        *************************************************************************/
  555   
  556       /** Find a localized string in the resource bundle.
  557        *  @param key     The key for the localized string.
  558        */
  559       public static String getLocalizedString(String key, Object... args) { // FIXME sb private
  560           try {
  561               if (messages == null)
  562                   messages = new JavacMessages(javacBundleName);
  563               return messages.getLocalizedString("javac." + key, args);
  564           }
  565           catch (MissingResourceException e) {
  566               throw new Error("Fatal Error: Resource for javac is missing", e);
  567           }
  568       }
  569   
  570       public static void useRawMessages(boolean enable) {
  571           if (enable) {
  572               messages = new JavacMessages(javacBundleName) {
  573                       @Override
  574                       public String getLocalizedString(String key, Object... args) {
  575                           return key;
  576                       }
  577                   };
  578           } else {
  579               messages = new JavacMessages(javacBundleName);
  580           }
  581       }
  582   
  583       private static final String javacBundleName =
  584           "com.sun.tools.javac.resources.javac";
  585   
  586       private static JavacMessages messages;
  587   }

Save This Page
Home » openjdk-7 » com.sun.tools » javac » main » [javadoc | source]