2
* The Apache Software License, Version 1.1
4
* Copyright (c) 2000 The Apache Software Foundation. All rights
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
11
* 1. Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in
16
* the documentation and/or other materials provided with the
19
* 3. The end-user documentation included with the redistribution, if
20
* any, must include the following acknowlegement:
21
* "This product includes software developed by the
22
* Apache Software Foundation (http://www.apache.org/)."
23
* Alternately, this acknowlegement may appear in the software itself,
24
* if and wherever such third-party acknowlegements normally appear.
26
* 4. The names "The Jakarta Project", "Ant", and "Apache Software
27
* Foundation" must not be used to endorse or promote products derived
28
* from this software without prior written permission. For written
29
* permission, please contact apache@apache.org.
31
* 5. Products derived from this software may not be called "Apache"
32
* nor may "Apache" appear in their names without prior written
33
* permission of the Apache Group.
35
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47
* ====================================================================
49
* This software consists of voluntary contributions made by many
50
* individuals on behalf of the Apache Software Foundation. For more
51
* information on the Apache Software Foundation, please see
52
* <http://www.apache.org/>.
55
package org.apache.tools.ant.taskdefs.optional;
57
import org.apache.tools.ant.BuildException;
58
import org.apache.tools.ant.DirectoryScanner;
59
import org.apache.tools.ant.Project;
60
import org.apache.tools.ant.Task;
61
import org.apache.tools.ant.taskdefs.LogOutputStream;
62
import org.apache.tools.ant.types.*;
64
import java.lang.reflect.Method;
65
import java.lang.reflect.Constructor;
70
* Task to generate JNI header files using javah. This task can take the following
73
* <li>classname - the fully-qualified name of a class</li>
74
* <li>outputFile - Concatenates the resulting header or source files for all
75
* the classes listed into this file</li>
76
* <li>destdir - Sets the directory where javah saves the header files or the
79
* <li>bootclasspath</li>
80
* <li>force - Specifies that output files should always be written
82
* <li>old - Specifies that old JDK1.0-style header files should be generated
83
* (otherwise output file contain JNI-style native method
84
* function prototypes) (JDK1.2 only)</li>
85
* <li>stubs - generate C declarations from the Java object file (used with old)</li>
86
* <li>verbose - causes javah to print a message to stdout concerning the status
87
* of the generated files</li>
88
* <li>extdirs - Override location of installed extensions</li>
90
* Of these arguments, either <b>outputFile</b> or <b>destdir</b> is required,
91
* but not both. More than one classname may be specified, using a comma-separated
92
* list or by using <code><class name="xxx"></code> elements within the task.
94
* When this task executes, it will generate C header and source files that
95
* are needed to implement native methods.
97
* @author Rick Beton <a href="mailto:richard.beton@physics.org">richard.beton@physics.org</a>
100
public class Javah extends Task {
102
private static final String FAIL_MSG = "Compile failed, messages should have been provided.";
104
private Vector classes = new Vector(2);
106
private File destDir;
107
private Path classpath = null;
108
private File outputFile = null;
109
private boolean verbose = false;
110
private boolean force = false;
111
private boolean old = false;
112
private boolean stubs = false;
113
private Path bootclasspath;
114
//private Path extdirs;
115
private static String lSep = System.getProperty("line.separator");
117
public void setClass(String cls) {
121
public ClassArgument createClass() {
122
ClassArgument ga = new ClassArgument();
123
classes.addElement(ga);
127
public class ClassArgument {
130
public ClassArgument() {
133
public void setName(String name) {
135
log("ClassArgument.name="+name);
138
public String getName() {
144
* Set the destination directory into which the Java source
145
* files should be compiled.
147
public void setDestdir(File destDir) {
148
this.destDir = destDir;
151
public void setClasspath(Path src) {
152
if (classpath == null) {
155
classpath.append(src);
158
public Path createClasspath() {
159
if (classpath == null) {
160
classpath = new Path(project);
162
return classpath.createPath();
166
* Adds a reference to a CLASSPATH defined elsewhere.
168
public void setClasspathRef(Reference r) {
169
createClasspath().setRefid(r);
172
public void setBootclasspath(Path src) {
173
if (bootclasspath == null) {
176
bootclasspath.append(src);
179
public Path createBootclasspath() {
180
if (bootclasspath == null) {
181
bootclasspath = new Path(project);
183
return bootclasspath.createPath();
187
* Adds a reference to a CLASSPATH defined elsewhere.
189
public void setBootClasspathRef(Reference r) {
190
createBootclasspath().setRefid(r);
194
// * Sets the extension directories that will be used during the
197
//public void setExtdirs(Path extdirs) {
198
// if (this.extdirs == null) {
199
// this.extdirs = extdirs;
201
// this.extdirs.append(extdirs);
206
// * Maybe creates a nested classpath element.
208
//public Path createExtdirs() {
209
// if (extdirs == null) {
210
// extdirs = new Path(project);
212
// return extdirs.createPath();
216
* Set the output file name.
218
public void setOutputFile(File outputFile) {
219
this.outputFile = outputFile;
223
* Set the force-write flag.
225
public void setForce(boolean force) {
232
public void setOld(boolean old) {
237
* Set the stubs flag.
239
public void setStubs(boolean stubs) {
244
* Set the verbose flag.
246
public void setVerbose(boolean verbose) {
247
this.verbose = verbose;
253
public void execute() throws BuildException {
254
// first off, make sure that we've got a srcdir
256
if ((cls == null) && (classes.size() == 0)) {
257
throw new BuildException("class attribute must be set!", location);
260
if ((cls != null) && (classes.size() > 0)) {
261
throw new BuildException("set class attribute or class element, not both.", location);
264
if (destDir != null) {
265
if (!destDir.isDirectory()) {
266
throw new BuildException("destination directory \"" + destDir + "\" does not exist or is not a directory", location);
268
if (outputFile != null) {
269
throw new BuildException("destdir and outputFile are mutually exclusive", location);
273
if (classpath == null) {
274
classpath = Path.systemClasspath;
277
String compiler = project.getProperty("build.compiler");
278
if (compiler == null) {
279
if (Project.getJavaVersion() != Project.JAVA_1_1 &&
280
Project.getJavaVersion() != Project.JAVA_1_2) {
283
compiler = "classic";
291
// we need a way to not use the current classpath.
294
* Peforms a compile using the classic compiler that shipped with
298
private void doClassicCompile() throws BuildException {
299
Commandline cmd = setupJavahCommand();
301
// Use reflection to be able to build on all JDKs
303
// provide the compiler a different message sink - namely our own
304
sun.tools.javac.Main compiler =
305
new sun.tools.javac.Main(new LogOutputStream(this, Project.MSG_WARN), "javac");
307
if (!compiler.compile(cmd.getArguments())) {
308
throw new BuildException("Compile failed");
312
// Javac uses logstr to change the output stream and calls
313
// the constructor's invoke method to create a compiler instance
314
// dynamically. However, javah has a different interface and this
315
// makes it harder, so here's a simple alternative.
316
//------------------------------------------------------------------
317
com.sun.tools.javah.Main main = new com.sun.tools.javah.Main( cmd.getArguments() );
320
//catch (ClassNotFoundException ex) {
321
// throw new BuildException("Cannot use javah because it is not available"+
322
// " A common solution is to set the environment variable"+
323
// " JAVA_HOME to your jdk directory.", location);
325
catch (Exception ex) {
326
if (ex instanceof BuildException) {
327
throw (BuildException) ex;
329
throw new BuildException("Error starting javah: ", ex, location);
335
* Does the command line argument processing common to classic and
338
private Commandline setupJavahCommand() {
339
Commandline cmd = new Commandline();
341
if (destDir != null) {
342
cmd.createArgument().setValue("-d");
343
cmd.createArgument().setFile(destDir);
346
if (outputFile != null) {
347
cmd.createArgument().setValue("-o");
348
cmd.createArgument().setFile(outputFile);
351
if (classpath != null) {
352
cmd.createArgument().setValue("-classpath");
353
cmd.createArgument().setPath(classpath);
356
// JDK1.1 is rather simpler than JDK1.2
357
if (Project.getJavaVersion().startsWith("1.1")) {
359
cmd.createArgument().setValue("-v");
363
cmd.createArgument().setValue("-verbose");
366
cmd.createArgument().setValue("-old");
369
cmd.createArgument().setValue("-force");
375
throw new BuildException("stubs only available in old mode.", location);
377
cmd.createArgument().setValue("-stubs");
379
if (bootclasspath != null) {
380
cmd.createArgument().setValue("-bootclasspath");
381
cmd.createArgument().setPath(bootclasspath);
384
logAndAddFilesToCompile(cmd);
389
* Logs the compilation parameters, adds the files to compile and logs the
390
* &qout;niceSourceList"
392
protected void logAndAddFilesToCompile(Commandline cmd) {
394
log("Compilation args: " + cmd.toString(),
395
Project.MSG_VERBOSE);
397
StringBuffer niceClassList = new StringBuffer();
399
StringTokenizer tok = new StringTokenizer(cls, ",", false);
400
while (tok.hasMoreTokens()) {
401
String aClass = tok.nextToken().trim();
402
cmd.createArgument().setValue(aClass);
403
niceClassList.append(" " + aClass + lSep);
408
Enumeration enum = classes.elements();
409
while (enum.hasMoreElements()) {
410
ClassArgument arg = (ClassArgument)enum.nextElement();
411
String aClass = arg.getName();
412
cmd.createArgument().setValue(aClass);
413
niceClassList.append(" " + aClass + lSep);
417
StringBuffer prefix = new StringBuffer("Class");
421
prefix.append(" to be compiled:");
424
log(prefix.toString() + niceClassList.toString(), Project.MSG_VERBOSE);