src/share/classes/com/sun/tools/apt/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

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

mercurial