Thu, 02 Oct 2008 19:58:40 -0700
6754988: Update copyright year
Summary: Update for files that have been modified starting July 2008
Reviewed-by: ohair, tbell
1 /*
2 * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
26 package com.sun.tools.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.CacheFSInfo;
35 import com.sun.tools.javac.file.JavacFileManager;
36 import com.sun.tools.javac.jvm.Target;
37 import com.sun.tools.javac.main.JavacOption.Option;
38 import com.sun.tools.javac.main.RecognizedOptions.OptionHelper;
39 import com.sun.tools.javac.util.*;
40 import com.sun.tools.javac.processing.AnnotationProcessingError;
41 import javax.tools.JavaFileManager;
42 import javax.tools.JavaFileObject;
43 import javax.annotation.processing.Processor;
45 /** This class provides a commandline interface to the GJC compiler.
46 *
47 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
48 * you write code that depends on this, you do so at your own risk.
49 * This code and its internal interfaces are subject to change or
50 * deletion without notice.</b>
51 */
52 public class Main {
54 /** The name of the compiler, for use in diagnostics.
55 */
56 String ownName;
58 /** The writer to use for diagnostic output.
59 */
60 PrintWriter out;
62 /**
63 * If true, any command line arg errors will cause an exception.
64 */
65 boolean fatalErrors;
67 /** Result codes.
68 */
69 static final int
70 EXIT_OK = 0, // Compilation completed with no errors.
71 EXIT_ERROR = 1, // Completed but reported errors.
72 EXIT_CMDERR = 2, // Bad command-line arguments
73 EXIT_SYSERR = 3, // System error or resource exhaustion.
74 EXIT_ABNORMAL = 4; // Compiler terminated abnormally
76 private Option[] recognizedOptions = RecognizedOptions.getJavaCompilerOptions(new OptionHelper() {
78 public void setOut(PrintWriter out) {
79 Main.this.out = out;
80 }
82 public void error(String key, Object... args) {
83 Main.this.error(key, args);
84 }
86 public void printVersion() {
87 Log.printLines(out, getLocalizedString("version", ownName, JavaCompiler.version()));
88 }
90 public void printFullVersion() {
91 Log.printLines(out, getLocalizedString("fullVersion", ownName, JavaCompiler.fullVersion()));
92 }
94 public void printHelp() {
95 help();
96 }
98 public void printXhelp() {
99 xhelp();
100 }
102 public void addFile(File f) {
103 if (!filenames.contains(f))
104 filenames.append(f);
105 }
107 public void addClassName(String s) {
108 classnames.append(s);
109 }
111 });
113 /**
114 * Construct a compiler instance.
115 */
116 public Main(String name) {
117 this(name, new PrintWriter(System.err, true));
118 }
120 /**
121 * Construct a compiler instance.
122 */
123 public Main(String name, PrintWriter out) {
124 this.ownName = name;
125 this.out = out;
126 }
127 /** A table of all options that's passed to the JavaCompiler constructor. */
128 private Options options = null;
130 /** The list of source files to process
131 */
132 public ListBuffer<File> filenames = null; // XXX sb protected
134 /** List of class files names passed on the command line
135 */
136 public ListBuffer<String> classnames = null; // XXX sb protected
138 /** Print a string that explains usage.
139 */
140 void help() {
141 Log.printLines(out, getLocalizedString("msg.usage.header", ownName));
142 for (int i=0; i<recognizedOptions.length; i++) {
143 recognizedOptions[i].help(out);
144 }
145 out.println();
146 }
148 /** Print a string that explains usage for X options.
149 */
150 void xhelp() {
151 for (int i=0; i<recognizedOptions.length; i++) {
152 recognizedOptions[i].xhelp(out);
153 }
154 out.println();
155 Log.printLines(out, getLocalizedString("msg.usage.nonstandard.footer"));
156 }
158 /** Report a usage error.
159 */
160 void error(String key, Object... args) {
161 if (fatalErrors) {
162 String msg = getLocalizedString(key, args);
163 throw new PropagatedException(new IllegalStateException(msg));
164 }
165 warning(key, args);
166 Log.printLines(out, getLocalizedString("msg.usage", ownName));
167 }
169 /** Report a warning.
170 */
171 void warning(String key, Object... args) {
172 Log.printLines(out, ownName + ": "
173 + getLocalizedString(key, args));
174 }
176 public Option getOption(String flag) {
177 for (Option option : recognizedOptions) {
178 if (option.matches(flag))
179 return option;
180 }
181 return null;
182 }
184 public void setOptions(Options options) {
185 if (options == null)
186 throw new NullPointerException();
187 this.options = options;
188 }
190 public void setFatalErrors(boolean fatalErrors) {
191 this.fatalErrors = fatalErrors;
192 }
194 /** Process command line arguments: store all command line options
195 * in `options' table and return all source filenames.
196 * @param flags The array of command line arguments.
197 */
198 public List<File> processArgs(String[] flags) { // XXX sb protected
199 int ac = 0;
200 while (ac < flags.length) {
201 String flag = flags[ac];
202 ac++;
204 Option option = null;
206 if (flag.length() > 0) {
207 // quick hack to speed up file processing:
208 // if the option does not begin with '-', there is no need to check
209 // most of the compiler options.
210 int firstOptionToCheck = flag.charAt(0) == '-' ? 0 : recognizedOptions.length-1;
211 for (int j=firstOptionToCheck; j<recognizedOptions.length; j++) {
212 if (recognizedOptions[j].matches(flag)) {
213 option = recognizedOptions[j];
214 break;
215 }
216 }
217 }
219 if (option == null) {
220 error("err.invalid.flag", flag);
221 return null;
222 }
224 if (option.hasArg()) {
225 if (ac == flags.length) {
226 error("err.req.arg", flag);
227 return null;
228 }
229 String operand = flags[ac];
230 ac++;
231 if (option.process(options, flag, operand))
232 return null;
233 } else {
234 if (option.process(options, flag))
235 return null;
236 }
237 }
239 if (!checkDirectory("-d"))
240 return null;
241 if (!checkDirectory("-s"))
242 return null;
244 String sourceString = options.get("-source");
245 Source source = (sourceString != null)
246 ? Source.lookup(sourceString)
247 : Source.DEFAULT;
248 String targetString = options.get("-target");
249 Target target = (targetString != null)
250 ? Target.lookup(targetString)
251 : Target.DEFAULT;
252 // We don't check source/target consistency for CLDC, as J2ME
253 // profiles are not aligned with J2SE targets; moreover, a
254 // single CLDC target may have many profiles. In addition,
255 // this is needed for the continued functioning of the JSR14
256 // prototype.
257 if (Character.isDigit(target.name.charAt(0))) {
258 if (target.compareTo(source.requiredTarget()) < 0) {
259 if (targetString != null) {
260 if (sourceString == null) {
261 warning("warn.target.default.source.conflict",
262 targetString,
263 source.requiredTarget().name);
264 } else {
265 warning("warn.source.target.conflict",
266 sourceString,
267 source.requiredTarget().name);
268 }
269 return null;
270 } else {
271 options.put("-target", source.requiredTarget().name);
272 }
273 } else {
274 if (targetString == null && !source.allowGenerics()) {
275 options.put("-target", Target.JDK1_4.name);
276 }
277 }
278 }
279 return filenames.toList();
280 }
281 // where
282 private boolean checkDirectory(String optName) {
283 String value = options.get(optName);
284 if (value == null)
285 return true;
286 File file = new File(value);
287 if (!file.exists()) {
288 error("err.dir.not.found", value);
289 return false;
290 }
291 if (!file.isDirectory()) {
292 error("err.file.not.directory", value);
293 return false;
294 }
295 return true;
296 }
298 /** Programmatic interface for main function.
299 * @param args The command line parameters.
300 */
301 public int compile(String[] args) {
302 Context context = new Context();
303 JavacFileManager.preRegister(context); // can't create it until Log has been set up
304 int result = compile(args, context);
305 if (fileManager instanceof JavacFileManager) {
306 // A fresh context was created above, so jfm must be a JavacFileManager
307 ((JavacFileManager)fileManager).close();
308 }
309 return result;
310 }
312 public int compile(String[] args, Context context) {
313 return compile(args, context, List.<JavaFileObject>nil(), null);
314 }
316 /** Programmatic interface for main function.
317 * @param args The command line parameters.
318 */
319 public int compile(String[] args,
320 Context context,
321 List<JavaFileObject> fileObjects,
322 Iterable<? extends Processor> processors)
323 {
324 if (options == null)
325 options = Options.instance(context); // creates a new one
327 filenames = new ListBuffer<File>();
328 classnames = new ListBuffer<String>();
329 JavaCompiler comp = null;
330 /*
331 * TODO: Logic below about what is an acceptable command line
332 * should be updated to take annotation processing semantics
333 * into account.
334 */
335 try {
336 if (args.length == 0 && fileObjects.isEmpty()) {
337 help();
338 return EXIT_CMDERR;
339 }
341 List<File> filenames;
342 try {
343 filenames = processArgs(CommandLine.parse(args));
344 if (filenames == null) {
345 // null signals an error in options, abort
346 return EXIT_CMDERR;
347 } else if (filenames.isEmpty() && fileObjects.isEmpty() && classnames.isEmpty()) {
348 // it is allowed to compile nothing if just asking for help or version info
349 if (options.get("-help") != null
350 || options.get("-X") != null
351 || options.get("-version") != null
352 || options.get("-fullversion") != null)
353 return EXIT_OK;
354 error("err.no.source.files");
355 return EXIT_CMDERR;
356 }
357 } catch (java.io.FileNotFoundException e) {
358 Log.printLines(out, ownName + ": " +
359 getLocalizedString("err.file.not.found",
360 e.getMessage()));
361 return EXIT_SYSERR;
362 }
364 boolean forceStdOut = options.get("stdout") != null;
365 if (forceStdOut) {
366 out.flush();
367 out = new PrintWriter(System.out, true);
368 }
370 context.put(Log.outKey, out);
372 // allow System property in following line as a Mustang legacy
373 boolean batchMode = (options.get("nonBatchMode") == null
374 && System.getProperty("nonBatchMode") == null);
375 if (batchMode)
376 CacheFSInfo.preRegister(context);
378 fileManager = context.get(JavaFileManager.class);
380 comp = JavaCompiler.instance(context);
381 if (comp == null) return EXIT_SYSERR;
383 if (!filenames.isEmpty()) {
384 // add filenames to fileObjects
385 comp = JavaCompiler.instance(context);
386 List<JavaFileObject> otherFiles = List.nil();
387 JavacFileManager dfm = (JavacFileManager)fileManager;
388 for (JavaFileObject fo : dfm.getJavaFileObjectsFromFiles(filenames))
389 otherFiles = otherFiles.prepend(fo);
390 for (JavaFileObject fo : otherFiles)
391 fileObjects = fileObjects.prepend(fo);
392 }
393 comp.compile(fileObjects,
394 classnames.toList(),
395 processors);
397 if (comp.errorCount() != 0 ||
398 options.get("-Werror") != null && comp.warningCount() != 0)
399 return EXIT_ERROR;
400 } catch (IOException ex) {
401 ioMessage(ex);
402 return EXIT_SYSERR;
403 } catch (OutOfMemoryError ex) {
404 resourceMessage(ex);
405 return EXIT_SYSERR;
406 } catch (StackOverflowError ex) {
407 resourceMessage(ex);
408 return EXIT_SYSERR;
409 } catch (FatalError ex) {
410 feMessage(ex);
411 return EXIT_SYSERR;
412 } catch(AnnotationProcessingError ex) {
413 apMessage(ex);
414 return EXIT_SYSERR;
415 } catch (ClientCodeException ex) {
416 // as specified by javax.tools.JavaCompiler#getTask
417 // and javax.tools.JavaCompiler.CompilationTask#call
418 throw new RuntimeException(ex.getCause());
419 } catch (PropagatedException ex) {
420 throw ex.getCause();
421 } catch (Throwable ex) {
422 // Nasty. If we've already reported an error, compensate
423 // for buggy compiler error recovery by swallowing thrown
424 // exceptions.
425 if (comp == null || comp.errorCount() == 0 ||
426 options == null || options.get("dev") != null)
427 bugMessage(ex);
428 return EXIT_ABNORMAL;
429 } finally {
430 if (comp != null) comp.close();
431 filenames = null;
432 options = null;
433 }
434 return EXIT_OK;
435 }
437 /** Print a message reporting an internal error.
438 */
439 void bugMessage(Throwable ex) {
440 Log.printLines(out, getLocalizedString("msg.bug",
441 JavaCompiler.version()));
442 ex.printStackTrace(out);
443 }
445 /** Print a message reporting an fatal error.
446 */
447 void feMessage(Throwable ex) {
448 Log.printLines(out, ex.getMessage());
449 }
451 /** Print a message reporting an input/output error.
452 */
453 void ioMessage(Throwable ex) {
454 Log.printLines(out, getLocalizedString("msg.io"));
455 ex.printStackTrace(out);
456 }
458 /** Print a message reporting an out-of-resources error.
459 */
460 void resourceMessage(Throwable ex) {
461 Log.printLines(out, getLocalizedString("msg.resource"));
462 // System.out.println("(name buffer len = " + Name.names.length + " " + Name.nc);//DEBUG
463 ex.printStackTrace(out);
464 }
466 /** Print a message reporting an uncaught exception from an
467 * annotation processor.
468 */
469 void apMessage(AnnotationProcessingError ex) {
470 Log.printLines(out,
471 getLocalizedString("msg.proc.annotation.uncaught.exception"));
472 ex.getCause().printStackTrace();
473 }
475 private JavaFileManager fileManager;
477 /* ************************************************************************
478 * Internationalization
479 *************************************************************************/
481 /** Find a localized string in the resource bundle.
482 * @param key The key for the localized string.
483 */
484 public static String getLocalizedString(String key, Object... args) { // FIXME sb private
485 try {
486 if (messages == null)
487 messages = new Messages(javacBundleName);
488 return messages.getLocalizedString("javac." + key, args);
489 }
490 catch (MissingResourceException e) {
491 throw new Error("Fatal Error: Resource for javac is missing", e);
492 }
493 }
495 public static void useRawMessages(boolean enable) {
496 if (enable) {
497 messages = new Messages(javacBundleName) {
498 public String getLocalizedString(String key, Object... args) {
499 return key;
500 }
501 };
502 } else {
503 messages = new Messages(javacBundleName);
504 }
505 }
507 private static final String javacBundleName =
508 "com.sun.tools.javac.resources.javac";
510 private static Messages messages;
511 }