diff --git a/WHATSNEW b/WHATSNEW index 7e0163198..e87a49a52 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -7,12 +7,15 @@ Changes that could break older environments: * Ant doesn't search for the buildfile anymore, unless you use the new -find argument. +* has been replaced by a number of new tasks. + Other changes: -------------- * A GUI Frontend: Antidote -* New tasks: stylebook, propertyfile, depend, antlr, telnet, csc, ilasm, transform +* New tasks: stylebook, propertyfile, depend, antlr, telnet, csc, + ilasm, transform, javah * Added output attribute to . diff --git a/build.xml b/build.xml index 2b6674229..ad8d63ba8 100644 --- a/build.xml +++ b/build.xml @@ -110,6 +110,7 @@ + diff --git a/src/main/org/apache/tools/ant/taskdefs/defaults.properties b/src/main/org/apache/tools/ant/taskdefs/defaults.properties index f65a88c49..8cdff4980 100644 --- a/src/main/org/apache/tools/ant/taskdefs/defaults.properties +++ b/src/main/org/apache/tools/ant/taskdefs/defaults.properties @@ -81,6 +81,7 @@ p4have=org.apache.tools.ant.taskdefs.optional.perforce.P4Have p4sync=org.apache.tools.ant.taskdefs.optional.perforce.P4Sync p4edit=org.apache.tools.ant.taskdefs.optional.perforce.P4Edit p4submit=org.apache.tools.ant.taskdefs.optional.perforce.P4Submit +javah=org.apache.tools.ant.taskdefs.optional.Javah # deprecated ant tasks (kept for back compatibility) javadoc2=org.apache.tools.ant.taskdefs.Javadoc diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/Javah.java b/src/main/org/apache/tools/ant/taskdefs/optional/Javah.java new file mode 100755 index 000000000..78189784e --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/optional/Javah.java @@ -0,0 +1,466 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.tools.ant.taskdefs.optional; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.taskdefs.LogOutputStream; +import org.apache.tools.ant.types.*; + +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; +import java.io.*; +import java.util.*; + +/** + * Task to generate JNI header files using javah. This task can take the following + * arguments: + *
    + *
  • classname - the fully-qualified name of a class
  • + *
  • outputFile - Concatenates the resulting header or source files for all + * the classes listed into this file
  • + *
  • destdir - Sets the directory where javah saves the header files or the + * stub files
  • + *
  • classpath
  • + *
  • bootclasspath
  • + *
  • force - Specifies that output files should always be written + (JDK1.2 only)
  • + *
  • old - Specifies that old JDK1.0-style header files should be generated + * (otherwise output file contain JNI-style native method + * function prototypes) (JDK1.2 only)
  • + *
  • stubs - generate C declarations from the Java object file (used with old)
  • + *
  • verbose - causes javah to print a message to stdout concerning the status + * of the generated files
  • + *
  • extdirs - Override location of installed extensions
  • + *
+ * Of these arguments, either outputFile or destdir is required, + * but not both. More than one classname may be specified, using a comma-separated + * list or by using <class name="xxx"> elements within the task. + *

