Path: blob/aarch64-shenandoah-jdk8u272-b10/langtools/src/share/classes/com/sun/tools/javah/JavahTask.java
38899 views
/*1* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.tools.javah;2627import java.io.File;28import java.io.FileNotFoundException;29import java.io.IOException;30import java.io.OutputStream;31import java.io.PrintWriter;32import java.io.Writer;33import java.text.MessageFormat;34import java.util.ArrayList;35import java.util.Arrays;36import java.util.Collections;37import java.util.HashMap;38import java.util.Iterator;39import java.util.LinkedHashSet;40import java.util.List;41import java.util.Locale;42import java.util.Map;43import java.util.MissingResourceException;44import java.util.ResourceBundle;45import java.util.Set;4647import javax.annotation.processing.AbstractProcessor;48import javax.annotation.processing.Messager;49import javax.annotation.processing.ProcessingEnvironment;50import javax.annotation.processing.RoundEnvironment;51import javax.annotation.processing.SupportedAnnotationTypes;5253import javax.lang.model.SourceVersion;54import javax.lang.model.element.ExecutableElement;55import javax.lang.model.element.TypeElement;56import javax.lang.model.element.VariableElement;57import javax.lang.model.type.ArrayType;58import javax.lang.model.type.DeclaredType;59import javax.lang.model.type.TypeMirror;60import javax.lang.model.type.TypeVisitor;61import javax.lang.model.util.ElementFilter;62import javax.lang.model.util.SimpleTypeVisitor8;63import javax.lang.model.util.Types;6465import javax.tools.Diagnostic;66import javax.tools.DiagnosticListener;67import javax.tools.JavaCompiler;68import javax.tools.JavaCompiler.CompilationTask;69import javax.tools.JavaFileManager;70import javax.tools.JavaFileObject;71import javax.tools.StandardJavaFileManager;72import javax.tools.StandardLocation;73import javax.tools.ToolProvider;74import static javax.tools.Diagnostic.Kind.*;7576import com.sun.tools.javac.code.Symbol.CompletionFailure;77import com.sun.tools.javac.main.CommandLine;7879/**80* Javah generates support files for native methods.81* Parse commandline options and invokes javadoc to execute those commands.82*83* <p><b>This is NOT part of any supported API.84* If you write code that depends on this, you do so at your own85* risk. This code and its internal interfaces are subject to change86* or deletion without notice.</b></p>87*88* @author Sucheta Dambalkar89* @author Jonathan Gibbons90*/91public class JavahTask implements NativeHeaderTool.NativeHeaderTask {92public class BadArgs extends Exception {93private static final long serialVersionUID = 1479361270874789045L;94BadArgs(String key, Object... args) {95super(JavahTask.this.getMessage(key, args));96this.key = key;97this.args = args;98}99100BadArgs showUsage(boolean b) {101showUsage = b;102return this;103}104105final String key;106final Object[] args;107boolean showUsage;108}109110static abstract class Option {111Option(boolean hasArg, String... aliases) {112this.hasArg = hasArg;113this.aliases = aliases;114}115116boolean isHidden() {117return false;118}119120boolean matches(String opt) {121for (String a: aliases) {122if (a.equals(opt))123return true;124}125return false;126}127128boolean ignoreRest() {129return false;130}131132abstract void process(JavahTask task, String opt, String arg) throws BadArgs;133134final boolean hasArg;135final String[] aliases;136}137138static abstract class HiddenOption extends Option {139HiddenOption(boolean hasArg, String... aliases) {140super(hasArg, aliases);141}142143@Override144boolean isHidden() {145return true;146}147}148149static final Option[] recognizedOptions = {150new Option(true, "-o") {151void process(JavahTask task, String opt, String arg) {152task.ofile = new File(arg);153}154},155156new Option(true, "-d") {157void process(JavahTask task, String opt, String arg) {158task.odir = new File(arg);159}160},161162new HiddenOption(true, "-td") {163void process(JavahTask task, String opt, String arg) {164// ignored; for backwards compatibility165}166},167168new HiddenOption(false, "-stubs") {169void process(JavahTask task, String opt, String arg) {170// ignored; for backwards compatibility171}172},173174new Option(false, "-v", "-verbose") {175void process(JavahTask task, String opt, String arg) {176task.verbose = true;177}178},179180new Option(false, "-h", "-help", "--help", "-?") {181void process(JavahTask task, String opt, String arg) {182task.help = true;183}184},185186new HiddenOption(false, "-trace") {187void process(JavahTask task, String opt, String arg) {188task.trace = true;189}190},191192new Option(false, "-version") {193void process(JavahTask task, String opt, String arg) {194task.version = true;195}196},197198new HiddenOption(false, "-fullversion") {199void process(JavahTask task, String opt, String arg) {200task.fullVersion = true;201}202},203204new Option(false, "-jni") {205void process(JavahTask task, String opt, String arg) {206task.jni = true;207}208},209210new Option(false, "-force") {211void process(JavahTask task, String opt, String arg) {212task.force = true;213}214},215216new HiddenOption(false, "-Xnew") {217void process(JavahTask task, String opt, String arg) {218// we're already using the new javah219}220},221222new HiddenOption(false, "-llni", "-Xllni") {223void process(JavahTask task, String opt, String arg) {224task.llni = true;225}226},227228new HiddenOption(false, "-llnidouble") {229void process(JavahTask task, String opt, String arg) {230task.llni = true;231task.doubleAlign = true;232}233},234235new HiddenOption(false) {236boolean matches(String opt) {237return opt.startsWith("-XD");238}239void process(JavahTask task, String opt, String arg) {240task.javac_extras.add(opt);241}242},243};244245JavahTask() {246}247248JavahTask(Writer out,249JavaFileManager fileManager,250DiagnosticListener<? super JavaFileObject> diagnosticListener,251Iterable<String> options,252Iterable<String> classes) {253this();254this.log = getPrintWriterForWriter(out);255this.fileManager = fileManager;256this.diagnosticListener = diagnosticListener;257258try {259handleOptions(options, false);260} catch (BadArgs e) {261throw new IllegalArgumentException(e.getMessage());262}263264this.classes = new ArrayList<String>();265if (classes != null) {266for (String classname: classes) {267classname.getClass(); // null-check268this.classes.add(classname);269}270}271}272273public void setLocale(Locale locale) {274if (locale == null)275locale = Locale.getDefault();276task_locale = locale;277}278279public void setLog(PrintWriter log) {280this.log = log;281}282283public void setLog(OutputStream s) {284setLog(getPrintWriterForStream(s));285}286287static PrintWriter getPrintWriterForStream(OutputStream s) {288return new PrintWriter(s, true);289}290291static PrintWriter getPrintWriterForWriter(Writer w) {292if (w == null)293return getPrintWriterForStream(null);294else if (w instanceof PrintWriter)295return (PrintWriter) w;296else297return new PrintWriter(w, true);298}299300public void setDiagnosticListener(DiagnosticListener<? super JavaFileObject> dl) {301diagnosticListener = dl;302}303304public void setDiagnosticListener(OutputStream s) {305setDiagnosticListener(getDiagnosticListenerForStream(s));306}307308private DiagnosticListener<JavaFileObject> getDiagnosticListenerForStream(OutputStream s) {309return getDiagnosticListenerForWriter(getPrintWriterForStream(s));310}311312private DiagnosticListener<JavaFileObject> getDiagnosticListenerForWriter(Writer w) {313final PrintWriter pw = getPrintWriterForWriter(w);314return new DiagnosticListener<JavaFileObject> () {315public void report(Diagnostic<? extends JavaFileObject> diagnostic) {316if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {317pw.print(getMessage("err.prefix"));318pw.print(" ");319}320pw.println(diagnostic.getMessage(null));321}322};323}324325int run(String[] args) {326try {327handleOptions(args);328boolean ok = run();329return ok ? 0 : 1;330} catch (BadArgs e) {331diagnosticListener.report(createDiagnostic(e.key, e.args));332return 1;333} catch (InternalError e) {334diagnosticListener.report(createDiagnostic("err.internal.error", e.getMessage()));335return 1;336} catch (Util.Exit e) {337return e.exitValue;338} finally {339log.flush();340}341}342343public void handleOptions(String[] args) throws BadArgs {344handleOptions(Arrays.asList(args), true);345}346347private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs {348if (log == null) {349log = getPrintWriterForStream(System.out);350if (diagnosticListener == null)351diagnosticListener = getDiagnosticListenerForStream(System.err);352} else {353if (diagnosticListener == null)354diagnosticListener = getDiagnosticListenerForWriter(log);355}356357if (fileManager == null)358fileManager = getDefaultFileManager(diagnosticListener, log);359360Iterator<String> iter = expandAtArgs(args).iterator();361noArgs = !iter.hasNext();362363while (iter.hasNext()) {364String arg = iter.next();365if (arg.startsWith("-"))366handleOption(arg, iter);367else if (allowClasses) {368if (classes == null)369classes = new ArrayList<String>();370classes.add(arg);371while (iter.hasNext())372classes.add(iter.next());373} else374throw new BadArgs("err.unknown.option", arg).showUsage(true);375}376377if ((classes == null || classes.size() == 0) &&378!(noArgs || help || version || fullVersion)) {379throw new BadArgs("err.no.classes.specified");380}381382if (jni && llni)383throw new BadArgs("jni.llni.mixed");384385if (odir != null && ofile != null)386throw new BadArgs("dir.file.mixed");387}388389private void handleOption(String name, Iterator<String> rest) throws BadArgs {390for (Option o: recognizedOptions) {391if (o.matches(name)) {392if (o.hasArg) {393if (rest.hasNext())394o.process(this, name, rest.next());395else396throw new BadArgs("err.missing.arg", name).showUsage(true);397} else398o.process(this, name, null);399400if (o.ignoreRest()) {401while (rest.hasNext())402rest.next();403}404return;405}406}407408if (fileManager.handleOption(name, rest))409return;410411throw new BadArgs("err.unknown.option", name).showUsage(true);412}413414private Iterable<String> expandAtArgs(Iterable<String> args) throws BadArgs {415try {416List<String> l = new ArrayList<String>();417for (String arg: args) l.add(arg);418return Arrays.asList(CommandLine.parse(l.toArray(new String[l.size()])));419} catch (FileNotFoundException e) {420throw new BadArgs("at.args.file.not.found", e.getLocalizedMessage());421} catch (IOException e) {422throw new BadArgs("at.args.io.exception", e.getLocalizedMessage());423}424}425426public Boolean call() {427return run();428}429430public boolean run() throws Util.Exit {431432Util util = new Util(log, diagnosticListener);433434if (noArgs || help) {435showHelp();436return help; // treat noArgs as an error for purposes of exit code437}438439if (version || fullVersion) {440showVersion(fullVersion);441return true;442}443444util.verbose = verbose;445446Gen g;447448if (llni)449g = new LLNI(doubleAlign, util);450else {451// if (stubs)452// throw new BadArgs("jni.no.stubs");453g = new JNI(util);454}455456if (ofile != null) {457if (!(fileManager instanceof StandardJavaFileManager)) {458diagnosticListener.report(createDiagnostic("err.cant.use.option.for.fm", "-o"));459return false;460}461Iterable<? extends JavaFileObject> iter =462((StandardJavaFileManager) fileManager).getJavaFileObjectsFromFiles(Collections.singleton(ofile));463JavaFileObject fo = iter.iterator().next();464g.setOutFile(fo);465} else {466if (odir != null) {467if (!(fileManager instanceof StandardJavaFileManager)) {468diagnosticListener.report(createDiagnostic("err.cant.use.option.for.fm", "-d"));469return false;470}471472if (!odir.exists())473if (!odir.mkdirs())474util.error("cant.create.dir", odir.toString());475try {476((StandardJavaFileManager) fileManager).setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(odir));477} catch (IOException e) {478Object msg = e.getLocalizedMessage();479if (msg == null) {480msg = e;481}482diagnosticListener.report(createDiagnostic("err.ioerror", odir, msg));483return false;484}485}486g.setFileManager(fileManager);487}488489/*490* Force set to false will turn off smarts about checking file491* content before writing.492*/493g.setForce(force);494495if (fileManager instanceof JavahFileManager)496((JavahFileManager) fileManager).setSymbolFileEnabled(false);497498JavaCompiler c = ToolProvider.getSystemJavaCompiler();499List<String> opts = new ArrayList<String>();500opts.add("-proc:only");501opts.addAll(javac_extras);502CompilationTask t = c.getTask(log, fileManager, diagnosticListener, opts, classes, null);503JavahProcessor p = new JavahProcessor(g);504t.setProcessors(Collections.singleton(p));505506boolean ok = t.call();507if (p.exit != null)508throw new Util.Exit(p.exit);509return ok;510}511512private List<File> pathToFiles(String path) {513List<File> files = new ArrayList<File>();514for (String f: path.split(File.pathSeparator)) {515if (f.length() > 0)516files.add(new File(f));517}518return files;519}520521static StandardJavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) {522return JavahFileManager.create(dl, log);523}524525private void showHelp() {526log.println(getMessage("main.usage", progname));527for (Option o: recognizedOptions) {528if (o.isHidden())529continue;530String name = o.aliases[0].substring(1); // there must always be at least one name531log.println(getMessage("main.opt." + name));532}533String[] fmOptions = { "-classpath", "-cp", "-bootclasspath" };534for (String o: fmOptions) {535if (fileManager.isSupportedOption(o) == -1)536continue;537String name = o.substring(1);538log.println(getMessage("main.opt." + name));539}540log.println(getMessage("main.usage.foot"));541}542543private void showVersion(boolean full) {544log.println(version(full));545}546547private static final String versionRBName = "com.sun.tools.javah.resources.version";548private static ResourceBundle versionRB;549550private String version(boolean full) {551String msgKey = (full ? "javah.fullVersion" : "javah.version");552String versionKey = (full ? "full" : "release");553// versionKey=product: mm.nn.oo[-milestone]554// versionKey=full: mm.mm.oo[-milestone]-build555if (versionRB == null) {556try {557versionRB = ResourceBundle.getBundle(versionRBName);558} catch (MissingResourceException e) {559return getMessage("version.resource.missing", System.getProperty("java.version"));560}561}562try {563return getMessage(msgKey, "javah", versionRB.getString(versionKey));564}565catch (MissingResourceException e) {566return getMessage("version.unknown", System.getProperty("java.version"));567}568}569570private Diagnostic<JavaFileObject> createDiagnostic(final String key, final Object... args) {571return new Diagnostic<JavaFileObject>() {572public Kind getKind() {573return Diagnostic.Kind.ERROR;574}575576public JavaFileObject getSource() {577return null;578}579580public long getPosition() {581return Diagnostic.NOPOS;582}583584public long getStartPosition() {585return Diagnostic.NOPOS;586}587588public long getEndPosition() {589return Diagnostic.NOPOS;590}591592public long getLineNumber() {593return Diagnostic.NOPOS;594}595596public long getColumnNumber() {597return Diagnostic.NOPOS;598}599600public String getCode() {601return key;602}603604public String getMessage(Locale locale) {605return JavahTask.this.getMessage(locale, key, args);606}607608};609}610611private String getMessage(String key, Object... args) {612return getMessage(task_locale, key, args);613}614615private String getMessage(Locale locale, String key, Object... args) {616if (bundles == null) {617// could make this a HashMap<Locale,SoftReference<ResourceBundle>>618// and for efficiency, keep a hard reference to the bundle for the task619// locale620bundles = new HashMap<Locale, ResourceBundle>();621}622623if (locale == null)624locale = Locale.getDefault();625626ResourceBundle b = bundles.get(locale);627if (b == null) {628try {629b = ResourceBundle.getBundle("com.sun.tools.javah.resources.l10n", locale);630bundles.put(locale, b);631} catch (MissingResourceException e) {632throw new InternalError("Cannot find javah resource bundle for locale " + locale, e);633}634}635636try {637return MessageFormat.format(b.getString(key), args);638} catch (MissingResourceException e) {639return key;640//throw new InternalError(e, key);641}642}643644File ofile;645File odir;646String bootcp;647String usercp;648List<String> classes;649boolean verbose;650boolean noArgs;651boolean help;652boolean trace;653boolean version;654boolean fullVersion;655boolean jni;656boolean llni;657boolean doubleAlign;658boolean force;659Set<String> javac_extras = new LinkedHashSet<String>();660661PrintWriter log;662JavaFileManager fileManager;663DiagnosticListener<? super JavaFileObject> diagnosticListener;664Locale task_locale;665Map<Locale, ResourceBundle> bundles;666667private static final String progname = "javah";668669@SupportedAnnotationTypes("*")670class JavahProcessor extends AbstractProcessor {671private Messager messager;672673JavahProcessor(Gen g) {674this.g = g;675}676677@Override678public SourceVersion getSupportedSourceVersion() {679// since this is co-bundled with javac, we can assume it supports680// the latest source version681return SourceVersion.latest();682}683684@Override685public void init(ProcessingEnvironment pEnv) {686super.init(pEnv);687messager = processingEnv.getMessager();688}689690public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {691try {692Set<TypeElement> classes = getAllClasses(ElementFilter.typesIn(roundEnv.getRootElements()));693if (classes.size() > 0) {694checkMethodParameters(classes);695g.setProcessingEnvironment(processingEnv);696g.setClasses(classes);697g.run();698}699} catch (CompletionFailure cf) {700messager.printMessage(ERROR, getMessage("class.not.found", cf.sym.getQualifiedName().toString()));701} catch (ClassNotFoundException cnfe) {702messager.printMessage(ERROR, getMessage("class.not.found", cnfe.getMessage()));703} catch (IOException ioe) {704messager.printMessage(ERROR, getMessage("io.exception", ioe.getMessage()));705} catch (Util.Exit e) {706exit = e;707}708709return true;710}711712private Set<TypeElement> getAllClasses(Set<? extends TypeElement> classes) {713Set<TypeElement> allClasses = new LinkedHashSet<TypeElement>();714getAllClasses0(classes, allClasses);715return allClasses;716}717718private void getAllClasses0(Iterable<? extends TypeElement> classes, Set<TypeElement> allClasses) {719for (TypeElement c: classes) {720allClasses.add(c);721getAllClasses0(ElementFilter.typesIn(c.getEnclosedElements()), allClasses);722}723}724725// 4942232:726// check that classes exist for all the parameters of native methods727private void checkMethodParameters(Set<TypeElement> classes) {728Types types = processingEnv.getTypeUtils();729for (TypeElement te: classes) {730for (ExecutableElement ee: ElementFilter.methodsIn(te.getEnclosedElements())) {731for (VariableElement ve: ee.getParameters()) {732TypeMirror tm = ve.asType();733checkMethodParametersVisitor.visit(tm, types);734}735}736}737}738739private TypeVisitor<Void,Types> checkMethodParametersVisitor =740new SimpleTypeVisitor8<Void,Types>() {741@Override742public Void visitArray(ArrayType t, Types types) {743visit(t.getComponentType(), types);744return null;745}746@Override747public Void visitDeclared(DeclaredType t, Types types) {748t.asElement().getKind(); // ensure class exists749for (TypeMirror st: types.directSupertypes(t))750visit(st, types);751return null;752}753};754755private Gen g;756private Util.Exit exit;757}758}759760761