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

Mon, 16 Jun 2008 13:28:00 -0700

author
jjg
date
Mon, 16 Jun 2008 13:28:00 -0700
changeset 50
b9bcea8bbe24
parent 1
9a66ca7c79fa
child 54
eaf608c64fec
permissions
-rw-r--r--

6714364: refactor javac File handling code into new javac.file package
Reviewed-by: mcimadamore

     1 /*
     2  * Copyright 1999-2006 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.javac.main;
    28 import java.io.File;
    29 import java.io.IOException;
    30 import java.io.PrintWriter;
    31 import java.util.MissingResourceException;
    33 import com.sun.tools.javac.code.Source;
    34 import com.sun.tools.javac.file.JavacFileManager;
    35 import com.sun.tools.javac.jvm.Target;
    36 import com.sun.tools.javac.main.JavacOption.Option;
    37 import com.sun.tools.javac.main.RecognizedOptions.OptionHelper;
    38 import com.sun.tools.javac.util.*;
    39 import com.sun.tools.javac.processing.AnnotationProcessingError;
    40 import javax.tools.JavaFileManager;
    41 import javax.tools.JavaFileObject;
    42 import javax.annotation.processing.Processor;
    44 /** This class provides a commandline interface to the GJC compiler.
    45  *
    46  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
    47  *  you write code that depends on this, you do so at your own risk.
    48  *  This code and its internal interfaces are subject to change or
    49  *  deletion without notice.</b>
    50  */
    51 public class Main {
    53     /** The name of the compiler, for use in diagnostics.
    54      */
    55     String ownName;
    57     /** The writer to use for diagnostic output.
    58      */
    59     PrintWriter out;
    61     /**
    62      * If true, any command line arg errors will cause an exception.
    63      */
    64     boolean fatalErrors;
    66     /** Result codes.
    67      */
    68     static final int
    69         EXIT_OK = 0,        // Compilation completed with no errors.
    70         EXIT_ERROR = 1,     // Completed but reported errors.
    71         EXIT_CMDERR = 2,    // Bad command-line arguments
    72         EXIT_SYSERR = 3,    // System error or resource exhaustion.
    73         EXIT_ABNORMAL = 4;  // Compiler terminated abnormally
    75     private Option[] recognizedOptions = RecognizedOptions.getJavaCompilerOptions(new OptionHelper() {
    77         public void setOut(PrintWriter out) {
    78             Main.this.out = out;
    79         }
    81         public void error(String key, Object... args) {
    82             Main.this.error(key, args);
    83         }
    85         public void printVersion() {
    86             Log.printLines(out, getLocalizedString("version", ownName,  JavaCompiler.version()));
    87         }
    89         public void printFullVersion() {
    90             Log.printLines(out, getLocalizedString("fullVersion", ownName,  JavaCompiler.fullVersion()));
    91         }
    93         public void printHelp() {
    94             help();
    95         }
    97         public void printXhelp() {
    98             xhelp();
    99         }
   101         public void addFile(File f) {
   102             if (!filenames.contains(f))
   103                 filenames.append(f);
   104         }
   106         public void addClassName(String s) {
   107             classnames.append(s);
   108         }
   110     });
   112     /**
   113      * Construct a compiler instance.
   114      */
   115     public Main(String name) {
   116         this(name, new PrintWriter(System.err, true));
   117     }
   119     /**
   120      * Construct a compiler instance.
   121      */
   122     public Main(String name, PrintWriter out) {
   123         this.ownName = name;
   124         this.out = out;
   125     }
   126     /** A table of all options that's passed to the JavaCompiler constructor.  */
   127     private Options options = null;
   129     /** The list of source files to process
   130      */
   131     public ListBuffer<File> filenames = null; // XXX sb protected
   133     /** List of class files names passed on the command line
   134      */
   135     public ListBuffer<String> classnames = null; // XXX sb protected
   137     /** Print a string that explains usage.
   138      */
   139     void help() {
   140         Log.printLines(out, getLocalizedString("msg.usage.header", ownName));
   141         for (int i=0; i<recognizedOptions.length; i++) {
   142             recognizedOptions[i].help(out);
   143         }
   144         out.println();
   145     }
   147     /** Print a string that explains usage for X options.
   148      */
   149     void xhelp() {
   150         for (int i=0; i<recognizedOptions.length; i++) {
   151             recognizedOptions[i].xhelp(out);
   152         }
   153         out.println();
   154         Log.printLines(out, getLocalizedString("msg.usage.nonstandard.footer"));
   155     }
   157     /** Report a usage error.
   158      */
   159     void error(String key, Object... args) {
   160         if (fatalErrors) {
   161             String msg = getLocalizedString(key, args);
   162             throw new PropagatedException(new IllegalStateException(msg));
   163         }
   164         warning(key, args);
   165         Log.printLines(out, getLocalizedString("msg.usage", ownName));
   166     }
   168     /** Report a warning.
   169      */
   170     void warning(String key, Object... args) {
   171         Log.printLines(out, ownName + ": "
   172                        + getLocalizedString(key, args));
   173     }
   175     public Option getOption(String flag) {
   176         for (Option option : recognizedOptions) {
   177             if (option.matches(flag))
   178                 return option;
   179         }
   180         return null;
   181     }
   183     public void setOptions(Options options) {
   184         if (options == null)
   185             throw new NullPointerException();
   186         this.options = options;
   187     }
   189     public void setFatalErrors(boolean fatalErrors) {
   190         this.fatalErrors = fatalErrors;
   191     }
   193     /** Process command line arguments: store all command line options
   194      *  in `options' table and return all source filenames.
   195      *  @param flags    The array of command line arguments.
   196      */
   197     public List<File> processArgs(String[] flags) { // XXX sb protected
   198         int ac = 0;
   199         while (ac < flags.length) {
   200             String flag = flags[ac];
   201             ac++;
   203             Option option = null;
   205             if (flag.length() > 0) {
   206                 // quick hack to speed up file processing:
   207                 // if the option does not begin with '-', there is no need to check
   208                 // most of the compiler options.
   209                 int firstOptionToCheck = flag.charAt(0) == '-' ? 0 : recognizedOptions.length-1;
   210                 for (int j=firstOptionToCheck; j<recognizedOptions.length; j++) {
   211                     if (recognizedOptions[j].matches(flag)) {
   212                         option = recognizedOptions[j];
   213                         break;
   214                     }
   215                 }
   216             }
   218             if (option == null) {
   219                 error("err.invalid.flag", flag);
   220                 return null;
   221             }
   223             if (option.hasArg()) {
   224                 if (ac == flags.length) {
   225                     error("err.req.arg", flag);
   226                     return null;
   227                 }
   228                 String operand = flags[ac];
   229                 ac++;
   230                 if (option.process(options, flag, operand))
   231                     return null;
   232             } else {
   233                 if (option.process(options, flag))
   234                     return null;
   235             }
   236         }
   238         if (!checkDirectory("-d"))
   239             return null;
   240         if (!checkDirectory("-s"))
   241             return null;
   243         String sourceString = options.get("-source");
   244         Source source = (sourceString != null)
   245             ? Source.lookup(sourceString)
   246             : Source.DEFAULT;
   247         String targetString = options.get("-target");
   248         Target target = (targetString != null)
   249             ? Target.lookup(targetString)
   250             : Target.DEFAULT;
   251         // We don't check source/target consistency for CLDC, as J2ME
   252         // profiles are not aligned with J2SE targets; moreover, a
   253         // single CLDC target may have many profiles.  In addition,
   254         // this is needed for the continued functioning of the JSR14
   255         // prototype.
   256         if (Character.isDigit(target.name.charAt(0))) {
   257             if (target.compareTo(source.requiredTarget()) < 0) {
   258                 if (targetString != null) {
   259                     if (sourceString == null) {
   260                         warning("warn.target.default.source.conflict",
   261                                 targetString,
   262                                 source.requiredTarget().name);
   263                     } else {
   264                         warning("warn.source.target.conflict",
   265                                 sourceString,
   266                                 source.requiredTarget().name);
   267                     }
   268                     return null;
   269                 } else {
   270                     options.put("-target", source.requiredTarget().name);
   271                 }
   272             } else {
   273                 if (targetString == null && !source.allowGenerics()) {
   274                     options.put("-target", Target.JDK1_4.name);
   275                 }
   276             }
   277         }
   278         return filenames.toList();
   279     }
   280     // where
   281         private boolean checkDirectory(String optName) {
   282             String value = options.get(optName);
   283             if (value == null)
   284                 return true;
   285             File file = new File(value);
   286             if (!file.exists()) {
   287                 error("err.dir.not.found", value);
   288                 return false;
   289             }
   290             if (!file.isDirectory()) {
   291                 error("err.file.not.directory", value);
   292                 return false;
   293             }
   294             return true;
   295         }
   297     /** Programmatic interface for main function.
   298      * @param args    The command line parameters.
   299      */
   300     public int compile(String[] args) {
   301         Context context = new Context();
   302         JavacFileManager.preRegister(context); // can't create it until Log has been set up
   303         int result = compile(args, context);
   304         if (fileManager instanceof JavacFileManager) {
   305             // A fresh context was created above, so jfm must be a JavacFileManager
   306             ((JavacFileManager)fileManager).close();
   307         }
   308         return result;
   309     }
   311     public int compile(String[] args, Context context) {
   312         return compile(args, context, List.<JavaFileObject>nil(), null);
   313     }
   315     /** Programmatic interface for main function.
   316      * @param args    The command line parameters.
   317      */
   318     public int compile(String[] args,
   319                        Context context,
   320                        List<JavaFileObject> fileObjects,
   321                        Iterable<? extends Processor> processors)
   322     {
   323         if (options == null)
   324             options = Options.instance(context); // creates a new one
   326         filenames = new ListBuffer<File>();
   327         classnames = new ListBuffer<String>();
   328         JavaCompiler comp = null;
   329         /*
   330          * TODO: Logic below about what is an acceptable command line
   331          * should be updated to take annotation processing semantics
   332          * into account.
   333          */
   334         try {
   335             if (args.length == 0 && fileObjects.isEmpty()) {
   336                 help();
   337                 return EXIT_CMDERR;
   338             }
   340             List<File> filenames;
   341             try {
   342                 filenames = processArgs(CommandLine.parse(args));
   343                 if (filenames == null) {
   344                     // null signals an error in options, abort
   345                     return EXIT_CMDERR;
   346                 } else if (filenames.isEmpty() && fileObjects.isEmpty() && classnames.isEmpty()) {
   347                     // it is allowed to compile nothing if just asking for help or version info
   348                     if (options.get("-help") != null
   349                         || options.get("-X") != null
   350                         || options.get("-version") != null
   351                         || options.get("-fullversion") != null)
   352                         return EXIT_OK;
   353                     error("err.no.source.files");
   354                     return EXIT_CMDERR;
   355                 }
   356             } catch (java.io.FileNotFoundException e) {
   357                 Log.printLines(out, ownName + ": " +
   358                                getLocalizedString("err.file.not.found",
   359                                                   e.getMessage()));
   360                 return EXIT_SYSERR;
   361             }
   363             boolean forceStdOut = options.get("stdout") != null;
   364             if (forceStdOut) {
   365                 out.flush();
   366                 out = new PrintWriter(System.out, true);
   367             }
   369             context.put(Log.outKey, out);
   371             fileManager = context.get(JavaFileManager.class);
   373             comp = JavaCompiler.instance(context);
   374             if (comp == null) return EXIT_SYSERR;
   376             if (!filenames.isEmpty()) {
   377                 // add filenames to fileObjects
   378                 comp = JavaCompiler.instance(context);
   379                 List<JavaFileObject> otherFiles = List.nil();
   380                 JavacFileManager dfm = (JavacFileManager)fileManager;
   381                 for (JavaFileObject fo : dfm.getJavaFileObjectsFromFiles(filenames))
   382                     otherFiles = otherFiles.prepend(fo);
   383                 for (JavaFileObject fo : otherFiles)
   384                     fileObjects = fileObjects.prepend(fo);
   385             }
   386             comp.compile(fileObjects,
   387                          classnames.toList(),
   388                          processors);
   390             if (comp.errorCount() != 0 ||
   391                 options.get("-Werror") != null && comp.warningCount() != 0)
   392                 return EXIT_ERROR;
   393         } catch (IOException ex) {
   394             ioMessage(ex);
   395             return EXIT_SYSERR;
   396         } catch (OutOfMemoryError ex) {
   397             resourceMessage(ex);
   398             return EXIT_SYSERR;
   399         } catch (StackOverflowError ex) {
   400             resourceMessage(ex);
   401             return EXIT_SYSERR;
   402         } catch (FatalError ex) {
   403             feMessage(ex);
   404             return EXIT_SYSERR;
   405         } catch(AnnotationProcessingError ex) {
   406             apMessage(ex);
   407             return EXIT_SYSERR;
   408         } catch (ClientCodeException ex) {
   409             // as specified by javax.tools.JavaCompiler#getTask
   410             // and javax.tools.JavaCompiler.CompilationTask#call
   411             throw new RuntimeException(ex.getCause());
   412         } catch (PropagatedException ex) {
   413             throw ex.getCause();
   414         } catch (Throwable ex) {
   415             // Nasty.  If we've already reported an error, compensate
   416             // for buggy compiler error recovery by swallowing thrown
   417             // exceptions.
   418             if (comp == null || comp.errorCount() == 0 ||
   419                 options == null || options.get("dev") != null)
   420                 bugMessage(ex);
   421             return EXIT_ABNORMAL;
   422         } finally {
   423             if (comp != null) comp.close();
   424             filenames = null;
   425             options = null;
   426         }
   427         return EXIT_OK;
   428     }
   430     /** Print a message reporting an internal error.
   431      */
   432     void bugMessage(Throwable ex) {
   433         Log.printLines(out, getLocalizedString("msg.bug",
   434                                                JavaCompiler.version()));
   435         ex.printStackTrace(out);
   436     }
   438     /** Print a message reporting an fatal error.
   439      */
   440     void feMessage(Throwable ex) {
   441         Log.printLines(out, ex.getMessage());
   442     }
   444     /** Print a message reporting an input/output error.
   445      */
   446     void ioMessage(Throwable ex) {
   447         Log.printLines(out, getLocalizedString("msg.io"));
   448         ex.printStackTrace(out);
   449     }
   451     /** Print a message reporting an out-of-resources error.
   452      */
   453     void resourceMessage(Throwable ex) {
   454         Log.printLines(out, getLocalizedString("msg.resource"));
   455 //      System.out.println("(name buffer len = " + Name.names.length + " " + Name.nc);//DEBUG
   456         ex.printStackTrace(out);
   457     }
   459     /** Print a message reporting an uncaught exception from an
   460      * annotation processor.
   461      */
   462     void apMessage(AnnotationProcessingError ex) {
   463         Log.printLines(out,
   464                        getLocalizedString("msg.proc.annotation.uncaught.exception"));
   465         ex.getCause().printStackTrace();
   466     }
   468     private JavaFileManager fileManager;
   470     /* ************************************************************************
   471      * Internationalization
   472      *************************************************************************/
   474     /** Find a localized string in the resource bundle.
   475      *  @param key     The key for the localized string.
   476      */
   477     public static String getLocalizedString(String key, Object... args) { // FIXME sb private
   478         try {
   479             if (messages == null)
   480                 messages = new Messages(javacBundleName);
   481             return messages.getLocalizedString("javac." + key, args);
   482         }
   483         catch (MissingResourceException e) {
   484             throw new Error("Fatal Error: Resource for javac is missing", e);
   485         }
   486     }
   488     public static void useRawMessages(boolean enable) {
   489         if (enable) {
   490             messages = new Messages(javacBundleName) {
   491                     public String getLocalizedString(String key, Object... args) {
   492                         return key;
   493                     }
   494                 };
   495         } else {
   496             messages = new Messages(javacBundleName);
   497         }
   498     }
   500     private static final String javacBundleName =
   501         "com.sun.tools.javac.resources.javac";
   503     private static Messages messages;
   504 }

mercurial