Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(148)

Side by Side Diff: third_party/jmake/src/org/pantsbuild/jmake/Main.java

Issue 1373723003: Fix javac --incremental by using jmake for dependency analysis (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@aidl
Patch Set: fix license check Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /* Copyright (c) 2002-2008 Sun Microsystems, Inc. All rights reserved
2 *
3 * This program is distributed under the terms of
4 * the GNU General Public License Version 2. See the LICENSE file
5 * at the top of the source tree.
6 */
7 package org.pantsbuild.jmake;
8
9 import java.io.BufferedReader;
10 import java.io.FileNotFoundException;
11 import java.io.FileReader;
12 import java.io.IOException;
13 import java.io.PrintStream;
14 import java.io.Reader;
15 import java.io.StreamTokenizer;
16 import java.lang.reflect.Method;
17 import java.util.ArrayList;
18 import java.util.List;
19
20 /**
21 * The main class of the <b>jmake</b> tool.<p>
22 *
23 * Has several entrypoints: <code>main</code>, <code>mainExternal</code>, <code> mainProgrammatic</code>,
24 * <code>mainExternalControlled</code> and <code>mainProgrammaticControlled</cod e>.
25 * The first is not intended to be used by applications other than <b>jmake</b> itself, whereas the
26 * rest can be used to call <b>jmake</b> externally with various degrees of cont rol over its behaviour.
27 * See method comments for more details.
28 *
29 * @author Misha Dmitriev
30 * 12 October 2004
31 */
32 public class Main {
33
34 static final String DEFAULT_STORE_NAME = "jmake.pdb";
35 static final String VERSION = "1.3.8-11";
36 private String pdbFileName = null;
37 private List<String> allProjectJavaFileNamesList =
38 new ArrayList<String>(100);
39 private String allProjectJavaFileNames[];
40 private String addedJavaFileNames[], removedJavaFileNames[], updatedJavaFi leNames[];
41 private String destDir = "";
42 private List<String> javacAddArgs = new ArrayList<String>();
43 private String jcPath, jcMainClass, jcMethod;
44 private String jcExecApp;
45 boolean controlledExecution = false;
46 Object externalApp = null;
47 Method externalCompileSourceFilesMethod = null;
48 private boolean failOnDependentJar = false, noWarnOnDependentJar = false;
49 private boolean pdbTextFormat = false;
50 private PCDManager pcdm = null;
51 private String dependencyFile;
52 private static final String optNames[] = {"-h", "-help", "-d", "-pdb", "-C", "-jcpath", "-jcmainclass", "-jcmethod", "-jcexec", "-Xtiming", "-version",
53 "-warnlimit", "-failondependentjar", "-nowarnondependentjar", "-classpat h", "-projclasspath", "-bootclasspath", "-extdirs", "-vpath", "-pdb-text-format" ,
54 "-depfile"};
55 private static final int optArgs[] = {0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1};
56 private static final int OPT_H = 0;
57 private static final int OPT_HELP = 1;
58 private static final int OPT_D = 2;
59 private static final int OPT_STORE = 3;
60 private static final int OPT_JAVAC_OPT = 4;
61 private static final int OPT_JCPATH = 5;
62 private static final int OPT_JCMAINCLASS = 6;
63 private static final int OPT_JCMETHOD = 7;
64 private static final int OPT_JCEXEC = 8;
65 private static final int OPT_TIMING = 9;
66 private static final int OPT_VERSION = 10;
67 private static final int OPT_WARNLIMIT = 11;
68 private static final int OPT_FAILONDEPJAR = 12;
69 private static final int OPT_NOWARNONDEPJAR = 13;
70 private static final int OPT_CLASSPATH = 14;
71 private static final int OPT_PROJECTCLASSPATH = 15;
72 private static final int OPT_BOOTCLASSPATH = 16;
73 private static final int OPT_EXTDIRS = 17;
74 private static final int OPT_VPATH = 18;
75 private static final int OPT_PDB_TEXT_FORMAT = 19;
76 private static final int OPT_DEPENDENCY_FILE = 20;
77
78 /** Construct a new instance of Main. */
79 public Main() {
80 }
81
82 /**
83 * Checks whether the argument is a legal jmake option. Returns its number o r
84 * -1 if not found.
85 */
86 private static int inOptions(String option) {
87 if (option.startsWith(optNames[OPT_JAVAC_OPT])) {
88 return OPT_JAVAC_OPT;
89 }
90 for (int i = 0; i < optNames.length; i++) {
91 if (option.equals(optNames[i])) {
92 return i;
93 }
94 }
95 return -1;
96 }
97
98 private void processCommandLine(String args[]) {
99 if ((args.length == 0) || (args.length == 1 && args[0].equals(optNames[O PT_HELP]))) {
100 printUsage();
101 throw new PrivateException(new PublicExceptions.NoActionRequestedExc eption());
102 }
103
104 List<String> argsV = new ArrayList<String>();
105 for (int i = 0; i < args.length; i++) {
106 argsV.add(args[i]);
107 }
108 int argsSt = 0;
109 String arg;
110
111 while (argsSt < argsV.size()) {
112 arg = argsV.get(argsSt++);
113 if (arg.charAt(0) == '-') {
114 int argN = inOptions(arg);
115 if (argN != -1) {
116 if (argsSt + optArgs[argN] > argsV.size()) {
117 optRequiresArg("\"" + optNames[argN] + "\"");
118 }
119 } else {
120 bailOut(arg + ERR_IS_INVALID_OPTION);
121 }
122
123 switch (argN) {
124 case OPT_H:
125 case OPT_HELP:
126 printUsage();
127 throw new PrivateException(new PublicExceptions.NoAction RequestedException());
128 case OPT_D:
129 destDir = argsV.get(argsSt);
130 javacAddArgs.add("-d");
131 javacAddArgs.add(argsV.get(argsSt));
132 argsSt++;
133 break;
134 case OPT_CLASSPATH:
135 try {
136 setClassPath(argsV.get(argsSt++));
137 } catch (PublicExceptions.InvalidCmdOptionException ex) {
138 bailOut(ex.getMessage());
139 }
140 break;
141 case OPT_PROJECTCLASSPATH:
142 try {
143 setProjectClassPath(argsV.get(argsSt++));
144 } catch (PublicExceptions.InvalidCmdOptionException ex) {
145 bailOut(ex.getMessage());
146 }
147 break;
148 case OPT_STORE:
149 pdbFileName = argsV.get(argsSt++);
150 break;
151 case OPT_JAVAC_OPT:
152 String javacArg =
153 (argsV.get(argsSt - 1)).substring(2);
154 if (javacArg.equals("-d") ||
155 javacArg.equals("-classpath") ||
156 javacArg.equals("-bootclasspath") ||
157 javacArg.equals("-extdirs")) {
158 bailOut(javacArg + ERR_SHOULD_BE_EXPLICIT);
159 }
160 javacAddArgs.add(javacArg);
161 break;
162 case OPT_JCPATH:
163 if (jcExecApp != null) {
164 bailOut(ERR_NO_TWO_COMPILER_OPTIONS);
165 }
166 jcPath = argsV.get(argsSt++);
167 break;
168 case OPT_JCMAINCLASS:
169 if (jcExecApp != null) {
170 bailOut(ERR_NO_TWO_COMPILER_OPTIONS);
171 }
172 jcMainClass = argsV.get(argsSt++);
173 break;
174 case OPT_JCMETHOD:
175 if (jcExecApp != null) {
176 bailOut(ERR_NO_TWO_COMPILER_OPTIONS);
177 }
178 jcMethod = argsV.get(argsSt++);
179 break;
180 case OPT_JCEXEC:
181 if (jcPath != null || jcMainClass != null || jcMethod != null) {
182 bailOut(ERR_NO_TWO_COMPILER_OPTIONS);
183 }
184 jcExecApp = argsV.get(argsSt++);
185 break;
186 case OPT_TIMING:
187 Utils.setTimingOn();
188 break;
189 case OPT_VERSION:
190 // Utils.printInfoMessage("jmake version " + VERSION); / / Printed anyway at present...
191 throw new PrivateException(new PublicExceptions.NoAction RequestedException());
192 case OPT_WARNLIMIT:
193 try {
194 Utils.warningLimit =
195 Integer.parseInt(argsV.get(argsSt++));
196 } catch (NumberFormatException e) {
197 Utils.ignore(e);
198 bailOut(argsV.get(argsSt) + ERR_IS_INVALID_OPTION);
199 }
200 break;
201 case OPT_FAILONDEPJAR:
202 if (noWarnOnDependentJar) {
203 bailOut("it is not allowed to use -nowarnondependent jar and -failondependentjar together");
204 }
205 failOnDependentJar = true;
206 break;
207 case OPT_NOWARNONDEPJAR:
208 if (failOnDependentJar) {
209 bailOut("it is not allowed to use -failondependentja r and -nowarnondependentjar together");
210 }
211 noWarnOnDependentJar = true;
212 break;
213 case OPT_BOOTCLASSPATH:
214 try {
215 setBootClassPath(argsV.get(argsSt++));
216 } catch (PublicExceptions.InvalidCmdOptionException ex) {
217 bailOut(ex.getMessage());
218 }
219 break;
220 case OPT_EXTDIRS:
221 try {
222 setExtDirs(argsV.get(argsSt++));
223 } catch (PublicExceptions.InvalidCmdOptionException ex) {
224 bailOut(ex.getMessage());
225 }
226 break;
227 case OPT_VPATH:
228 try {
229 setVirtualPath(argsV.get(argsSt++));
230 } catch (PublicExceptions.InvalidCmdOptionException ex) {
231 bailOut(ex.getMessage());
232 }
233 break;
234 case OPT_PDB_TEXT_FORMAT:
235 pdbTextFormat = true;
236 break;
237 case OPT_DEPENDENCY_FILE:
238 dependencyFile = argsV.get(argsSt++);
239 break;
240 default:
241 bailOut(arg + ERR_IS_INVALID_OPTION);
242 }
243 } else { // Not an option, at least does not start with "-". Trea t it as a command line file name or source name.
244 if (arg.length() > 1 && arg.charAt(0) == '@') {
245 arg = arg.substring(1);
246 loadCmdFile(arg, argsV);
247 } else {
248 if (!arg.endsWith(".java")) {
249 bailOut(arg + ERR_IS_INVALID_OPTION);
250 }
251 allProjectJavaFileNamesList.add(arg);
252 }
253 }
254 }
255 }
256
257 /** Load @-file that can contain anything that command line can contain. */
258 private void loadCmdFile(String name, List<String> argsV) {
259 try {
260 Reader r = new BufferedReader(new FileReader(name));
261 StreamTokenizer st = new StreamTokenizer(r);
262 st.resetSyntax();
263 st.wordChars(' ', 255);
264 st.whitespaceChars(0, ' ');
265 st.commentChar('#');
266 st.quoteChar('"');
267 st.quoteChar('\'');
268 while (st.nextToken() != StreamTokenizer.TT_EOF) {
269 argsV.add(st.sval);
270 }
271 r.close();
272 } catch (IOException e) {
273 throw new PrivateException(new PublicExceptions.CommandFileReadExcep tion(name + ":\n" + e.getMessage()));
274 }
275 }
276
277 /**
278 * Main entrypoint for applications that want to call <b>jmake</b> externall y and are willing
279 * to handle exceptions that it may throw.
280 *
281 * @param args command line arguments passed to <b>jmake</b>.
282 *
283 * @throws PublicExceptions.NoActionRequestedException if <b>jmake</b> was not requested to do any real work;
284 * @throws PublicExceptions.InvalidCmdOptionException if invalid command l ine option was detected;
285 * @throws PublicExceptions.PDBCorruptedException if project database is corrupted;
286 * @throws PublicExceptions.CommandFileReadException if there was error r eading a command file;
287 * @throws PublicExceptions.CompilerInteractionException if there was a prob lem initializing or calling the compiler,
288 * or compilation erro rs were detected;
289 * @throws PublicExceptions.ClassFileParseException if there was error p arsing a class file;
290 * @throws PublicExceptions.ClassNameMismatchException if there is a mismat ch between the deduced and the actual class name;
291 * @throws PublicExceptions.InvalidSourceFileExtensionException if a supplie d source file has an invalid extension (not .java);
292 * @throws PublicExceptions.JarDependsOnSourceException if a class in a <cod e>JAR</code> is found dependent on a class with the .java source;
293 * @throws PublicExceptions.DoubleEntryException if more than one ent ry for the same class is found in the project
294 * @throws FileNotFoundException if a <code>.java</co de> or a <code>.class</code> file was not found;
295 * @throws IOException if there was an I/O problem of any kind;
296 * @throws PublicExceptions.InternalException if an internal probl em that should never happen was detected.
297 */
298 public void mainProgrammatic(String args[]) throws
299 PublicExceptions.NoActionRequestedException,
300 PublicExceptions.InvalidCmdOptionException,
301 PublicExceptions.PDBCorruptedException,
302 PublicExceptions.CommandFileReadException,
303 PublicExceptions.CompilerInteractionException,
304 PublicExceptions.ClassFileParseException,
305 PublicExceptions.ClassNameMismatchException,
306 PublicExceptions.InvalidSourceFileExtensionException,
307 PublicExceptions.JarDependsOnSourceException,
308 PublicExceptions.DoubleEntryException,
309 FileNotFoundException,
310 IOException,
311 PublicExceptions.InternalException {
312 try {
313 Utils.printInfoMessage("Jmake version " + VERSION);
314 if (!controlledExecution) {
315 processCommandLine(args);
316 String[] projectJars = ClassPath.getProjectJars();
317 if (projectJars != null) {
318 for (int i = 0; i < projectJars.length; i++) {
319 allProjectJavaFileNamesList.add(projectJars[i]);
320 }
321 }
322 allProjectJavaFileNames =
323 allProjectJavaFileNamesList.toArray(new String[allProjec tJavaFileNamesList.size()]);
324 } else {
325 String[] projectJars = ClassPath.getProjectJars();
326 if (projectJars != null) {
327 String newNames[] =
328 new String[allProjectJavaFileNames.length + projectJ ars.length];
329 System.arraycopy(allProjectJavaFileNames, 0, newNames, 0, al lProjectJavaFileNames.length);
330 System.arraycopy(projectJars, 0, newNames, allProjectJavaFil eNames.length, projectJars.length);
331 allProjectJavaFileNames = newNames;
332 }
333 }
334
335 Utils.startTiming(Utils.TIMING_PDBREAD);
336 PCDContainer pcdc;
337 pcdc = PCDContainer.load(pdbFileName, pdbTextFormat);
338 Utils.stopAndPrintTiming("DB read", Utils.TIMING_PDBREAD);
339
340 pcdm = new PCDManager(pcdc, allProjectJavaFileNames,
341 addedJavaFileNames, removedJavaFileNames, updatedJavaFileNames,
342 destDir, javacAddArgs, failOnDependentJar, noWarnOnDependentJar,
343 dependencyFile);
344
345 pcdm.initializeCompiler(jcExecApp, jcPath, jcMainClass, jcMethod, ex ternalApp, externalCompileSourceFilesMethod);
346
347 pcdm.run();
348 } catch (PrivateException e) {
349 Throwable origException = e.getOriginalException();
350 if (origException instanceof PublicExceptions.NoActionRequestedExcep tion) {
351 throw (PublicExceptions.NoActionRequestedException) origExceptio n;
352 } else if (origException instanceof PublicExceptions.InvalidCmdOptio nException) {
353 throw (PublicExceptions.InvalidCmdOptionException) origException ;
354 } else if (origException instanceof PublicExceptions.CommandFileRead Exception) {
355 throw (PublicExceptions.CommandFileReadException) origException;
356 } else if (origException instanceof PublicExceptions.PDBCorruptedExc eption) {
357 throw (PublicExceptions.PDBCorruptedException) origException;
358 } else if (origException instanceof PublicExceptions.CompilerInterac tionException) {
359 throw (PublicExceptions.CompilerInteractionException) origExcept ion;
360 } else if (origException instanceof PublicExceptions.ClassFileParseE xception) {
361 throw (PublicExceptions.ClassFileParseException) origException;
362 } else if (origException instanceof PublicExceptions.ClassNameMismat chException) {
363 throw (PublicExceptions.ClassNameMismatchException) origExceptio n;
364 } else if (origException instanceof PublicExceptions.InvalidSourceFi leExtensionException) {
365 throw (PublicExceptions.InvalidSourceFileExtensionException) ori gException;
366 } else if (origException instanceof PublicExceptions.JarDependsOnSou rceException) {
367 throw (PublicExceptions.JarDependsOnSourceException) origExcepti on;
368 } else if (origException instanceof PublicExceptions.DoubleEntryExce ption) {
369 throw (PublicExceptions.DoubleEntryException) origException;
370 } else if (origException instanceof FileNotFoundException) {
371 throw (FileNotFoundException) origException;
372 } else if (origException instanceof IOException) {
373 throw (IOException) origException;
374 } else if (origException instanceof PublicExceptions.InternalExcepti on) {
375 throw (PublicExceptions.InternalException) origException;
376 }
377 } finally {
378 ClassPath.resetOnFinish();
379 }
380 }
381
382 /**
383 * Main entrypoint for applications that want to call <b>jmake</b> externall y and would prefer
384 * receiving an error code instead of an exception in case something goes wr ong.<p>
385 *
386 * @param args command line arguments passed to <b>jmake</b>.
387 *
388 * @return <dl>
389 * <dt><code> 0</code> if everything was successful;
390 * <dt><code> -1</code> invalid command line option detected;
391 * <dt><code> -2</code> error reading command file;
392 * <dt><code> -3</code> project database corrupted;
393 * <dt><code> -4</code> error initializing or calling the compiler;
394 * <dt><code> -5</code> compilation error;
395 * <dt><code> -6</code> error parsing a class file;
396 * <dt><code> -7</code> file not found;
397 * <dt><code> -8</code> I/O exception;
398 * <dt><code> -9</code> internal jmake exception;
399 * <dt><code>-10</code> deduced and actual class name mismatch;
400 * <dt><code>-11</code> invalid source file extension;
401 * <dt><code>-12</code> a class in a <code>JAR</code> is found dependent o n a class with the .java source;
402 * <dt><code>-13</code> more than one entry for the same class is found in the project
403 * <dt><code>-20</code> internal Java error (caused by <code>java.lang.Inte rnalError</code>);
404 * <dt><code>-30</code> internal Java error (caused by <code>java.lang.Runt imeException</code>).
405 * </dl>
406 */
407 public int mainExternal(String args[]) {
408 try {
409 mainProgrammatic(args);
410 } catch (PublicExceptions.NoActionRequestedException e0) {
411 // Nothing to do
412 } catch (PublicExceptions.InvalidCmdOptionException e1) {
413 Utils.printErrorMessage(e1.getMessage());
414 return -1;
415 } catch (PublicExceptions.CommandFileReadException e2) {
416 Utils.printErrorMessage("error parsing command file:");
417 Utils.printErrorMessage(e2.getMessage());
418 return -2;
419 } catch (PublicExceptions.PDBCorruptedException e3) {
420 Utils.printErrorMessage("project database corrupted: " + e3.getMessa ge());
421 return -3;
422 } catch (PublicExceptions.CompilerInteractionException e4) {
423 if (e4.getOriginalException() != null) {
424 Utils.printErrorMessage("error interacting with the compiler: ") ;
425 Utils.printErrorMessage(e4.getMessage());
426 Utils.printErrorMessage("original exception:");
427 Utils.printErrorMessage(e4.getOriginalException().getMessage());
428 return -4;
429 } else { // Otherwise there is a compilation error, and the compiler has already printed a lot...
430 return -5;
431 }
432 } catch (PublicExceptions.ClassFileParseException e6) {
433 Utils.printErrorMessage(e6.getMessage());
434 return -6;
435 } catch (FileNotFoundException e7) {
436 Utils.printErrorMessage(e7.getMessage());
437 return -7;
438 } catch (IOException e8) {
439 Utils.printErrorMessage(e8.getMessage());
440 return -8;
441 } catch (PublicExceptions.InternalException e9) {
442 Utils.printErrorMessage("internal jmake exception detected:");
443 Utils.printErrorMessage(e9.getMessage());
444 Utils.printErrorMessage(Utils.REPORT_PROBLEM);
445 Utils.printErrorMessage("the stack trace is as follows:");
446 e9.printStackTrace();
447 return -9;
448 } catch (PublicExceptions.ClassNameMismatchException e10) {
449 Utils.printErrorMessage(e10.getMessage());
450 return -10;
451 } catch (PublicExceptions.InvalidSourceFileExtensionException e11) {
452 Utils.printErrorMessage(e11.getMessage());
453 return -11;
454 } catch (PublicExceptions.JarDependsOnSourceException e12) {
455 Utils.printErrorMessage(e12.getMessage());
456 return -12;
457 } catch (PublicExceptions.DoubleEntryException e13) {
458 Utils.printErrorMessage(e13.getMessage());
459 return -13;
460 } catch (InternalError e20) {
461 Utils.printErrorMessage("internal Java error: " + e20);
462 Utils.printErrorMessage("Consult the following stack trace for more info:");
463 e20.printStackTrace();
464 return -20;
465 } catch (RuntimeException e30) {
466 Utils.printErrorMessage("internal Java exception: " + e30);
467 Utils.printErrorMessage("Consult the following stack trace for more info:");
468 e30.printStackTrace();
469 return -30;
470 }
471
472 return 0;
473 }
474
475 /**
476 * Main entrypoint for applications such as Ant, that want to have full cont rol over
477 * compilations that <b>jmake</b> invokes, and are willing to handle excepti ons
478 * that it may throw.
479 *
480 * @param javaFileNames array of strings that specify <code>.java</code> file names.
481 * @param destDirName name of the destination directory (<b>jmake</b> w ill look up binary classes
482 * in there, it should be the same as the one used b y the Java compiler method).
483 * If <code>null</code> is passed, classes will be l ooked up in the same directories
484 * as their sources, in agreement with the default J ava compiler behaviour.
485 * @param pdbFileName project database file name (if <code>null</code> is passed,
486 * a file with the default name placed in the curren t directory will be used).
487 * @param externalApp an object on which to invoke <code>externalCompil eSourceFilesMethod</code> method.
488 * @param externalCompileSourceFilesMethod a method of the form <code>int x(String[] args)</code>. It
489 * should return <code>0</code> if compilation is su ccessful and any non-zero value
490 * otherwise. <b>jmake</b> passes it a list of the < code>.java</code> files to
491 * recompile in the form of canonical full path file names.
492 *
493 * @throws PublicExceptions.NoActionRequestedException if <b>jmake</b> was not requested to do any real work;
494 * @throws PublicExceptions.InvalidCmdOptionException if invalid command l ine option was detected;
495 * @throws PublicExceptions.PDBCorruptedException if project database is corrupted;
496 * @throws PublicExceptions.CommandFileReadException if there was error r eading a command file;
497 * @throws PublicExceptions.CompilerInteractionException if there was a prob lem initializing or calling the compiler,
498 * or compilation erro rs were detected;
499 * @throws PublicExceptions.ClassFileParseException if there was error p arsing a class file;
500 * @throws PublicExceptions.ClassNameMismatchException if there is a mismat ch between the deduced and the actual class name;
501 * @throws PublicExceptions.InvalidSourceFileExtensionException if a specifi ed source file has an invalid extension (not .java);
502 * @throws PublicExceptions.JarDependsOnSourceException if a class in a <cod e>JAR</code> is found dependent on a class with the .java source;
503 * @throws PublicExceptions.DoubleEntryException if more than one ent ry for the same class is found in the project
504 * @throws PublicExceptions.InternalException if an internal probl em that should never happen was detected.
505 * @throws FileNotFoundException if a <code>.java</co de> or a <code>.class</code> file was not found;
506 * @throws IOException if there was an I/O problem of any kind;
507 */
508 public void mainProgrammaticControlled(String javaFileNames[], String destDi rName, String pdbFileName,
509 Object externalApp, Method externalCompileSourceFilesMethod) throws
510 PublicExceptions.NoActionRequestedException,
511 PublicExceptions.InvalidCmdOptionException,
512 PublicExceptions.PDBCorruptedException,
513 PublicExceptions.CommandFileReadException,
514 PublicExceptions.CompilerInteractionException,
515 PublicExceptions.ClassFileParseException,
516 PublicExceptions.ClassNameMismatchException,
517 PublicExceptions.InvalidSourceFileExtensionException,
518 PublicExceptions.JarDependsOnSourceException,
519 PublicExceptions.DoubleEntryException,
520 PublicExceptions.InternalException,
521 FileNotFoundException,
522 IOException {
523
524 controlledExecution = true;
525 this.pdbFileName = pdbFileName;
526 this.destDir = destDirName;
527 this.allProjectJavaFileNames = javaFileNames;
528 this.externalApp = externalApp;
529 this.externalCompileSourceFilesMethod = externalCompileSourceFilesMethod ;
530
531 mainProgrammatic(null);
532 }
533
534 /**
535 * Main entrypoint for applications such as Ant, that want to have full cont rol over
536 * compilations that <b>jmake</b> invokes, and do not want to handle excepti ons that it
537 * may throw. Error codes returned are the same as <code>mainExternal(String [])</code> returns.
538 *
539 * @param javaFileNames array of strings that specify <code>.java</code> file names.
540 * @param destDirName name of the destination directory (<b>jmake</b> w ill look up binary classes
541 * in there, it should be the same as the one used b y the Java compiler method).
542 * If <code>null</code> is passed, classes will be l ooked up in the same directories
543 * as their sources, in agreement with the default J ava compiler behaviour.
544 * @param pdbFileName project database file name (if <code>null</code> is passed,
545 * a file with the default name placed in the curren t directory will be used).
546 * @param externalApp an object on which to invoke <code>externalCompil eSourceFilesMethod</code> method.
547 * @param externalCompileSourceFilesMethod a method of the form <code>int x(String[] args)</code>. It
548 * should return <code>0</code> if compilation is su ccessful and any non-zero value
549 * otherwise. <b>jmake</b> passes it a list of the < code>.java</code> files to
550 * recompile in the form of canonical full path file names.
551 *
552 * @see #mainExternal(String[])
553 */
554 public int mainExternalControlled(String javaFileNames[], String destDirName , String pdbFileName,
555 Object externalApp, Method externalCompileSourceFilesMethod) {
556 controlledExecution = true;
557 this.pdbFileName = pdbFileName;
558 this.destDir = destDirName;
559 this.allProjectJavaFileNames = javaFileNames;
560 this.externalApp = externalApp;
561 this.externalCompileSourceFilesMethod = externalCompileSourceFilesMethod ;
562
563 return mainExternal(null);
564 }
565
566 /**
567 * Main entrypoint for applications such as IDEs, that themselves keep track of updated/added/removed sources,
568 * want to have full control over compilations that <b>jmake</b> invokes, an d are willing to handle exceptions
569 * that it may throw.
570 *
571 * @param addedJavaFileNames names of <code>.java</code> files just added to the project
572 * @param removedJavaFileNames names of <code>.java</code> files just remove d from the project
573 * @param updatedJavaFileNames names of updated project <code>.java</code> f iles
574 * @param destDirName name of the destination directory (<b>jmake</b> w ill look up binary classes
575 * in there, it should be the same as the one used b y the Java compiler method).
576 * If <code>null</code> is passed, classes will be l ooked up in the same directories
577 * as their sources, in agreement with the default J ava compiler behaviour.
578 * @param pdbFileName project database file name (if <code>null</code> is passed,
579 * a file with the default name placed in the curren t directory will be used).
580 * @param externalApp an object on which to invoke <code>externalCompil eSourceFilesMethod</code> method.
581 * @param externalCompileSourceFilesMethod a method of the form <code>int x(String[] args)</code>. It
582 * should return <code>0</code> if compilation is su ccessful and any non-zero value
583 * otherwise. <b>jmake</b> passes it a list of the < code>.java</code> files to
584 * recompile in the form of canonical full path file names.
585 *
586 * @throws PublicExceptions.NoActionRequestedException if <b>jmake</b> was not requested to do any real work;
587 * @throws PublicExceptions.InvalidCmdOptionException if invalid command l ine option was detected;
588 * @throws PublicExceptions.PDBCorruptedException if project database is corrupted;
589 * @throws PublicExceptions.CommandFileReadException if there was error r eading a command file;
590 * @throws PublicExceptions.CompilerInteractionException if there was a prob lem initializing or calling the compiler,
591 * or compilation erro rs were detected;
592 * @throws PublicExceptions.ClassFileParseException if there was error p arsing a class file;
593 * @throws PublicExceptions.ClassNameMismatchException if there is a mismat ch between the deduced and the actual class name;
594 * @throws PublicExceptions.InvalidSourceFileExtensionException if a specifi ed source file has an invalid extension (not .java);
595 * @throws PublicExceptions.JarDependsOnSourceException if a class in a <cod e>JAR</code> is found dependent on a class with the .java source;
596 * @throws PublicExceptions.DoubleEntryException if more than one ent ry for the same class is found in the project
597 * @throws PublicExceptions.InternalException if an internal probl em that should never happen was detected.
598 * @throws FileNotFoundException if a <code>.java</co de> or a <code>.class</code> file was not found;
599 * @throws IOException if there was an I/O problem of any kind;
600 */
601 public void mainProgrammaticControlled(String addedJavaFileNames[], String r emovedJavaFileNames[], String updatedJavaFileNames[],
602 String destDirName, String pdbFileName,
603 Object externalApp, Method externalCompileSourceFilesMethod) throws
604 PublicExceptions.NoActionRequestedException,
605 PublicExceptions.InvalidCmdOptionException,
606 PublicExceptions.PDBCorruptedException,
607 PublicExceptions.CommandFileReadException,
608 PublicExceptions.CompilerInteractionException,
609 PublicExceptions.ClassFileParseException,
610 PublicExceptions.ClassNameMismatchException,
611 PublicExceptions.InvalidSourceFileExtensionException,
612 PublicExceptions.JarDependsOnSourceException,
613 PublicExceptions.DoubleEntryException,
614 PublicExceptions.InternalException,
615 FileNotFoundException,
616 IOException {
617
618 controlledExecution = true;
619 this.pdbFileName = pdbFileName;
620 this.destDir = destDirName;
621 this.addedJavaFileNames = addedJavaFileNames;
622 this.removedJavaFileNames = removedJavaFileNames;
623 this.updatedJavaFileNames = updatedJavaFileNames;
624 this.externalApp = externalApp;
625 this.externalCompileSourceFilesMethod = externalCompileSourceFilesMethod ;
626
627 mainProgrammatic(null);
628 }
629
630 /**
631 * Main entrypoint for applications such as IDEs, that themselves keep track of updated/added/removed sources,
632 * want to have full control over compilations that <b>jmake</b> invokes, an d do not want to handle exceptions
633 * that it may throw. Error codes returned are the same as <code>mainExterna l(String[])</code> returns.
634 *
635 * @param addedJavaFileNames names of <code>.java</code> files just added to the project
636 * @param removedJavaFileNames names of <code>.java</code> files just remove d from the project
637 * @param updatedJavaFileNames names of updated project <code>.java</code> f iles
638 * @param destDirName name of the destination directory (<b>jmake</b> w ill look up binary classes
639 * in there, it should be the same as the one used b y the Java compiler method).
640 * If <code>null</code> is passed, classes will be l ooked up in the same directories
641 * as their sources, in agreement with the default J ava compiler behaviour.
642 * @param pdbFileName project database file name (if <code>null</code> is passed,
643 * a file with the default name placed in the curren t directory will be used).
644 * @param externalApp an object on which to invoke <code>externalCompil eSourceFilesMethod</code> method.
645 * @param externalCompileSourceFilesMethod a method of the form <code>int x(String[] args)</code>. It
646 * should return <code>0</code> if compilation is su ccessful and any non-zero value
647 * otherwise. <b>jmake</b> passes it a list of the < code>.java</code> files to
648 * recompile in the form of canonical full path file names.
649 *
650 * @see #mainExternal(String[])
651 */
652 public int mainExternalControlled(String addedJavaFileNames[], String remove dJavaFileNames[], String updatedJavaFileNames[],
653 String destDirName, String pdbFileName,
654 Object externalApp, Method externalCompileSourceFilesMethod) {
655 controlledExecution = true;
656 this.pdbFileName = pdbFileName;
657 this.destDir = destDirName;
658 this.addedJavaFileNames = addedJavaFileNames;
659 this.removedJavaFileNames = removedJavaFileNames;
660 this.updatedJavaFileNames = updatedJavaFileNames;
661 this.externalApp = externalApp;
662 this.externalCompileSourceFilesMethod = externalCompileSourceFilesMethod ;
663
664 return mainExternal(null);
665 }
666
667 /**
668 * Main entrypoint for the standalone <b>jmake</b> application. This method calls does little but calling
669 * <code>mainExternal</code>, and its execution always completes with <code> System.exit(code)</code>,
670 * where <code>code</code> is the value returned by <code>mainExternal</code >.
671 *
672 * @see #mainExternal(String[])
673 * @see #mainProgrammatic(String[])
674 *
675 * @param args command line arguments passed to <b>jmake</b>
676 */
677 public static void main(String args[]) {
678 Utils.startTiming(Utils.TIMING_TOTAL);
679
680 Main m = new Main();
681 int exitCode = m.mainExternal(args);
682
683 Utils.stopAndPrintTiming("Total", Utils.TIMING_TOTAL);
684 if ( exitCode != 0 ) {
685 System.exit(exitCode);
686 }
687 }
688
689 /**
690 * Customize the output of <b>jmake</b>.
691 *
692 * @see #setOutputStreams(PrintStream, PrintStream, PrintStream)
693 *
694 * @param printInfoMessages specify whether to print information messages
695 * @param printWarningMessages specify whether to print warning messages
696 * @param printErrorMessages specify whether to print error messages
697 */
698 public static void customizeOutput(boolean printInfoMessages,
699 boolean printWarningMessages,
700 boolean printErrorMessages) {
701 Utils.customizeOutput(printInfoMessages, printWarningMessages, printErro rMessages);
702 }
703
704 /**
705 * Set the class path to be used by the compiler, and also by the dependency checker for the purposes of
706 * superclass/superinterface change tracking. For the compiler, this class p ath will be merged with the
707 * project class path (set via setProjectClassPath(String)). Other than that , its value will be used only to
708 * look up superclasses/superinterfaces of project classes. Note that non-pr oject superclasses and
709 * superinterfaces are first looked up at the boot class path, then on the e xtension class path, and then
710 * on this class path.
711 *
712 * @see #setProjectClassPath(String)
713 * @see #setBootClassPath(String)
714 * @see #setExtDirs(String)
715 *
716 * @param classPath the value of the class path, in the usual format (i.e. entries that are directories
717 * or JARs, separated by colon or semicolon depending on t he platform).
718 *
719 * @throws PublicExceptions.InvalidCmdOptionException if invalid class pat h value is specified.
720 */
721 public static void setClassPath(String classPath) throws PublicExceptions.In validCmdOptionException {
722 ClassPath.setClassPath(classPath);
723 }
724
725 /**
726 * Set the class path to be used by the compiler, and also by the dependency checker for the purposes of
727 * superclass/superinterface change tracking and sourceless class dependency checking. For the compiler,
728 * and also in order to look up superclasses/superinterfaces of project clas ses, this class path will be
729 * merged with the standard class path (set via setClassPath(String)). But i n addition, all binary classes
730 * that are on this class path are stored in the project database and checke d for updates every time jmake
731 * is invoked. Any changes to these classes trigger the standard dependency checking procedure. However,
732 * dependent classes are looked up only among the "normal" project classes, i.e. those that have sources.
733 * Therefore sourceless classes are assumed to always be mutually consistent .
734 *
735 * Currently only JAR files can be present on this class path.
736 *
737 * @see #setClassPath(String)
738 *
739 * @param projectClassPath the value of the class path, in the usual format (i.e. entries that are directories
740 * or JARs, separated by colon or semicolon dependi ng on the platform).
741 *
742 * @throws PublicExceptions.InvalidCmdOptionException if invalid class pat h value is specified.
743 */
744 public static void setProjectClassPath(String projectClassPath) throws Publi cExceptions.InvalidCmdOptionException {
745 ClassPath.setProjectClassPath(projectClassPath);
746 }
747
748 /**
749 * Set the boot class path to be used by the compiler (-bootclasspath option ) and also by the dependency
750 * checker (by default, the value of "sun.boot.class.path" property is used) .
751 *
752 * @see #setClassPath(String)
753 *
754 * @param classPath the value of the boot class path, in the usual format (i.e. entries that are directories
755 * or JARs, separated by colon or semicolon depending on t he platform).
756 *
757 * @throws PublicExceptions.InvalidCmdOptionException if invalid class pat h value is specified.
758 */
759 public static void setBootClassPath(String classPath) throws PublicException s.InvalidCmdOptionException {
760 ClassPath.setBootClassPath(classPath);
761 }
762
763 /**
764 * Set the extensions location to be used by the compiler (-extdirs option) and also by the dependency
765 * checker (by default, the value of "java.ext.dirs" property is used).
766 *
767 * @see #setClassPath(String)
768 *
769 * @param dirs the value of extension directories, in the usual format (on e or more directory names
770 * separated by colon or semicolon depending on the platform).
771 *
772 * @throws PublicExceptions.InvalidCmdOptionException if invalid class pat h value is specified.
773 */
774 public static void setExtDirs(String dirs) throws PublicExceptions.InvalidCm dOptionException {
775 ClassPath.setExtDirs(dirs);
776 }
777
778 /**
779 * Set the virtual path used to find both source and class files that are pa rt of the project
780 * but are not in the local directory.
781 *
782 * @see #setClassPath(String)
783 *
784 * @param dirs the value of extension directories, in the usual format (on e or more directory names
785 * separated by colon or semicolon depending on the platform).
786 *
787 * @throws PublicExceptions.InvalidCmdOptionException if invalid path valu e is specified.
788 */
789 public static void setVirtualPath(String dirs) throws PublicExceptions.Inval idCmdOptionException {
790 ClassPath.setVirtualPath(dirs);
791 }
792
793 /** Produce no warning or error message upon a dependent <code>JAR</code> de tection. */
794 public static final int DEPJAR_NOWARNORERROR = 0;
795 /** Produce a warning upon a dependent <code>JAR</code> detection. */
796 public static final int DEPJAR_WARNING = 1;
797 /** Produce an error message (throw an exception) upon a dependent <code>JAR </code> detection. */
798 public static final int DEPJAR_ERROR = 2;
799
800 /**
801 * Set the response of <b>jmake</b> in case a dependence of a class located in a <code>JAR</code> file on a
802 * class with a <code>.java</code> source is detected (such dependencies are highly discouraged, since it is not
803 * possible to recompile a class in the <code>JAR</code> that has no source) .
804 *
805 * @param code response type: DEPJAR_NOWARNORERROR, DEPJAR_WARNING (default behaviour) or DEPJAR_ERROR.
806 */
807 public void setResponseOnDependentJar(int code) {
808 switch (code) {
809 case DEPJAR_NOWARNORERROR:
810 noWarnOnDependentJar = true;
811 failOnDependentJar = false;
812 break;
813 case DEPJAR_WARNING:
814 noWarnOnDependentJar = false;
815 failOnDependentJar = false;
816 break;
817 case DEPJAR_ERROR:
818 noWarnOnDependentJar = false;
819 failOnDependentJar = true;
820 break;
821 }
822 }
823
824 /**
825 * Return the names of all classes that <b>jmake</b>, on this invocation, fo und updated - either because
826 * <b>jmake</b> itself recompiled them or because they were updated independ ently (their timestamp/checksum
827 * found different from those contained in the project database).
828 */
829 public String[] getUpdatedClasses() {
830 return pcdm.getAllUpdatedClassesAsStringArray();
831 }
832
833 /**
834 * Set the output print streams to be used by <b>jmake</b>.
835 *
836 * @see #customizeOutput(boolean, boolean, boolean)
837 *
838 * @param out print stream to be used for information ("logging") messages that <b>jmake</b> emits
839 * @param warn print stream to be used for warning messages
840 * @param err print stream to be used for error messages
841 */
842 public static void setOutputStreams(PrintStream out, PrintStream warn, Print Stream err) {
843 Utils.setOutputStreams(out, warn, err);
844 }
845
846 /** Get the version of this copy of <b>jmake</b> */
847 public static String getVersion() {
848 return VERSION;
849 }
850 private static final String ERR_IS_INVALID_OPTION =
851 " is an invalid option or argument.";
852 private static final String ERR_NO_TWO_COMPILER_OPTIONS =
853 "You may not specify both compiler class and compiler executable app lication";
854 private static final String ERR_SHOULD_BE_EXPLICIT =
855 " compiler option should be specified directly as a jmake option";
856
857 private static void bailOut(String s) {
858 throw new PrivateException(new PublicExceptions.InvalidCmdOptionExceptio n("jmake: " + s + "\nRun \"jmake -h\" for help."));
859 }
860
861 private static void optRequiresArg(String s) {
862 bailOut("the " + s + " option requires an argument.");
863 }
864
865 private static void printUsage() {
866 Utils.printInfoMessage("Usage: jmake <options> <.java files> <@files>");
867 Utils.printInfoMessage("where possible options include:");
868 Utils.printInfoMessage(" -h, -help print this help message" );
869 Utils.printInfoMessage(" -version print the product versio n number");
870 Utils.printInfoMessage(" -pdb <file name> specify non-default proj ect database file");
871 Utils.printInfoMessage(" -pdb-text-format if specified, pdb file i s stored in text format");
872 Utils.printInfoMessage(" -d <directory> specify where to place g enerated class files");
873 Utils.printInfoMessage(" -classpath <path> specify where to find us er class files");
874 Utils.printInfoMessage(" -projclasspath <path> specify where to find so urceless project classes");
875 Utils.printInfoMessage(" (currently only JARs are allowed on this path)");
876 Utils.printInfoMessage(" -C<option> specify an option to be passed to the Java compiler");
877 Utils.printInfoMessage(" (this option's arguments should also be preceded by -C)");
878 Utils.printInfoMessage(" -jcpath <path> specify the class path f or a non-default Java compiler");
879 Utils.printInfoMessage(" (default is <JAVAHOME>/l ib/tools.jar)");
880 Utils.printInfoMessage(" -jcmainclass <class> specify the main class f or a non-default Java compiler");
881 Utils.printInfoMessage(" (default is com.sun.tool s.javac.Main)");
882 Utils.printInfoMessage(" -jcmethod <method> specify the method to ca ll in the Java compiler class");
883 Utils.printInfoMessage(" (default is \"compile(St ring args[])\")");
884 Utils.printInfoMessage(" -jcexec <file name> specify a binary non-def ault Java compiler application");
885 Utils.printInfoMessage(" -failondependentjar fail if a class on proje ctclasspath depends on a class");
886 Utils.printInfoMessage(" with .java source (by de fault, a warning is issued)");
887 Utils.printInfoMessage(" -nowarnondependentjar no warning or error if a class on projectclasspath");
888 Utils.printInfoMessage(" depends on a class with a .java source (use with care)");
889 Utils.printInfoMessage(" -warnlimit <number> specify the maximum numb er of warnings (20 by default)");
890 Utils.printInfoMessage(" -bootclasspath <path> override location of boo tstrap class files");
891 Utils.printInfoMessage(" -extdirs <dirs> override location of ins talled extensions");
892 Utils.printInfoMessage(" -vpath <dirs> a list of directories to search for Java and class files similar to GNUMake's VPATH");
893 Utils.printInfoMessage(" -depfile <path> a file generated by the compiler containing additional java->class mappings");
894 Utils.printInfoMessage("");
895 Utils.printInfoMessage("Examples:");
896 Utils.printInfoMessage(" jmake -d classes -classpath .;mylib.jar X.java Y.java Z.java");
897 Utils.printInfoMessage(" jmake -pdb myproject.pdb -jcexec c:\\java\\jik es\\jikes.exe @myproject.src");
898 }
899 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698