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