+ * When this task executes, it will generate C header and source files that + * are needed to implement native methods. + * + * @author Rick Beton richard.beton@physics.org + */ + +public class Javah extends Task { + + private static final String FAIL_MSG = "Compile failed, messages should have been provided."; + + private Vector classes = new Vector(2); + private String cls; + private File destDir; + private Path classpath = null; + private String outputFile = null; + private boolean verbose = false; + private boolean force = false; + private boolean old = false; + private boolean stubs = false; + private Path bootclasspath; + //private Path extdirs; + private static String lSep = System.getProperty("line.separator"); + + public void setClass(String cls) { + this.cls = cls; + } + + public ClassArgument createClass() { + ClassArgument ga = new ClassArgument(); + classes.addElement(ga); + return ga; + } + + public class ClassArgument { + private String name; + + public ClassArgument() { + } + + public void setName(String name) { + this.name = name; + log("ClassArgument.name="+name); + } + + public String getName() { + return name; + } + } + + /** + * Set the destination directory into which the Java source + * files should be compiled. + */ + public void setDestdir(File destDir) { + this.destDir = destDir; + } + + public void setClasspath(Path src) { + if (classpath == null) { + classpath = src; + } else { + classpath.append(src); + } + } + public Path createClasspath() { + if (classpath == null) { + classpath = new Path(project); + } + return classpath.createPath(); + } + + /** + * Adds a reference to a CLASSPATH defined elsewhere. + */ + public void setClasspathRef(Reference r) { + createClasspath().setRefid(r); + } + + public void setBootclasspath(Path src) { + if (bootclasspath == null) { + bootclasspath = src; + } else { + bootclasspath.append(src); + } + } + public Path createBootclasspath() { + if (bootclasspath == null) { + bootclasspath = new Path(project); + } + return bootclasspath.createPath(); + } + + /** + * Adds a reference to a CLASSPATH defined elsewhere. + */ + public void setBootClasspathRef(Reference r) { + createBootclasspath().setRefid(r); + } + + ///** + // * Sets the extension directories that will be used during the + // * compilation. + // */ + //public void setExtdirs(Path extdirs) { + // if (this.extdirs == null) { + // this.extdirs = extdirs; + // } else { + // this.extdirs.append(extdirs); + // } + //} + + ///** + // * Maybe creates a nested classpath element. + // */ + //public Path createExtdirs() { + // if (extdirs == null) { + // extdirs = new Path(project); + // } + // return extdirs.createPath(); + //} + + /** + * Set the output file name. + */ + public void setOutputFile(String outputFile) { + this.outputFile = outputFile; + } + + /** + * Set the force-write flag. + */ + public void setForce(boolean force) { + this.force = force; + } + + /** + * Set the old flag. + */ + public void setOld(boolean old) { + this.old = old; + } + + /** + * Set the stubs flag. + */ + public void setStubs(boolean stubs) { + this.stubs = stubs; + } + + /** + * Set the verbose flag. + */ + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + + /** + * Executes the task. + */ + public void execute() throws BuildException { + // first off, make sure that we've got a srcdir + + if ((cls == null) && (classes.size() == 0)) { + throw new BuildException("class attribute must be set!", location); + } + + if ((cls != null) && (classes.size() > 0)) { + throw new BuildException("set class attribute or class element, not both.", location); + } + + if (destDir != null) { + if (!destDir.isDirectory()) { + throw new BuildException("destination directory \"" + destDir + "\" does not exist or is not a directory", location); + } + if (outputFile != null) { + throw new BuildException("destdir and outputFile are mutually exclusive", location); + } + } + + if (classpath == null) { + classpath = Path.systemClasspath; + } + + String compiler = project.getProperty("build.compiler"); + if (compiler == null) { + if (Project.getJavaVersion().startsWith("1.3")) { + compiler = "modern"; + } else { + compiler = "classic"; + } + } + + doClassicCompile(); + } + + // XXX + // we need a way to not use the current classpath. + + /** + * Peforms a compile using the classic compiler that shipped with + * JDK 1.1 and 1.2. + */ + + private void doClassicCompile() throws BuildException { + Commandline cmd = setupJavahCommand(); + + // Use reflection to be able to build on all JDKs + /* + // provide the compiler a different message sink - namely our own + sun.tools.javac.Main compiler = + new sun.tools.javac.Main(new LogOutputStream(this, Project.MSG_WARN), "javac"); + + if (!compiler.compile(cmd.getArguments())) { + throw new BuildException("Compile failed"); + } + */ + PrintStream err = System.err; + PrintStream out = System.out; + + try { + // Javac uses logstr to change the output stream and calls + // the constructor's invoke method to create a compiler instance + // dynamically. However, javah has a different interface and this + // makes it harder, so here's a simple alternative. + //------------------------------------------------------------------ + PrintStream logstr = + new PrintStream(new LogOutputStream(this, Project.MSG_WARN)); + System.setOut(logstr); + System.setErr(logstr); + com.sun.tools.javah.Main main = new com.sun.tools.javah.Main( cmd.getArguments() ); + main.run(); + } + //catch (ClassNotFoundException ex) { + // throw new BuildException("Cannot use javah because it is not available"+ + // " A common solution is to set the environment variable"+ + // " JAVA_HOME to your jdk directory.", location); + //} + catch (Exception ex) { + if (ex instanceof BuildException) { + throw (BuildException) ex; + } else { + throw new BuildException("Error starting javah: ", ex, location); + } + } finally { + System.setErr(err); + System.setOut(out); + } + } + + /** + * Does the command line argument processing common to classic and + * modern. + */ + private Commandline setupJavahCommand() { + Commandline cmd = new Commandline(); + + if (destDir != null) { + cmd.createArgument().setValue("-d"); + cmd.createArgument().setFile(destDir); + } + + if (outputFile != null) { + cmd.createArgument().setValue("-o"); + cmd.createArgument().setValue(outputFile); + } + + if (classpath != null) { + cmd.createArgument().setValue("-classpath"); + cmd.createArgument().setPath(classpath); + } + + // JDK1.1 is rather simpler than JDK1.2 + if (Project.getJavaVersion().startsWith("1.1")) { + if (verbose) { + cmd.createArgument().setValue("-v"); + } + } else { + if (verbose) { + cmd.createArgument().setValue("-verbose"); + } + if (old) { + cmd.createArgument().setValue("-old"); + } + if (force) { + cmd.createArgument().setValue("-force"); + } + } + + if (stubs) { + if (!old) { + throw new BuildException("stubs only available in old mode.", location); + } + cmd.createArgument().setValue("-stubs"); + } + if (bootclasspath != null) { + cmd.createArgument().setValue("-bootclasspath"); + cmd.createArgument().setPath(bootclasspath); + } + + logAndAddFilesToCompile(cmd); + return cmd; + } + + /** + * Logs the compilation parameters, adds the files to compile and logs the + * &qout;niceSourceList" + */ + protected void logAndAddFilesToCompile(Commandline cmd) { + int n = 0; + log("Compilation args: " + cmd.toString(), + Project.MSG_VERBOSE); + + StringBuffer niceClassList = new StringBuffer(); + if (cls != null) { + StringTokenizer tok = new StringTokenizer(cls, ",", false); + while (tok.hasMoreTokens()) { + String aClass = tok.nextToken().trim(); + cmd.createArgument().setValue(aClass); + niceClassList.append(" " + aClass + lSep); + n++; + } + } + + Enumeration enum = classes.elements(); + while (enum.hasMoreElements()) { + ClassArgument arg = (ClassArgument)enum.nextElement(); + String aClass = arg.getName(); + cmd.createArgument().setValue(aClass); + niceClassList.append(" " + aClass + lSep); + n++; + } + + StringBuffer prefix = new StringBuffer("Class"); + if (n > 1) { + prefix.append("es"); + } + prefix.append(" to be compiled:"); + prefix.append(lSep); + + log(prefix.toString() + niceClassList.toString(), Project.MSG_VERBOSE); + } + + ///** + // * Emulation of extdirs feature in java >= 1.2. + // * This method adds all files in the given + // * directories (but not in sub-directories!) to the classpath, + // * so that you don't have to specify them all one by one. + // * @param classpath - Path to append files to + // */ + //protected void addExtdirsToClasspath(Path classpath) { + // if (extdirs == null) { + // String extProp = System.getProperty("java.ext.dirs"); + // if (extProp != null) { + // extdirs = new Path(project, extProp); + // } else { + // return; + // } + // } + // + // String[] dirs = extdirs.list(); + // for (int i=0; i