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

Sun, 26 Jul 2009 21:27:11 -0700

author
darcy
date
Sun, 26 Jul 2009 21:27:11 -0700
changeset 331
d043adadc8b6
parent 285
4ce1c1400334
child 497
16b9b7f45933
permissions
-rw-r--r--

6381698: Warn of decommissioning of apt
Reviewed-by: jjg

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

mercurial