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/javah/JavahTask.java
38899 views
1
/*
2
* Copyright (c) 2002, 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.javah;
27
28
import java.io.File;
29
import java.io.FileNotFoundException;
30
import java.io.IOException;
31
import java.io.OutputStream;
32
import java.io.PrintWriter;
33
import java.io.Writer;
34
import java.text.MessageFormat;
35
import java.util.ArrayList;
36
import java.util.Arrays;
37
import java.util.Collections;
38
import java.util.HashMap;
39
import java.util.Iterator;
40
import java.util.LinkedHashSet;
41
import java.util.List;
42
import java.util.Locale;
43
import java.util.Map;
44
import java.util.MissingResourceException;
45
import java.util.ResourceBundle;
46
import java.util.Set;
47
48
import javax.annotation.processing.AbstractProcessor;
49
import javax.annotation.processing.Messager;
50
import javax.annotation.processing.ProcessingEnvironment;
51
import javax.annotation.processing.RoundEnvironment;
52
import javax.annotation.processing.SupportedAnnotationTypes;
53
54
import javax.lang.model.SourceVersion;
55
import javax.lang.model.element.ExecutableElement;
56
import javax.lang.model.element.TypeElement;
57
import javax.lang.model.element.VariableElement;
58
import javax.lang.model.type.ArrayType;
59
import javax.lang.model.type.DeclaredType;
60
import javax.lang.model.type.TypeMirror;
61
import javax.lang.model.type.TypeVisitor;
62
import javax.lang.model.util.ElementFilter;
63
import javax.lang.model.util.SimpleTypeVisitor8;
64
import javax.lang.model.util.Types;
65
66
import javax.tools.Diagnostic;
67
import javax.tools.DiagnosticListener;
68
import javax.tools.JavaCompiler;
69
import javax.tools.JavaCompiler.CompilationTask;
70
import javax.tools.JavaFileManager;
71
import javax.tools.JavaFileObject;
72
import javax.tools.StandardJavaFileManager;
73
import javax.tools.StandardLocation;
74
import javax.tools.ToolProvider;
75
import static javax.tools.Diagnostic.Kind.*;
76
77
import com.sun.tools.javac.code.Symbol.CompletionFailure;
78
import com.sun.tools.javac.main.CommandLine;
79
80
/**
81
* Javah generates support files for native methods.
82
* Parse commandline options and invokes javadoc to execute those commands.
83
*
84
* <p><b>This is NOT part of any supported API.
85
* If you write code that depends on this, you do so at your own
86
* risk. This code and its internal interfaces are subject to change
87
* or deletion without notice.</b></p>
88
*
89
* @author Sucheta Dambalkar
90
* @author Jonathan Gibbons
91
*/
92
public class JavahTask implements NativeHeaderTool.NativeHeaderTask {
93
public class BadArgs extends Exception {
94
private static final long serialVersionUID = 1479361270874789045L;
95
BadArgs(String key, Object... args) {
96
super(JavahTask.this.getMessage(key, args));
97
this.key = key;
98
this.args = args;
99
}
100
101
BadArgs showUsage(boolean b) {
102
showUsage = b;
103
return this;
104
}
105
106
final String key;
107
final Object[] args;
108
boolean showUsage;
109
}
110
111
static abstract class Option {
112
Option(boolean hasArg, String... aliases) {
113
this.hasArg = hasArg;
114
this.aliases = aliases;
115
}
116
117
boolean isHidden() {
118
return false;
119
}
120
121
boolean matches(String opt) {
122
for (String a: aliases) {
123
if (a.equals(opt))
124
return true;
125
}
126
return false;
127
}
128
129
boolean ignoreRest() {
130
return false;
131
}
132
133
abstract void process(JavahTask task, String opt, String arg) throws BadArgs;
134
135
final boolean hasArg;
136
final String[] aliases;
137
}
138
139
static abstract class HiddenOption extends Option {
140
HiddenOption(boolean hasArg, String... aliases) {
141
super(hasArg, aliases);
142
}
143
144
@Override
145
boolean isHidden() {
146
return true;
147
}
148
}
149
150
static final Option[] recognizedOptions = {
151
new Option(true, "-o") {
152
void process(JavahTask task, String opt, String arg) {
153
task.ofile = new File(arg);
154
}
155
},
156
157
new Option(true, "-d") {
158
void process(JavahTask task, String opt, String arg) {
159
task.odir = new File(arg);
160
}
161
},
162
163
new HiddenOption(true, "-td") {
164
void process(JavahTask task, String opt, String arg) {
165
// ignored; for backwards compatibility
166
}
167
},
168
169
new HiddenOption(false, "-stubs") {
170
void process(JavahTask task, String opt, String arg) {
171
// ignored; for backwards compatibility
172
}
173
},
174
175
new Option(false, "-v", "-verbose") {
176
void process(JavahTask task, String opt, String arg) {
177
task.verbose = true;
178
}
179
},
180
181
new Option(false, "-h", "-help", "--help", "-?") {
182
void process(JavahTask task, String opt, String arg) {
183
task.help = true;
184
}
185
},
186
187
new HiddenOption(false, "-trace") {
188
void process(JavahTask task, String opt, String arg) {
189
task.trace = true;
190
}
191
},
192
193
new Option(false, "-version") {
194
void process(JavahTask task, String opt, String arg) {
195
task.version = true;
196
}
197
},
198
199
new HiddenOption(false, "-fullversion") {
200
void process(JavahTask task, String opt, String arg) {
201
task.fullVersion = true;
202
}
203
},
204
205
new Option(false, "-jni") {
206
void process(JavahTask task, String opt, String arg) {
207
task.jni = true;
208
}
209
},
210
211
new Option(false, "-force") {
212
void process(JavahTask task, String opt, String arg) {
213
task.force = true;
214
}
215
},
216
217
new HiddenOption(false, "-Xnew") {
218
void process(JavahTask task, String opt, String arg) {
219
// we're already using the new javah
220
}
221
},
222
223
new HiddenOption(false, "-llni", "-Xllni") {
224
void process(JavahTask task, String opt, String arg) {
225
task.llni = true;
226
}
227
},
228
229
new HiddenOption(false, "-llnidouble") {
230
void process(JavahTask task, String opt, String arg) {
231
task.llni = true;
232
task.doubleAlign = true;
233
}
234
},
235
236
new HiddenOption(false) {
237
boolean matches(String opt) {
238
return opt.startsWith("-XD");
239
}
240
void process(JavahTask task, String opt, String arg) {
241
task.javac_extras.add(opt);
242
}
243
},
244
};
245
246
JavahTask() {
247
}
248
249
JavahTask(Writer out,
250
JavaFileManager fileManager,
251
DiagnosticListener<? super JavaFileObject> diagnosticListener,
252
Iterable<String> options,
253
Iterable<String> classes) {
254
this();
255
this.log = getPrintWriterForWriter(out);
256
this.fileManager = fileManager;
257
this.diagnosticListener = diagnosticListener;
258
259
try {
260
handleOptions(options, false);
261
} catch (BadArgs e) {
262
throw new IllegalArgumentException(e.getMessage());
263
}
264
265
this.classes = new ArrayList<String>();
266
if (classes != null) {
267
for (String classname: classes) {
268
classname.getClass(); // null-check
269
this.classes.add(classname);
270
}
271
}
272
}
273
274
public void setLocale(Locale locale) {
275
if (locale == null)
276
locale = Locale.getDefault();
277
task_locale = locale;
278
}
279
280
public void setLog(PrintWriter log) {
281
this.log = log;
282
}
283
284
public void setLog(OutputStream s) {
285
setLog(getPrintWriterForStream(s));
286
}
287
288
static PrintWriter getPrintWriterForStream(OutputStream s) {
289
return new PrintWriter(s, true);
290
}
291
292
static PrintWriter getPrintWriterForWriter(Writer w) {
293
if (w == null)
294
return getPrintWriterForStream(null);
295
else if (w instanceof PrintWriter)
296
return (PrintWriter) w;
297
else
298
return new PrintWriter(w, true);
299
}
300
301
public void setDiagnosticListener(DiagnosticListener<? super JavaFileObject> dl) {
302
diagnosticListener = dl;
303
}
304
305
public void setDiagnosticListener(OutputStream s) {
306
setDiagnosticListener(getDiagnosticListenerForStream(s));
307
}
308
309
private DiagnosticListener<JavaFileObject> getDiagnosticListenerForStream(OutputStream s) {
310
return getDiagnosticListenerForWriter(getPrintWriterForStream(s));
311
}
312
313
private DiagnosticListener<JavaFileObject> getDiagnosticListenerForWriter(Writer w) {
314
final PrintWriter pw = getPrintWriterForWriter(w);
315
return new DiagnosticListener<JavaFileObject> () {
316
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
317
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
318
pw.print(getMessage("err.prefix"));
319
pw.print(" ");
320
}
321
pw.println(diagnostic.getMessage(null));
322
}
323
};
324
}
325
326
int run(String[] args) {
327
try {
328
handleOptions(args);
329
boolean ok = run();
330
return ok ? 0 : 1;
331
} catch (BadArgs e) {
332
diagnosticListener.report(createDiagnostic(e.key, e.args));
333
return 1;
334
} catch (InternalError e) {
335
diagnosticListener.report(createDiagnostic("err.internal.error", e.getMessage()));
336
return 1;
337
} catch (Util.Exit e) {
338
return e.exitValue;
339
} finally {
340
log.flush();
341
}
342
}
343
344
public void handleOptions(String[] args) throws BadArgs {
345
handleOptions(Arrays.asList(args), true);
346
}
347
348
private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs {
349
if (log == null) {
350
log = getPrintWriterForStream(System.out);
351
if (diagnosticListener == null)
352
diagnosticListener = getDiagnosticListenerForStream(System.err);
353
} else {
354
if (diagnosticListener == null)
355
diagnosticListener = getDiagnosticListenerForWriter(log);
356
}
357
358
if (fileManager == null)
359
fileManager = getDefaultFileManager(diagnosticListener, log);
360
361
Iterator<String> iter = expandAtArgs(args).iterator();
362
noArgs = !iter.hasNext();
363
364
while (iter.hasNext()) {
365
String arg = iter.next();
366
if (arg.startsWith("-"))
367
handleOption(arg, iter);
368
else if (allowClasses) {
369
if (classes == null)
370
classes = new ArrayList<String>();
371
classes.add(arg);
372
while (iter.hasNext())
373
classes.add(iter.next());
374
} else
375
throw new BadArgs("err.unknown.option", arg).showUsage(true);
376
}
377
378
if ((classes == null || classes.size() == 0) &&
379
!(noArgs || help || version || fullVersion)) {
380
throw new BadArgs("err.no.classes.specified");
381
}
382
383
if (jni && llni)
384
throw new BadArgs("jni.llni.mixed");
385
386
if (odir != null && ofile != null)
387
throw new BadArgs("dir.file.mixed");
388
}
389
390
private void handleOption(String name, Iterator<String> rest) throws BadArgs {
391
for (Option o: recognizedOptions) {
392
if (o.matches(name)) {
393
if (o.hasArg) {
394
if (rest.hasNext())
395
o.process(this, name, rest.next());
396
else
397
throw new BadArgs("err.missing.arg", name).showUsage(true);
398
} else
399
o.process(this, name, null);
400
401
if (o.ignoreRest()) {
402
while (rest.hasNext())
403
rest.next();
404
}
405
return;
406
}
407
}
408
409
if (fileManager.handleOption(name, rest))
410
return;
411
412
throw new BadArgs("err.unknown.option", name).showUsage(true);
413
}
414
415
private Iterable<String> expandAtArgs(Iterable<String> args) throws BadArgs {
416
try {
417
List<String> l = new ArrayList<String>();
418
for (String arg: args) l.add(arg);
419
return Arrays.asList(CommandLine.parse(l.toArray(new String[l.size()])));
420
} catch (FileNotFoundException e) {
421
throw new BadArgs("at.args.file.not.found", e.getLocalizedMessage());
422
} catch (IOException e) {
423
throw new BadArgs("at.args.io.exception", e.getLocalizedMessage());
424
}
425
}
426
427
public Boolean call() {
428
return run();
429
}
430
431
public boolean run() throws Util.Exit {
432
433
Util util = new Util(log, diagnosticListener);
434
435
if (noArgs || help) {
436
showHelp();
437
return help; // treat noArgs as an error for purposes of exit code
438
}
439
440
if (version || fullVersion) {
441
showVersion(fullVersion);
442
return true;
443
}
444
445
util.verbose = verbose;
446
447
Gen g;
448
449
if (llni)
450
g = new LLNI(doubleAlign, util);
451
else {
452
// if (stubs)
453
// throw new BadArgs("jni.no.stubs");
454
g = new JNI(util);
455
}
456
457
if (ofile != null) {
458
if (!(fileManager instanceof StandardJavaFileManager)) {
459
diagnosticListener.report(createDiagnostic("err.cant.use.option.for.fm", "-o"));
460
return false;
461
}
462
Iterable<? extends JavaFileObject> iter =
463
((StandardJavaFileManager) fileManager).getJavaFileObjectsFromFiles(Collections.singleton(ofile));
464
JavaFileObject fo = iter.iterator().next();
465
g.setOutFile(fo);
466
} else {
467
if (odir != null) {
468
if (!(fileManager instanceof StandardJavaFileManager)) {
469
diagnosticListener.report(createDiagnostic("err.cant.use.option.for.fm", "-d"));
470
return false;
471
}
472
473
if (!odir.exists())
474
if (!odir.mkdirs())
475
util.error("cant.create.dir", odir.toString());
476
try {
477
((StandardJavaFileManager) fileManager).setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(odir));
478
} catch (IOException e) {
479
Object msg = e.getLocalizedMessage();
480
if (msg == null) {
481
msg = e;
482
}
483
diagnosticListener.report(createDiagnostic("err.ioerror", odir, msg));
484
return false;
485
}
486
}
487
g.setFileManager(fileManager);
488
}
489
490
/*
491
* Force set to false will turn off smarts about checking file
492
* content before writing.
493
*/
494
g.setForce(force);
495
496
if (fileManager instanceof JavahFileManager)
497
((JavahFileManager) fileManager).setSymbolFileEnabled(false);
498
499
JavaCompiler c = ToolProvider.getSystemJavaCompiler();
500
List<String> opts = new ArrayList<String>();
501
opts.add("-proc:only");
502
opts.addAll(javac_extras);
503
CompilationTask t = c.getTask(log, fileManager, diagnosticListener, opts, classes, null);
504
JavahProcessor p = new JavahProcessor(g);
505
t.setProcessors(Collections.singleton(p));
506
507
boolean ok = t.call();
508
if (p.exit != null)
509
throw new Util.Exit(p.exit);
510
return ok;
511
}
512
513
private List<File> pathToFiles(String path) {
514
List<File> files = new ArrayList<File>();
515
for (String f: path.split(File.pathSeparator)) {
516
if (f.length() > 0)
517
files.add(new File(f));
518
}
519
return files;
520
}
521
522
static StandardJavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) {
523
return JavahFileManager.create(dl, log);
524
}
525
526
private void showHelp() {
527
log.println(getMessage("main.usage", progname));
528
for (Option o: recognizedOptions) {
529
if (o.isHidden())
530
continue;
531
String name = o.aliases[0].substring(1); // there must always be at least one name
532
log.println(getMessage("main.opt." + name));
533
}
534
String[] fmOptions = { "-classpath", "-cp", "-bootclasspath" };
535
for (String o: fmOptions) {
536
if (fileManager.isSupportedOption(o) == -1)
537
continue;
538
String name = o.substring(1);
539
log.println(getMessage("main.opt." + name));
540
}
541
log.println(getMessage("main.usage.foot"));
542
}
543
544
private void showVersion(boolean full) {
545
log.println(version(full));
546
}
547
548
private static final String versionRBName = "com.sun.tools.javah.resources.version";
549
private static ResourceBundle versionRB;
550
551
private String version(boolean full) {
552
String msgKey = (full ? "javah.fullVersion" : "javah.version");
553
String versionKey = (full ? "full" : "release");
554
// versionKey=product: mm.nn.oo[-milestone]
555
// versionKey=full: mm.mm.oo[-milestone]-build
556
if (versionRB == null) {
557
try {
558
versionRB = ResourceBundle.getBundle(versionRBName);
559
} catch (MissingResourceException e) {
560
return getMessage("version.resource.missing", System.getProperty("java.version"));
561
}
562
}
563
try {
564
return getMessage(msgKey, "javah", versionRB.getString(versionKey));
565
}
566
catch (MissingResourceException e) {
567
return getMessage("version.unknown", System.getProperty("java.version"));
568
}
569
}
570
571
private Diagnostic<JavaFileObject> createDiagnostic(final String key, final Object... args) {
572
return new Diagnostic<JavaFileObject>() {
573
public Kind getKind() {
574
return Diagnostic.Kind.ERROR;
575
}
576
577
public JavaFileObject getSource() {
578
return null;
579
}
580
581
public long getPosition() {
582
return Diagnostic.NOPOS;
583
}
584
585
public long getStartPosition() {
586
return Diagnostic.NOPOS;
587
}
588
589
public long getEndPosition() {
590
return Diagnostic.NOPOS;
591
}
592
593
public long getLineNumber() {
594
return Diagnostic.NOPOS;
595
}
596
597
public long getColumnNumber() {
598
return Diagnostic.NOPOS;
599
}
600
601
public String getCode() {
602
return key;
603
}
604
605
public String getMessage(Locale locale) {
606
return JavahTask.this.getMessage(locale, key, args);
607
}
608
609
};
610
}
611
612
private String getMessage(String key, Object... args) {
613
return getMessage(task_locale, key, args);
614
}
615
616
private String getMessage(Locale locale, String key, Object... args) {
617
if (bundles == null) {
618
// could make this a HashMap<Locale,SoftReference<ResourceBundle>>
619
// and for efficiency, keep a hard reference to the bundle for the task
620
// locale
621
bundles = new HashMap<Locale, ResourceBundle>();
622
}
623
624
if (locale == null)
625
locale = Locale.getDefault();
626
627
ResourceBundle b = bundles.get(locale);
628
if (b == null) {
629
try {
630
b = ResourceBundle.getBundle("com.sun.tools.javah.resources.l10n", locale);
631
bundles.put(locale, b);
632
} catch (MissingResourceException e) {
633
throw new InternalError("Cannot find javah resource bundle for locale " + locale, e);
634
}
635
}
636
637
try {
638
return MessageFormat.format(b.getString(key), args);
639
} catch (MissingResourceException e) {
640
return key;
641
//throw new InternalError(e, key);
642
}
643
}
644
645
File ofile;
646
File odir;
647
String bootcp;
648
String usercp;
649
List<String> classes;
650
boolean verbose;
651
boolean noArgs;
652
boolean help;
653
boolean trace;
654
boolean version;
655
boolean fullVersion;
656
boolean jni;
657
boolean llni;
658
boolean doubleAlign;
659
boolean force;
660
Set<String> javac_extras = new LinkedHashSet<String>();
661
662
PrintWriter log;
663
JavaFileManager fileManager;
664
DiagnosticListener<? super JavaFileObject> diagnosticListener;
665
Locale task_locale;
666
Map<Locale, ResourceBundle> bundles;
667
668
private static final String progname = "javah";
669
670
@SupportedAnnotationTypes("*")
671
class JavahProcessor extends AbstractProcessor {
672
private Messager messager;
673
674
JavahProcessor(Gen g) {
675
this.g = g;
676
}
677
678
@Override
679
public SourceVersion getSupportedSourceVersion() {
680
// since this is co-bundled with javac, we can assume it supports
681
// the latest source version
682
return SourceVersion.latest();
683
}
684
685
@Override
686
public void init(ProcessingEnvironment pEnv) {
687
super.init(pEnv);
688
messager = processingEnv.getMessager();
689
}
690
691
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
692
try {
693
Set<TypeElement> classes = getAllClasses(ElementFilter.typesIn(roundEnv.getRootElements()));
694
if (classes.size() > 0) {
695
checkMethodParameters(classes);
696
g.setProcessingEnvironment(processingEnv);
697
g.setClasses(classes);
698
g.run();
699
}
700
} catch (CompletionFailure cf) {
701
messager.printMessage(ERROR, getMessage("class.not.found", cf.sym.getQualifiedName().toString()));
702
} catch (ClassNotFoundException cnfe) {
703
messager.printMessage(ERROR, getMessage("class.not.found", cnfe.getMessage()));
704
} catch (IOException ioe) {
705
messager.printMessage(ERROR, getMessage("io.exception", ioe.getMessage()));
706
} catch (Util.Exit e) {
707
exit = e;
708
}
709
710
return true;
711
}
712
713
private Set<TypeElement> getAllClasses(Set<? extends TypeElement> classes) {
714
Set<TypeElement> allClasses = new LinkedHashSet<TypeElement>();
715
getAllClasses0(classes, allClasses);
716
return allClasses;
717
}
718
719
private void getAllClasses0(Iterable<? extends TypeElement> classes, Set<TypeElement> allClasses) {
720
for (TypeElement c: classes) {
721
allClasses.add(c);
722
getAllClasses0(ElementFilter.typesIn(c.getEnclosedElements()), allClasses);
723
}
724
}
725
726
// 4942232:
727
// check that classes exist for all the parameters of native methods
728
private void checkMethodParameters(Set<TypeElement> classes) {
729
Types types = processingEnv.getTypeUtils();
730
for (TypeElement te: classes) {
731
for (ExecutableElement ee: ElementFilter.methodsIn(te.getEnclosedElements())) {
732
for (VariableElement ve: ee.getParameters()) {
733
TypeMirror tm = ve.asType();
734
checkMethodParametersVisitor.visit(tm, types);
735
}
736
}
737
}
738
}
739
740
private TypeVisitor<Void,Types> checkMethodParametersVisitor =
741
new SimpleTypeVisitor8<Void,Types>() {
742
@Override
743
public Void visitArray(ArrayType t, Types types) {
744
visit(t.getComponentType(), types);
745
return null;
746
}
747
@Override
748
public Void visitDeclared(DeclaredType t, Types types) {
749
t.asElement().getKind(); // ensure class exists
750
for (TypeMirror st: types.directSupertypes(t))
751
visit(st, types);
752
return null;
753
}
754
};
755
756
private Gen g;
757
private Util.Exit exit;
758
}
759
}
760
761