Mon, 16 Jun 2008 13:28:00 -0700
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 | } |