Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/langtools/src/share/classes/com/sun/tools/sjavac/Main.java
38899 views
1
/*
2
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package com.sun.tools.sjavac;
27
28
import java.io.File;
29
import java.io.IOException;
30
import java.io.PrintStream;
31
import java.util.*;
32
import java.util.regex.Matcher;
33
import java.util.regex.Pattern;
34
35
import com.sun.tools.sjavac.server.JavacServer;
36
37
/**
38
* The main class of the smart javac wrapper tool.
39
*
40
* <p><b>This is NOT part of any supported API.
41
* If you write code that depends on this, you do so at your own
42
* risk. This code and its internal interfaces are subject to change
43
* or deletion without notice.</b></p>
44
*/
45
public class Main {
46
47
/* This is a smart javac wrapper primarily used when building the OpenJDK,
48
though other projects are welcome to use it too. But please be aware
49
that it is not an official api and will change in the future.
50
(We really mean it!)
51
52
Goals:
53
54
** Create a state file, containing information about the build, so
55
that incremental builds only rebuild what is necessary. Also the
56
state file can be used by make/ant to detect when to trigger
57
a call to the smart javac wrapper.
58
59
This file is called bin/javac_state (assuming that you specified "-d bin")
60
Thus the simplest makefile is:
61
62
SJAVAC=java -cp .../tools.jar com.sun.tools.sjavac.Main
63
SRCS=$(shell find src -name "*.java")
64
bin/javac_state : $(SRCS)
65
$(SJAVAC) src -d bin
66
67
This makefile will run very fast and detect properly when Java code needs to
68
be recompiled. The smart javac wrapper will then use the information in java_state
69
to do an efficient incremental compile.
70
71
Previously it was near enough impossible to write an efficient makefile for Java
72
with support for incremental builds and dependency tracking.
73
74
** Separate java sources to be compiled from java
75
sources used >only< for linking. The options:
76
77
"dir" points to root dir with sources to be compiled
78
"-sourcepath dir" points to root dir with sources used only for linking
79
"-classpath dir" points to dir with classes used only for linking (as before)
80
81
** Use all cores for compilation by default.
82
"-j 4" limit the number of cores to 4.
83
For the moment, the sjavac server additionally limits the number of cores to three.
84
This will improve in the future when more sharing is performed between concurrent JavaCompilers.
85
86
** Basic translation support from other sources to java, and then compilation of the generated java.
87
This functionality might be moved into annotation processors instead.
88
Again this is driven by the OpenJDK sources where properties and a few other types of files
89
are converted into Java sources regularily. The javac_state embraces copy and tr, and perform
90
incremental recompiles and copying for these as well. META-INF will be a special copy rule
91
that will copy any files found below any META-INF dir in src to the bin/META-INF dir.
92
"-copy .gif"
93
"-copy META-INF"
94
"-tr .prop=com.sun.tools.javac.smart.CompileProperties
95
"-tr .propp=com.sun.tools.javac.smart.CompileProperties,java.util.ListResourceBundle
96
"-tr .proppp=com.sun.tools.javac.smart.CompileProperties,sun.util.resources.LocaleNamesBundle
97
98
** Control which classes in the src,sourcepath and classpath that javac is allowed to see.
99
Again, this is necessary to deal with the source code structure of the OpenJDK which is
100
intricate (read messy).
101
102
"-i tools.*" to include the tools package and all its subpackages in the build.
103
"-x tools.net.aviancarrier.*" to exclude the aviancarrier package and all its sources and subpackages.
104
"-x tools.net.drums" to exclude the drums package only, keep its subpackages.
105
"-xf tools/net/Bar.java" // Do not compile this file...
106
"-xf *Bor.java" // Do not compile Bor.java wherever it is found, BUT do compile ABor.java!
107
"-if tools/net/Bor.java" // Only compile this file...odd, but sometimes used.
108
109
** The smart javac wrapper is driven by the modification time on the source files and compared
110
to the modification times written into the javac_state file.
111
112
It does not compare the modification time of the source with the modification time of the artifact.
113
However it will detect if the modification time of an artifact has changed compared to the java_state,
114
and this will trigger a delete of the artifact and a subsequent recompile of the source.
115
116
The smart javac wrapper is not a generic makefile/ant system. Its purpose is to compile java source
117
as the final step before the output dir is finalized and immediately jared, or jmodded. The output
118
dir should be considered opaque. Do not write into the outputdir yourself!
119
Any artifacts found in the outputdir that javac_state does not know of, will be deleted!
120
This can however be prevented, using the switch --permit-unidentified-artifacts
121
This switch is necessary when build the OpenJDK because its makefiles still write directly to
122
the output classes dirs.
123
124
Any makefile/ant rules that want to put contents into the outputdir should put the content
125
in one of several source roots. Static content that is under version control, can be put in the same source
126
code tree as the Java sources. Dynamic content that is generated by make/ant on the fly, should
127
be put in a separate gensrc_stuff root. The smart javac wrapper call will then take the arguments:
128
"gensrc_stuff src -d bin"
129
130
The command line:
131
java -cp tools.jar com.sun.tools.sjavac.Main \
132
-i "com.bar.*" -x "com.bar.foo.*" \
133
first_root \
134
-i "com.bar.foo.*" \
135
second_root \
136
-x "org.net.*" \
137
-sourcepath link_root_sources \
138
-classpath link_root_classes \
139
-d bin
140
141
Will compile all sources for package com.bar and its subpackages, found below first_root,
142
except the package com.bar.foo (and its subpackages), for which the sources are picked
143
from second_root instead. It will link against classes in link_root_classes and against
144
sources in link_root_sources, but will not see (try to link against) sources matching org.net.*
145
but will link against org.net* classes (if they exist) in link_root_classes.
146
147
(If you want a set of complex filter rules to be applied to several source directories, without
148
having to repeat the the filter rules for each root. You can use the explicit -src option. For example:
149
sjavac -x "com.foo.*" -src root1:root2:root3 )
150
151
The resulting classes are written into bin.
152
*/
153
154
// This is the final destination for classes and copied files.
155
private File bin_dir;
156
// This is where the annotation process will put generated sources.
157
private File gensrc_dir;
158
// This is where javac -h puts the generated c-header files.
159
private File header_dir;
160
161
// This file contains the list of sources genereated by the makefile.
162
// We double check that our calculated list of sources matches this list,
163
// if not, then we terminate with an error!
164
private File makefile_source_list;
165
// The challenging task to manage an incremental build is done by javac_state.
166
private JavacState javac_state;
167
168
// The suffix rules tells you for example, that .java files should be compiled,
169
// and .html files should be copied and .properties files be translated.
170
Map<String,Transformer> suffix_rules;
171
172
public static void main(String... args) {
173
if (args.length > 0 && args[0].startsWith("--startserver:")) {
174
if (args.length>1) {
175
Log.error("When spawning a background server, only a single --startserver argument is allowed.");
176
return;
177
}
178
// Spawn a background server.
179
int rc = JavacServer.startServer(args[0], System.err);
180
System.exit(rc);
181
}
182
Main main = new Main();
183
int rc = main.go(args, System.out, System.err);
184
// Remove the portfile, but only if this background=false was used.
185
JavacServer.cleanup(args);
186
System.exit(rc);
187
}
188
189
private void printHelp() {
190
System.out.println("Usage: sjavac <options>\n"+
191
"where required options are:\n"+
192
"dir Compile all sources in dir recursively\n"+
193
"-d dir Store generated classes here and the javac_state file\n"+
194
"--server:portfile=/tmp/abc Use a background sjavac server\n\n"+
195
"All other arguments as javac, except -implicit:none which is forced by default.\n"+
196
"No java source files can be supplied on the command line, nor can an @file be supplied.\n\n"+
197
"Warning!\n"+
198
"This tool might disappear at any time, and its command line options might change at any time!");
199
}
200
201
public int go(String[] args, PrintStream out, PrintStream err) {
202
try {
203
if (args.length == 0 || findJavaSourceFiles(args) || findAtFile(args) || null==Util.findServerSettings(args)) {
204
printHelp();
205
return 0;
206
}
207
208
Log.setLogLevel(findLogLevel(args), out, err);
209
String server_settings = Util.findServerSettings(args);
210
args = verifyImplicitOption(args);
211
// Find the source root directories, and add the -src option before these, if not there already.
212
args = addSrcBeforeDirectories(args);
213
// Check that there is at least one -src supplied.
214
checkSrcOption(args);
215
// Check that there is one -d supplied.
216
bin_dir = findDirectoryOption(args,"-d","output", true, false, true);
217
gensrc_dir = findDirectoryOption(args,"-s","gensrc", false, false, true);
218
header_dir = findDirectoryOption(args,"-h","headers", false, false, true);
219
makefile_source_list = findFileOption(args,"--compare-found-sources","makefile source list", false);
220
221
// Load the prev build state database.
222
javac_state = JavacState.load(args, bin_dir, gensrc_dir, header_dir,
223
findBooleanOption(args, "--permit-unidentified-artifacts"), out, err);
224
225
// Setup the suffix rules from the command line.
226
suffix_rules = javac_state.getJavaSuffixRule();
227
findTranslateOptions(args, suffix_rules);
228
if (suffix_rules.keySet().size() > 1 && gensrc_dir == null) {
229
Log.error("You have translators but no gensrc dir (-s) specified!");
230
return -1;
231
}
232
findCopyOptions(args, suffix_rules);
233
234
// All found modules are put here.
235
Map<String,Module> modules = new HashMap<String,Module>();
236
// We start out in the legacy empty no-name module.
237
// As soon as we stumble on a module-info.java file we change to that module.
238
Module current_module = new Module("", "");
239
modules.put("", current_module);
240
241
// Find all sources, use the suffix rules to know which files are sources.
242
Map<String,Source> sources = new HashMap<String,Source>();
243
// Find the files, this will automatically populate the found modules
244
// with found packages where the sources are found!
245
findFiles(args, "-src", suffix_rules.keySet(), sources, modules, current_module, false);
246
247
if (sources.isEmpty()) {
248
Log.error("Found nothing to compile!");
249
return -1;
250
}
251
252
// Create a map of all source files that are available for linking. Both -src and
253
// -sourcepath point to such files. It is possible to specify multiple
254
// -sourcepath options to enable different filtering rules. If the
255
// filters are the same for multiple sourcepaths, they may be concatenated
256
// using :(;). Before sending the list of sourcepaths to javac, they are
257
// all concatenated. The list created here is used by the SmartFileWrapper to
258
// make sure only the correct sources are actually available.
259
// We might find more modules here as well.
260
Map<String,Source> sources_to_link_to = new HashMap<String,Source>();
261
findFiles(args, "-src", Util.set(".java"), sources_to_link_to, modules, current_module, true);
262
findFiles(args, "-sourcepath", Util.set(".java"), sources_to_link_to, modules, current_module, true);
263
// Rewrite the -src option to make it through to the javac instances.
264
rewriteOptions(args, "-src", "-sourcepath");
265
266
// Find all class files allowable for linking.
267
// And pickup knowledge of all modules found here.
268
// This cannot currently filter classes inside jar files.
269
// Map<String,Source> classes_to_link_to = new HashMap<String,Source>();
270
// findFiles(args, "-classpath", Util.set(".class"), classes_to_link_to, modules, current_module, true);
271
272
// Find all module sources allowable for linking.
273
// Map<String,Source> modules_to_link_to = new HashMap<String,Source>();
274
// findFiles(args, "-modulepath", Util.set(".class"), modules_to_link_to, modules, current_module, true);
275
276
// Add the set of sources to the build database.
277
javac_state.now().flattenPackagesSourcesAndArtifacts(modules);
278
javac_state.now().checkInternalState("checking sources", false, sources);
279
javac_state.now().checkInternalState("checking linked sources", true, sources_to_link_to);
280
javac_state.setVisibleSources(sources_to_link_to);
281
282
// If there is any change in the source files, taint packages
283
// and mark the database in need of saving.
284
javac_state.checkSourceStatus(false);
285
286
// Find all existing artifacts. Their timestamp will match the last modified timestamps stored
287
// in javac_state, simply because loading of the JavacState will clean out all artifacts
288
// that do not match the javac_state database.
289
javac_state.findAllArtifacts();
290
291
// Remove unidentified artifacts from the bin, gensrc and header dirs.
292
// (Unless we allow them to be there.)
293
// I.e. artifacts that are not known according to the build database (javac_state).
294
// For examples, files that have been manually copied into these dirs.
295
// Artifacts with bad timestamps (ie the on disk timestamp does not match the timestamp
296
// in javac_state) have already been removed when the javac_state was loaded.
297
if (!findBooleanOption(args, "--permit-unidentified-artifacts")) {
298
javac_state.removeUnidentifiedArtifacts();
299
}
300
// Go through all sources and taint all packages that miss artifacts.
301
javac_state.taintPackagesThatMissArtifacts();
302
303
// Now clean out all known artifacts belonging to tainted packages.
304
javac_state.deleteClassArtifactsInTaintedPackages();
305
// Copy files, for example property files, images files, xml files etc etc.
306
javac_state.performCopying(bin_dir, suffix_rules);
307
// Translate files, for example compile properties or compile idls.
308
javac_state.performTranslation(gensrc_dir, suffix_rules);
309
// Add any potentially generated java sources to the tobe compiled list.
310
// (Generated sources must always have a package.)
311
Map<String,Source> generated_sources = new HashMap<String,Source>();
312
Source.scanRoot(gensrc_dir, Util.set(".java"), null, null, null, null,
313
generated_sources, modules, current_module, false, true, false);
314
javac_state.now().flattenPackagesSourcesAndArtifacts(modules);
315
// Recheck the the source files and their timestamps again.
316
javac_state.checkSourceStatus(true);
317
318
// Now do a safety check that the list of source files is identical
319
// to the list Make believes we are compiling. If we do not get this
320
// right, then incremental builds will fail with subtility.
321
// If any difference is detected, then we will fail hard here.
322
// This is an important safety net.
323
javac_state.compareWithMakefileList(makefile_source_list);
324
325
// Do the compilations, repeatedly until no tainted packages exist.
326
boolean again;
327
// Collect the name of all compiled packages.
328
Set<String> recently_compiled = new HashSet<String>();
329
boolean[] rc = new boolean[1];
330
do {
331
// Clean out artifacts in tainted packages.
332
javac_state.deleteClassArtifactsInTaintedPackages();
333
again = javac_state.performJavaCompilations(bin_dir, server_settings, args, recently_compiled, rc);
334
if (!rc[0]) break;
335
} while (again);
336
// Only update the state if the compile went well.
337
if (rc[0]) {
338
javac_state.save();
339
// Reflatten only the artifacts.
340
javac_state.now().flattenArtifacts(modules);
341
// Remove artifacts that were generated during the last compile, but not this one.
342
javac_state.removeSuperfluousArtifacts(recently_compiled);
343
}
344
return rc[0] ? 0 : -1;
345
} catch (ProblemException e) {
346
Log.error(e.getMessage());
347
return -1;
348
} catch (Exception e) {
349
e.printStackTrace(err);
350
return -1;
351
}
352
}
353
354
/**
355
* Are java source files passed on the command line?
356
*/
357
private boolean findJavaSourceFiles(String[] args) {
358
String prev = "";
359
for (String s : args) {
360
if (s.endsWith(".java") && !prev.equals("-xf") && !prev.equals("-if")) {
361
return true;
362
}
363
prev = s;
364
}
365
return false;
366
}
367
368
/**
369
* Is an at file passed on the command line?
370
*/
371
private boolean findAtFile(String[] args) {
372
for (String s : args) {
373
if (s.startsWith("@")) {
374
return true;
375
}
376
}
377
return false;
378
}
379
380
/**
381
* Find the log level setting.
382
*/
383
private String findLogLevel(String[] args) {
384
for (String s : args) {
385
if (s.startsWith("--log=") && s.length()>6) {
386
return s.substring(6);
387
}
388
if (s.equals("-verbose")) {
389
return "info";
390
}
391
}
392
return "info";
393
}
394
395
/**
396
* Remove smart javac wrapper arguments, before feeding
397
* the args to the plain javac.
398
*/
399
static String[] removeWrapperArgs(String[] args) {
400
String[] out = new String[args.length];
401
// The first source path index is remembered
402
// here. So that all following can be concatenated to it.
403
int source_path = -1;
404
// The same for class path.
405
int class_path = -1;
406
// And module path.
407
int module_path = -1;
408
int j = 0;
409
for (int i = 0; i<args.length; ++i) {
410
if (args[i].equals("-src") ||
411
args[i].equals("-x") ||
412
args[i].equals("-i") ||
413
args[i].equals("-xf") ||
414
args[i].equals("-if") ||
415
args[i].equals("-copy") ||
416
args[i].equals("-tr") ||
417
args[i].equals("-j")) {
418
// Just skip it and skip following value
419
i++;
420
} else if (args[i].startsWith("--server:")) {
421
// Just skip it.
422
} else if (args[i].startsWith("--log=")) {
423
// Just skip it.
424
} else if (args[i].equals("--permit-unidentified-artifacts")) {
425
// Just skip it.
426
} else if (args[i].equals("--permit-sources-without-package")) {
427
// Just skip it.
428
} else if (args[i].equals("--compare-found-sources")) {
429
// Just skip it and skip verify file name
430
i++;
431
} else if (args[i].equals("-sourcepath")) {
432
if (source_path == -1) {
433
source_path = j;
434
out[j] = args[i];
435
out[j+1] = args[i+1];
436
j+=2;
437
i++;
438
} else {
439
// Skip this and its argument, but
440
// append argument to found sourcepath.
441
out[source_path+1] = out[source_path+1]+File.pathSeparatorChar+args[i+1];
442
i++;
443
}
444
} else if (args[i].equals("-classpath") || args[i].equals("-cp")) {
445
if (class_path == -1) {
446
class_path = j;
447
out[j] = args[i];
448
out[j+1] = args[i+1];
449
j+=2;
450
i++;
451
} else {
452
// Skip this and its argument, but
453
// append argument to found sourcepath.
454
out[class_path+1] = out[class_path+1]+File.pathSeparatorChar+args[i+1];
455
i++;
456
}
457
} else if (args[i].equals("-modulepath")) {
458
if (module_path == -1) {
459
module_path = j;
460
out[j] = args[i];
461
out[j+1] = args[i+1];
462
j+=2;
463
i++;
464
} else {
465
// Skip this and its argument, but
466
// append argument to found sourcepath.
467
out[module_path+1] = out[module_path+1]+File.pathSeparatorChar+args[i+1];
468
i++;
469
}
470
} else {
471
// Copy argument.
472
out[j] = args[i];
473
j++;
474
}
475
}
476
String[] ret = new String[j];
477
System.arraycopy(out, 0, ret, 0, j);
478
return ret;
479
}
480
481
/**
482
* Make sure directory exist, create it if not.
483
*/
484
private static boolean makeSureExists(File dir) {
485
// Make sure the dest directories exist.
486
if (!dir.exists()) {
487
if (!dir.mkdirs()) {
488
Log.error("Could not create the directory "+dir.getPath());
489
return false;
490
}
491
}
492
return true;
493
}
494
495
/**
496
* Verify that a package pattern is valid.
497
*/
498
private static void checkPattern(String s) throws ProblemException {
499
// Package names like foo.bar.gamma are allowed, and
500
// package names suffixed with .* like foo.bar.* are
501
// also allowed.
502
Pattern p = Pattern.compile("[a-zA-Z_]{1}[a-zA-Z0-9_]*(\\.[a-zA-Z_]{1}[a-zA-Z0-9_]*)*(\\.\\*)?+");
503
Matcher m = p.matcher(s);
504
if (!m.matches()) {
505
throw new ProblemException("The string \""+s+"\" is not a proper package name pattern.");
506
}
507
}
508
509
/**
510
* Verify that a translate pattern is valid.
511
*/
512
private static void checkTranslatePattern(String s) throws ProblemException {
513
// .prop=com.sun.tools.javac.smart.CompileProperties
514
// .idl=com.sun.corba.CompileIdl
515
// .g3=antlr.CompileGrammar,debug=true
516
Pattern p = Pattern.compile(
517
"\\.[a-zA-Z_]{1}[a-zA-Z0-9_]*=[a-z_]{1}[a-z0-9_]*(\\.[a-z_]{1}[a-z0-9_]*)*"+
518
"(\\.[a-zA-Z_]{1}[a-zA-Z0-9_]*)(,.*)?");
519
Matcher m = p.matcher(s);
520
if (!m.matches()) {
521
throw new ProblemException("The string \""+s+"\" is not a proper translate pattern.");
522
}
523
}
524
525
/**
526
* Verify that a copy pattern is valid.
527
*/
528
private static void checkCopyPattern(String s) throws ProblemException {
529
// .gif
530
// .html
531
Pattern p = Pattern.compile(
532
"\\.[a-zA-Z_]{1}[a-zA-Z0-9_]*");
533
Matcher m = p.matcher(s);
534
if (!m.matches()) {
535
throw new ProblemException("The string \""+s+"\" is not a proper suffix.");
536
}
537
}
538
539
/**
540
* Verify that a source file name is valid.
541
*/
542
private static void checkFilePattern(String s) throws ProblemException {
543
// File names like foo/bar/gamma/Bar.java are allowed,
544
// as well as /bar/jndi.properties as well as,
545
// */bar/Foo.java
546
Pattern p = null;
547
if (File.separatorChar == '\\') {
548
p = Pattern.compile("\\*?(.+\\\\)*.+");
549
}
550
else if (File.separatorChar == '/') {
551
p = Pattern.compile("\\*?(.+/)*.+");
552
} else {
553
throw new ProblemException("This platform uses the unsupported "+File.separatorChar+
554
" as file separator character. Please add support for it!");
555
}
556
Matcher m = p.matcher(s);
557
if (!m.matches()) {
558
throw new ProblemException("The string \""+s+"\" is not a proper file name.");
559
}
560
}
561
562
/**
563
* Scan the arguments to find an option is used.
564
*/
565
private static boolean hasOption(String[] args, String option) {
566
for (String a : args) {
567
if (a.equals(option)) return true;
568
}
569
return false;
570
}
571
572
/**
573
* Check if -implicit is supplied, if so check that it is none.
574
* If -implicit is not supplied, supply -implicit:none
575
* Only implicit:none is allowed because otherwise the multicore compilations
576
* and dependency tracking will be tangled up.
577
*/
578
private static String[] verifyImplicitOption(String[] args)
579
throws ProblemException {
580
581
boolean foundImplicit = false;
582
for (String a : args) {
583
if (a.startsWith("-implicit:")) {
584
foundImplicit = true;
585
if (!a.equals("-implicit:none")) {
586
throw new ProblemException("The only allowed setting for sjavac is -implicit:none, it is also the default.");
587
}
588
}
589
}
590
if (foundImplicit) {
591
return args;
592
}
593
// -implicit:none not found lets add it.
594
String[] newargs = new String[args.length+1];
595
System.arraycopy(args,0, newargs, 0, args.length);
596
newargs[args.length] = "-implicit:none";
597
return newargs;
598
}
599
600
/**
601
* Rewrite a single option into something else.
602
*/
603
private static void rewriteOptions(String[] args, String option, String new_option) {
604
for (int i=0; i<args.length; ++i) {
605
if (args[i].equals(option)) {
606
args[i] = new_option;
607
}
608
}
609
}
610
611
/**
612
* Scan the arguments to find an option that specifies a directory.
613
* Create the directory if necessary.
614
*/
615
private static File findDirectoryOption(String[] args, String option, String name, boolean needed, boolean allow_dups, boolean create)
616
throws ProblemException, ProblemException {
617
File dir = null;
618
for (int i = 0; i<args.length; ++i) {
619
if (args[i].equals(option)) {
620
if (dir != null) {
621
throw new ProblemException("You have already specified the "+name+" dir!");
622
}
623
if (i+1 >= args.length) {
624
throw new ProblemException("You have to specify a directory following "+option+".");
625
}
626
if (args[i+1].indexOf(File.pathSeparatorChar) != -1) {
627
throw new ProblemException("You must only specify a single directory for "+option+".");
628
}
629
dir = new File(args[i+1]);
630
if (!dir.exists()) {
631
if (!create) {
632
throw new ProblemException("This directory does not exist: "+dir.getPath());
633
} else
634
if (!makeSureExists(dir)) {
635
throw new ProblemException("Cannot create directory "+dir.getPath());
636
}
637
}
638
if (!dir.isDirectory()) {
639
throw new ProblemException("\""+args[i+1]+"\" is not a directory.");
640
}
641
}
642
}
643
if (dir == null && needed) {
644
throw new ProblemException("You have to specify "+option);
645
}
646
try {
647
if (dir != null)
648
return dir.getCanonicalFile();
649
} catch (IOException e) {
650
throw new ProblemException(""+e);
651
}
652
return null;
653
}
654
655
/**
656
* Option is followed by path.
657
*/
658
private static boolean shouldBeFollowedByPath(String o) {
659
return o.equals("-s") ||
660
o.equals("-h") ||
661
o.equals("-d") ||
662
o.equals("-sourcepath") ||
663
o.equals("-classpath") ||
664
o.equals("-cp") ||
665
o.equals("-bootclasspath") ||
666
o.equals("-src");
667
}
668
669
/**
670
* Add -src before source root directories if not already there.
671
*/
672
private static String[] addSrcBeforeDirectories(String[] args) {
673
List<String> newargs = new ArrayList<String>();
674
for (int i = 0; i<args.length; ++i) {
675
File dir = new File(args[i]);
676
if (dir.exists() && dir.isDirectory()) {
677
if (i == 0 || !shouldBeFollowedByPath(args[i-1])) {
678
newargs.add("-src");
679
}
680
}
681
newargs.add(args[i]);
682
}
683
return newargs.toArray(new String[0]);
684
}
685
686
/**
687
* Check the -src options.
688
*/
689
private static void checkSrcOption(String[] args)
690
throws ProblemException {
691
Set<File> dirs = new HashSet<File>();
692
for (int i = 0; i<args.length; ++i) {
693
if (args[i].equals("-src")) {
694
if (i+1 >= args.length) {
695
throw new ProblemException("You have to specify a directory following -src.");
696
}
697
StringTokenizer st = new StringTokenizer(args[i+1], File.pathSeparator);
698
while (st.hasMoreElements()) {
699
File dir = new File(st.nextToken());
700
if (!dir.exists()) {
701
throw new ProblemException("This directory does not exist: "+dir.getPath());
702
}
703
if (!dir.isDirectory()) {
704
throw new ProblemException("\""+dir.getPath()+"\" is not a directory.");
705
}
706
if (dirs.contains(dir)) {
707
throw new ProblemException("The src directory \""+dir.getPath()+"\" is specified more than once!");
708
}
709
dirs.add(dir);
710
}
711
}
712
}
713
if (dirs.isEmpty()) {
714
throw new ProblemException("You have to specify -src.");
715
}
716
}
717
718
/**
719
* Scan the arguments to find an option that specifies a file.
720
*/
721
private static File findFileOption(String[] args, String option, String name, boolean needed)
722
throws ProblemException, ProblemException {
723
File file = null;
724
for (int i = 0; i<args.length; ++i) {
725
if (args[i].equals(option)) {
726
if (file != null) {
727
throw new ProblemException("You have already specified the "+name+" file!");
728
}
729
if (i+1 >= args.length) {
730
throw new ProblemException("You have to specify a file following "+option+".");
731
}
732
file = new File(args[i+1]);
733
if (file.isDirectory()) {
734
throw new ProblemException("\""+args[i+1]+"\" is not a file.");
735
}
736
if (!file.exists() && needed) {
737
throw new ProblemException("The file \""+args[i+1]+"\" does not exist.");
738
}
739
740
}
741
}
742
if (file == null && needed) {
743
throw new ProblemException("You have to specify "+option);
744
}
745
return file;
746
}
747
748
/**
749
* Look for a specific switch, return true if found.
750
*/
751
public static boolean findBooleanOption(String[] args, String option) {
752
for (int i = 0; i<args.length; ++i) {
753
if (args[i].equals(option)) return true;
754
}
755
return false;
756
}
757
758
/**
759
* Scan the arguments to find an option that specifies a number.
760
*/
761
public static int findNumberOption(String[] args, String option) {
762
int rc = 0;
763
for (int i = 0; i<args.length; ++i) {
764
if (args[i].equals(option)) {
765
if (args.length > i+1) {
766
rc = Integer.parseInt(args[i+1]);
767
}
768
}
769
}
770
return rc;
771
}
772
773
/**
774
* Scan the arguments to find the option (-tr) that setup translation rules to java source
775
* from different sources. For example: .properties are translated using CompileProperties
776
* The found translators are stored as suffix rules.
777
*/
778
private static void findTranslateOptions(String[] args, Map<String,Transformer> suffix_rules)
779
throws ProblemException, ProblemException {
780
781
for (int i = 0; i<args.length; ++i) {
782
if (args[i].equals("-tr")) {
783
if (i+1 >= args.length) {
784
throw new ProblemException("You have to specify a translate rule following -tr.");
785
}
786
String s = args[i+1];
787
checkTranslatePattern(s);
788
int ep = s.indexOf("=");
789
String suffix = s.substring(0,ep);
790
String classname = s.substring(ep+1);
791
if (suffix_rules.get(suffix) != null) {
792
throw new ProblemException("You have already specified a "+
793
"rule for the suffix "+suffix);
794
}
795
if (s.equals(".class")) {
796
throw new ProblemException("You cannot have a translator for .class files!");
797
}
798
if (s.equals(".java")) {
799
throw new ProblemException("You cannot have a translator for .java files!");
800
}
801
String extra = null;
802
int exp = classname.indexOf(",");
803
if (exp != -1) {
804
extra = classname.substring(exp+1);
805
classname = classname.substring(0,exp);
806
}
807
try {
808
Class<?> cl = Class.forName(classname);
809
Transformer t = (Transformer)cl.newInstance();
810
t.setExtra(extra);
811
suffix_rules.put(suffix, t);
812
}
813
catch (Exception e) {
814
throw new ProblemException("Cannot use "+classname+" as a translator!");
815
}
816
}
817
}
818
}
819
820
/**
821
* Scan the arguments to find the option (-copy) that setup copying rules into the bin dir.
822
* For example: -copy .html
823
* The found copiers are stored as suffix rules as well. No translation is done, just copying.
824
*/
825
private void findCopyOptions(String[] args, Map<String,Transformer> suffix_rules)
826
throws ProblemException, ProblemException {
827
828
for (int i = 0; i<args.length; ++i) {
829
if (args[i].equals("-copy")) {
830
if (i+1 >= args.length) {
831
throw new ProblemException("You have to specify a translate rule following -tr.");
832
}
833
String s = args[i+1];
834
checkCopyPattern(s);
835
if (suffix_rules.get(s) != null) {
836
throw new ProblemException("You have already specified a "+
837
"rule for the suffix "+s);
838
}
839
if (s.equals(".class")) {
840
throw new ProblemException("You cannot have a copy rule for .class files!");
841
}
842
if (s.equals(".java")) {
843
throw new ProblemException("You cannot have a copy rule for .java files!");
844
}
845
suffix_rules.put(s, javac_state.getCopier());
846
}
847
}
848
}
849
850
/**
851
* Rewrite a / separated path into \ separated, but only
852
* if we are running on a platform were File.separatorChar=='\', ie winapi.
853
*/
854
private String fixupSeparator(String p) {
855
if (File.separatorChar == '/') return p;
856
return p.replaceAll("/", "\\\\");
857
}
858
859
/**
860
* Scan the arguments for -i -x -xf -if followed by the option
861
* -src, -sourcepath, -modulepath or -classpath and produce a map of all the
862
* files to referenced for that particular option.
863
*
864
* Store the found sources and the found modules in the supplied maps.
865
*/
866
private boolean findFiles(String[] args, String option, Set<String> suffixes,
867
Map<String,Source> found_files, Map<String, Module> found_modules,
868
Module current_module, boolean inLinksrc)
869
throws ProblemException, ProblemException
870
{
871
// Track which source roots, source path roots and class path roots have been added.
872
Set<File> roots = new HashSet<File>();
873
// Track the current set of package includes,excludes as well as excluded source files,
874
// to be used in the next -src/-sourcepath/-classpath
875
List<String> includes = new LinkedList<String>();
876
List<String> excludes = new LinkedList<String>();
877
List<String> excludefiles = new LinkedList<String>();
878
List<String> includefiles = new LinkedList<String>();
879
// This include is used to find all modules in the source.
880
List<String> moduleinfo = new LinkedList<String>();
881
moduleinfo.add("module-info.java");
882
883
for (int i = 0; i<args.length; ++i) {
884
if (args[i].equals("-i")) {
885
if (i+1 >= args.length) {
886
throw new ProblemException("You have to specify a package pattern following -i");
887
}
888
String incl = args[i+1];
889
checkPattern(incl);
890
includes.add(incl);
891
}
892
if (args[i].equals("-x")) {
893
if (i+1 >= args.length) {
894
throw new ProblemException("You have to specify a package pattern following -x");
895
}
896
String excl = args[i+1];
897
checkPattern(excl);
898
excludes.add(excl);
899
}
900
if (args[i].equals("-xf")) {
901
if (i+1 >= args.length) {
902
throw new ProblemException("You have to specify a file following -xf");
903
}
904
String exclf = args[i+1];
905
checkFilePattern(exclf);
906
exclf = Util.normalizeDriveLetter(exclf);
907
excludefiles.add(fixupSeparator(exclf));
908
}
909
if (args[i].equals("-if")) {
910
if (i+1 >= args.length) {
911
throw new ProblemException("You have to specify a file following -xf");
912
}
913
String inclf = args[i+1];
914
checkFilePattern(inclf);
915
inclf = Util.normalizeDriveLetter(inclf);
916
includefiles.add(fixupSeparator(inclf));
917
}
918
if (args[i].equals(option)) {
919
if (i+1 >= args.length) {
920
throw new ProblemException("You have to specify a directory following "+option);
921
}
922
String[] root_dirs = args[i+1].split(File.pathSeparator);
923
for (String r : root_dirs) {
924
File root = new File(r);
925
if (!root.isDirectory()) {
926
throw new ProblemException("\""+r+"\" is not a directory.");
927
}
928
try {
929
root = root.getCanonicalFile();
930
} catch (IOException e) {
931
throw new ProblemException(""+e);
932
}
933
if (roots.contains(root)) {
934
throw new ProblemException("\""+r+"\" has already been used for "+option);
935
}
936
if (root.equals(bin_dir)) {
937
throw new ProblemException("\""+r+"\" cannot be used both for "+option+" and -d");
938
}
939
if (root.equals(gensrc_dir)) {
940
throw new ProblemException("\""+r+"\" cannot be used both for "+option+" and -s");
941
}
942
if (root.equals(header_dir)) {
943
throw new ProblemException("\""+r+"\" cannot be used both for "+option+" and -h");
944
}
945
roots.add(root);
946
Source.scanRoot(root, suffixes, excludes, includes, excludefiles, includefiles,
947
found_files, found_modules, current_module,
948
findBooleanOption(args, "--permit-sources-without-package"),
949
false, inLinksrc);
950
}
951
}
952
if (args[i].equals("-src") ||
953
args[i].equals("-sourcepath") ||
954
args[i].equals("-modulepath") ||
955
args[i].equals("-classpath") ||
956
args[i].equals("-cp"))
957
{
958
// Reset the includes,excludes and excludefiles after they have been used.
959
includes = new LinkedList<String>();
960
excludes = new LinkedList<String>();
961
excludefiles = new LinkedList<String>();
962
includefiles = new LinkedList<String>();
963
}
964
}
965
return true;
966
}
967
968
}
969
970
971