All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.tools.javah.JavahTask Maven / Gradle / Ivy

There is a newer version: 9-dev-r4023-3
Show newest version
/*
 * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.tools.javah;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.nio.file.NoSuchFileException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVisitor;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.SimpleTypeVisitor9;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;

import com.sun.tools.javac.code.Symbol.CompletionFailure;
import com.sun.tools.javac.main.CommandLine;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;

import static javax.tools.Diagnostic.Kind.*;


/**
 * Javah generates support files for native methods.
 * Parse commandline options and invokes javadoc to execute those commands.
 *
 * 

This is NOT part of any supported API. * If you write code that depends on this, you do so at your own * risk. This code and its internal interfaces are subject to change * or deletion without notice.

* * @author Sucheta Dambalkar * @author Jonathan Gibbons */ public class JavahTask implements NativeHeaderTool.NativeHeaderTask { public class BadArgs extends Exception { private static final long serialVersionUID = 1479361270874789045L; BadArgs(String key, Object... args) { super(JavahTask.this.getMessage(key, args)); this.key = key; this.args = args; } BadArgs showUsage(boolean b) { showUsage = b; return this; } final String key; final Object[] args; boolean showUsage; } static abstract class Option { Option(boolean hasArg, String... aliases) { this.hasArg = hasArg; this.aliases = aliases; } boolean isHidden() { return false; } boolean matches(String opt) { for (String a: aliases) { if (a.equals(opt)) return true; } return false; } boolean ignoreRest() { return false; } abstract void process(JavahTask task, String opt, String arg) throws BadArgs; final boolean hasArg; final String[] aliases; } static abstract class HiddenOption extends Option { HiddenOption(boolean hasArg, String... aliases) { super(hasArg, aliases); } @Override boolean isHidden() { return true; } } static final Option[] recognizedOptions = { new Option(true, "-o") { void process(JavahTask task, String opt, String arg) { task.ofile = new File(arg); } }, new Option(true, "-d") { void process(JavahTask task, String opt, String arg) { task.odir = new File(arg); } }, new HiddenOption(true, "-td") { void process(JavahTask task, String opt, String arg) { // ignored; for backwards compatibility } }, new Option(false, "-v", "-verbose") { void process(JavahTask task, String opt, String arg) { task.verbose = true; } }, new Option(false, "-h", "-help", "--help", "-?") { void process(JavahTask task, String opt, String arg) { task.help = true; } }, new HiddenOption(false, "-trace") { void process(JavahTask task, String opt, String arg) { task.trace = true; } }, new Option(false, "-version") { void process(JavahTask task, String opt, String arg) { task.version = true; } }, new HiddenOption(false, "-fullversion") { void process(JavahTask task, String opt, String arg) { task.fullVersion = true; } }, new Option(false, "-jni") { void process(JavahTask task, String opt, String arg) { task.jni = true; } }, new Option(false, "-force") { void process(JavahTask task, String opt, String arg) { task.force = true; } }, new HiddenOption(false, "-Xnew") { void process(JavahTask task, String opt, String arg) { // we're already using the new javah } }, new HiddenOption(false, "-llni", "-Xllni") { void process(JavahTask task, String opt, String arg) { task.llni = true; } }, new HiddenOption(false, "-llnidouble") { void process(JavahTask task, String opt, String arg) { task.llni = true; task.doubleAlign = true; } }, new HiddenOption(false) { boolean matches(String opt) { return opt.startsWith("-XD"); } void process(JavahTask task, String opt, String arg) { task.javac_extras.add(opt); } }, }; JavahTask() { } JavahTask(Writer out, JavaFileManager fileManager, DiagnosticListener diagnosticListener, Iterable options, Iterable classes) { this(); this.log = getPrintWriterForWriter(out); this.fileManager = fileManager; this.diagnosticListener = diagnosticListener; try { handleOptions(options, false); } catch (BadArgs e) { throw new IllegalArgumentException(e.getMessage()); } this.classes = new ArrayList<>(); if (classes != null) { for (String classname: classes) { Objects.requireNonNull(classname); this.classes.add(classname); } } } public void setLocale(Locale locale) { if (locale == null) locale = Locale.getDefault(); task_locale = locale; } public void setLog(PrintWriter log) { this.log = log; } public void setLog(OutputStream s) { setLog(getPrintWriterForStream(s)); } static PrintWriter getPrintWriterForStream(OutputStream s) { return new PrintWriter(s, true); } static PrintWriter getPrintWriterForWriter(Writer w) { if (w == null) return getPrintWriterForStream(null); else if (w instanceof PrintWriter) return (PrintWriter) w; else return new PrintWriter(w, true); } public void setDiagnosticListener(DiagnosticListener dl) { diagnosticListener = dl; } public void setDiagnosticListener(OutputStream s) { setDiagnosticListener(getDiagnosticListenerForStream(s)); } private DiagnosticListener getDiagnosticListenerForStream(OutputStream s) { return getDiagnosticListenerForWriter(getPrintWriterForStream(s)); } private DiagnosticListener getDiagnosticListenerForWriter(Writer w) { final PrintWriter pw = getPrintWriterForWriter(w); return diagnostic -> { if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { pw.print(getMessage("err.prefix")); pw.print(" "); } pw.println(diagnostic.getMessage(null)); }; } int run(String[] args) { try { handleOptions(args); boolean ok = run(); return ok ? 0 : 1; } catch (BadArgs e) { diagnosticListener.report(createDiagnostic(e.key, e.args)); return 1; } catch (InternalError e) { diagnosticListener.report(createDiagnostic("err.internal.error", e.getMessage())); return 1; } catch (Util.Exit e) { return e.exitValue; } finally { log.flush(); } } public void handleOptions(String[] args) throws BadArgs { handleOptions(Arrays.asList(args), true); } private void handleOptions(Iterable args, boolean allowClasses) throws BadArgs { if (log == null) { log = getPrintWriterForStream(System.out); if (diagnosticListener == null) diagnosticListener = getDiagnosticListenerForStream(System.err); } else { if (diagnosticListener == null) diagnosticListener = getDiagnosticListenerForWriter(log); } if (fileManager == null) fileManager = getDefaultFileManager(diagnosticListener, log); Iterator iter = expandAtArgs(args).iterator(); noArgs = !iter.hasNext(); while (iter.hasNext()) { String arg = iter.next(); if (arg.startsWith("-")) handleOption(arg, iter); else if (allowClasses) { if (classes == null) classes = new ArrayList<>(); classes.add(arg); while (iter.hasNext()) classes.add(iter.next()); } else throw new BadArgs("err.unknown.option", arg).showUsage(true); } if ((classes == null || classes.size() == 0) && !(noArgs || help || version || fullVersion)) { throw new BadArgs("err.no.classes.specified"); } if (jni && llni) throw new BadArgs("jni.llni.mixed"); if (odir != null && ofile != null) throw new BadArgs("dir.file.mixed"); } private void handleOption(String name, Iterator rest) throws BadArgs { for (Option o: recognizedOptions) { if (o.matches(name)) { if (o.hasArg) { if (rest.hasNext()) o.process(this, name, rest.next()); else throw new BadArgs("err.missing.arg", name).showUsage(true); } else o.process(this, name, null); if (o.ignoreRest()) { while (rest.hasNext()) rest.next(); } return; } } if (fileManager.handleOption(name, rest)) return; throw new BadArgs("err.unknown.option", name).showUsage(true); } private Iterable expandAtArgs(Iterable args) throws BadArgs { try { List l = new ArrayList<>(); for (String arg: args) l.add(arg); return Arrays.asList(CommandLine.parse(l.toArray(new String[l.size()]))); } catch (FileNotFoundException | NoSuchFileException e) { throw new BadArgs("at.args.file.not.found", e.getLocalizedMessage()); } catch (IOException e) { throw new BadArgs("at.args.io.exception", e.getLocalizedMessage()); } } public Boolean call() { return run(); } public boolean run() throws Util.Exit { if (!javac_extras.contains("-XDsuppress-tool-removal-message")) { log.println(getMessage("javah.misc.Deprecation")); } Util util = new Util(log, diagnosticListener); if (noArgs || help) { showHelp(); return help; // treat noArgs as an error for purposes of exit code } if (version || fullVersion) { showVersion(fullVersion); return true; } util.verbose = verbose; Gen g; if (llni) g = new LLNI(doubleAlign, util); else { g = new JNI(util); } if (ofile != null) { if (!(fileManager instanceof StandardJavaFileManager)) { diagnosticListener.report(createDiagnostic("err.cant.use.option.for.fm", "-o")); return false; } Iterable iter = ((StandardJavaFileManager) fileManager).getJavaFileObjectsFromFiles(Collections.singleton(ofile)); JavaFileObject fo = iter.iterator().next(); g.setOutFile(fo); } else { if (odir != null) { if (!(fileManager instanceof StandardJavaFileManager)) { diagnosticListener.report(createDiagnostic("err.cant.use.option.for.fm", "-d")); return false; } if (!odir.exists()) if (!odir.mkdirs()) util.error("cant.create.dir", odir.toString()); try { ((StandardJavaFileManager) fileManager).setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(odir)); } catch (IOException e) { Object msg = e.getLocalizedMessage(); if (msg == null) { msg = e; } diagnosticListener.report(createDiagnostic("err.ioerror", odir, msg)); return false; } } g.setFileManager(fileManager); } /* * Force set to false will turn off smarts about checking file * content before writing. */ g.setForce(force); if (fileManager instanceof JavahFileManager) ((JavahFileManager) fileManager).setSymbolFileEnabled(false); JavaCompiler c = ToolProvider.getSystemJavaCompiler(); List opts = new ArrayList<>(); opts.add("-proc:only"); opts.addAll(javac_extras); CompilationTask t; try { t = c.getTask(log, fileManager, diagnosticListener, opts, classes, null); } catch (IllegalArgumentException e) { util.error("bad.arg", e.getMessage()); return false; } JavahProcessor p = new JavahProcessor(g); t.setProcessors(Collections.singleton(p)); boolean ok = t.call(); if (p.exit != null) throw new Util.Exit(p.exit); return ok; } static StandardJavaFileManager getDefaultFileManager(final DiagnosticListener dl, PrintWriter log) { return JavahFileManager.create(dl, log); } private void showHelp() { log.println(getMessage("main.usage", progname)); for (Option o: recognizedOptions) { if (o.isHidden()) continue; String name = o.aliases[0].substring(1); // there must always be at least one name log.println(getMessage("main.opt." + name)); } String[] fmOptions = { "--module-path", "--system", "--class-path", "-classpath", "-cp", "-bootclasspath" }; for (String o: fmOptions) { if (fileManager.isSupportedOption(o) == -1) continue; String name = o.replaceAll("^-+", "").replaceAll("-+", "_"); log.println(getMessage("main.opt." + name)); } log.println(getMessage("main.usage.foot")); } private void showVersion(boolean full) { log.println(version(full)); } private static final String versionRBName = "com.sun.tools.javah.resources.version"; private static ResourceBundle versionRB; private String version(boolean full) { String msgKey = (full ? "javah.fullVersion" : "javah.version"); String versionKey = (full ? "full" : "release"); // versionKey=product: mm.nn.oo[-milestone] // versionKey=full: mm.mm.oo[-milestone]-build if (versionRB == null) { try { versionRB = ResourceBundle.getBundle(versionRBName); } catch (MissingResourceException e) { return getMessage("version.resource.missing", System.getProperty("java.version")); } } try { return getMessage(msgKey, "javah", versionRB.getString(versionKey)); } catch (MissingResourceException e) { return getMessage("version.unknown", System.getProperty("java.version")); } } private Diagnostic createDiagnostic(final String key, final Object... args) { return new Diagnostic() { @DefinedBy(Api.COMPILER) public Kind getKind() { return Diagnostic.Kind.ERROR; } @DefinedBy(Api.COMPILER) public JavaFileObject getSource() { return null; } @DefinedBy(Api.COMPILER) public long getPosition() { return Diagnostic.NOPOS; } @DefinedBy(Api.COMPILER) public long getStartPosition() { return Diagnostic.NOPOS; } @DefinedBy(Api.COMPILER) public long getEndPosition() { return Diagnostic.NOPOS; } @DefinedBy(Api.COMPILER) public long getLineNumber() { return Diagnostic.NOPOS; } @DefinedBy(Api.COMPILER) public long getColumnNumber() { return Diagnostic.NOPOS; } @DefinedBy(Api.COMPILER) public String getCode() { return key; } @DefinedBy(Api.COMPILER) public String getMessage(Locale locale) { return JavahTask.this.getMessage(locale, key, args); } }; } private String getMessage(String key, Object... args) { return getMessage(task_locale, key, args); } private String getMessage(Locale locale, String key, Object... args) { if (bundles == null) { // could make this a HashMap> // and for efficiency, keep a hard reference to the bundle for the task // locale bundles = new HashMap<>(); } if (locale == null) locale = Locale.getDefault(); ResourceBundle b = bundles.get(locale); if (b == null) { try { b = ResourceBundle.getBundle("com.sun.tools.javah.resources.l10n", locale); bundles.put(locale, b); } catch (MissingResourceException e) { throw new InternalError("Cannot find javah resource bundle for locale " + locale, e); } } try { return MessageFormat.format(b.getString(key), args); } catch (MissingResourceException e) { return key; //throw new InternalError(e, key); } } File ofile; File odir; String bootcp; String usercp; List classes; boolean verbose; boolean noArgs; boolean help; boolean trace; boolean version; boolean fullVersion; boolean jni; boolean llni; boolean doubleAlign; boolean force; Set javac_extras = new LinkedHashSet<>(); PrintWriter log; JavaFileManager fileManager; DiagnosticListener diagnosticListener; Locale task_locale; Map bundles; private static final String progname = "javah"; @SupportedAnnotationTypes("*") class JavahProcessor extends AbstractProcessor { private Messager messager; JavahProcessor(Gen g) { this.g = g; } @Override @DefinedBy(Api.ANNOTATION_PROCESSING) public SourceVersion getSupportedSourceVersion() { // since this is co-bundled with javac, we can assume it supports // the latest source version return SourceVersion.latest(); } @Override @DefinedBy(Api.ANNOTATION_PROCESSING) public void init(ProcessingEnvironment pEnv) { super.init(pEnv); messager = processingEnv.getMessager(); } @DefinedBy(Api.ANNOTATION_PROCESSING) public boolean process(Set annotations, RoundEnvironment roundEnv) { try { Set classes = getAllClasses(ElementFilter.typesIn(roundEnv.getRootElements())); if (classes.size() > 0) { checkMethodParameters(classes); g.setProcessingEnvironment(processingEnv); g.setClasses(classes); g.run(); } } catch (CompletionFailure cf) { messager.printMessage(ERROR, getMessage("class.not.found", cf.sym.getQualifiedName().toString())); } catch (ClassNotFoundException cnfe) { messager.printMessage(ERROR, getMessage("class.not.found", cnfe.getMessage())); } catch (IOException ioe) { messager.printMessage(ERROR, getMessage("io.exception", ioe.getMessage())); } catch (Util.Exit e) { exit = e; } return true; } private Set getAllClasses(Set classes) { Set allClasses = new LinkedHashSet<>(); getAllClasses0(classes, allClasses); return allClasses; } private void getAllClasses0(Iterable classes, Set allClasses) { for (TypeElement c: classes) { allClasses.add(c); getAllClasses0(ElementFilter.typesIn(c.getEnclosedElements()), allClasses); } } // 4942232: // check that classes exist for all the parameters of native methods private void checkMethodParameters(Set classes) { Types types = processingEnv.getTypeUtils(); for (TypeElement te: classes) { for (ExecutableElement ee: ElementFilter.methodsIn(te.getEnclosedElements())) { for (VariableElement ve: ee.getParameters()) { TypeMirror tm = ve.asType(); checkMethodParametersVisitor.visit(tm, types); } } } } private TypeVisitor checkMethodParametersVisitor = new SimpleTypeVisitor9() { @Override @DefinedBy(Api.LANGUAGE_MODEL) public Void visitArray(ArrayType t, Types types) { visit(t.getComponentType(), types); return null; } @Override @DefinedBy(Api.LANGUAGE_MODEL) public Void visitDeclared(DeclaredType t, Types types) { t.asElement().getKind(); // ensure class exists for (TypeMirror st: types.directSupertypes(t)) visit(st, types); return null; } }; private Gen g; private Util.Exit exit; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy