~ubuntu-branches/ubuntu/jaunty/ant/jaunty-proposed

« back to all changes in this revision

Viewing changes to src/main/org/apache/tools/ant/taskdefs/optional/Javah.java

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Gybas
  • Date: 2002-02-14 14:28:48 UTC
  • Revision ID: james.westby@ubuntu.com-20020214142848-2ww7ynmqkj31vlmn
Tags: upstream-1.4.1
ImportĀ upstreamĀ versionĀ 1.4.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * The Apache Software License, Version 1.1
 
3
 *
 
4
 * Copyright (c) 2000 The Apache Software Foundation.  All rights
 
5
 * reserved.
 
6
 *
 
7
 * Redistribution and use in source and binary forms, with or without
 
8
 * modification, are permitted provided that the following conditions
 
9
 * are met:
 
10
 *
 
11
 * 1. Redistributions of source code must retain the above copyright
 
12
 *    notice, this list of conditions and the following disclaimer.
 
13
 *
 
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
 
17
 *    distribution.
 
18
 *
 
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.
 
25
 *
 
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.
 
30
 *
 
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.
 
34
 *
 
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
 
46
 * SUCH DAMAGE.
 
47
 * ====================================================================
 
48
 *
 
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/>.
 
53
 */
 
54
 
 
55
package org.apache.tools.ant.taskdefs.optional;
 
56
 
 
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.*;
 
63
 
 
64
import java.lang.reflect.Method;
 
65
import java.lang.reflect.Constructor;
 
66
import java.io.*;
 
67
import java.util.*;
 
68
 
 
69
/**
 
70
 * Task to generate JNI header files using javah. This task can take the following
 
71
 * arguments:
 
72
 * <ul>
 
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
 
77
 *     stub files</li>
 
78
 * <li>classpath</li>
 
79
 * <li>bootclasspath</li>
 
80
 * <li>force - Specifies that output files should always be written
 
81
       (JDK1.2 only)</li>
 
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>
 
89
 * </ul>
 
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>&lt;class name="xxx"&gt;</code> elements within the task.
 
93
 * <p>
 
94
 * When this task executes, it will generate C header and source files that
 
95
 * are needed to implement native methods.
 
96
 *
 
97
 * @author Rick Beton <a href="mailto:richard.beton@physics.org">richard.beton@physics.org</a>
 
98
 */
 
99
 
 
100
public class Javah extends Task {
 
101
 
 
102
    private static final String FAIL_MSG = "Compile failed, messages should have been provided.";
 
103
 
 
104
    private Vector classes = new Vector(2);
 
105
    private String cls;
 
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");
 
116
 
 
117
    public void setClass(String cls) {
 
118
        this.cls = cls;
 
119
    }
 
120
 
 
121
    public ClassArgument createClass() {
 
122
        ClassArgument ga = new ClassArgument();
 
123
        classes.addElement(ga);
 
124
        return ga;
 
125
    }
 
126
 
 
127
    public class ClassArgument {
 
128
        private String name;
 
129
 
 
130
        public ClassArgument() {
 
131
        }
 
132
 
 
133
        public void setName(String name) {
 
134
            this.name = name;
 
135
            log("ClassArgument.name="+name);
 
136
        }
 
137
 
 
138
        public String getName() {
 
139
            return name;
 
140
        }
 
141
    }
 
142
 
 
143
    /**
 
144
     * Set the destination directory into which the Java source
 
145
     * files should be compiled.
 
146
     */
 
147
    public void setDestdir(File destDir) {
 
148
        this.destDir = destDir;
 
149
    }
 
150
 
 
151
    public void setClasspath(Path src) {
 
152
        if (classpath == null) {
 
153
            classpath = src;
 
154
        } else {
 
155
            classpath.append(src);
 
156
        }
 
157
    }
 
158
    public Path createClasspath() {
 
159
        if (classpath == null) {
 
160
            classpath = new Path(project);
 
161
        }
 
162
        return classpath.createPath();
 
163
    }
 
164
 
 
165
    /**
 
166
     * Adds a reference to a CLASSPATH defined elsewhere.
 
167
     */
 
168
    public void setClasspathRef(Reference r) {
 
169
        createClasspath().setRefid(r);
 
170
    }
 
171
 
 
172
    public void setBootclasspath(Path src) {
 
173
        if (bootclasspath == null) {
 
174
            bootclasspath = src;
 
175
        } else {
 
176
            bootclasspath.append(src);
 
177
        }
 
178
    }
 
179
    public Path createBootclasspath() {
 
180
        if (bootclasspath == null) {
 
181
            bootclasspath = new Path(project);
 
182
        }
 
183
        return bootclasspath.createPath();
 
184
    }
 
185
 
 
186
    /**
 
187
     * Adds a reference to a CLASSPATH defined elsewhere.
 
188
     */
 
189
    public void setBootClasspathRef(Reference r) {
 
190
        createBootclasspath().setRefid(r);
 
191
    }
 
192
 
 
193
    ///**
 
194
    // * Sets the extension directories that will be used during the
 
195
    // * compilation.
 
196
    // */
 
197
    //public void setExtdirs(Path extdirs) {
 
198
    //    if (this.extdirs == null) {
 
199
    //        this.extdirs = extdirs;
 
200
    //    } else {
 
201
    //        this.extdirs.append(extdirs);
 
202
    //    }
 
203
    //}
 
204
 
 
205
    ///**
 
206
    // * Maybe creates a nested classpath element.
 
207
    // */
 
208
    //public Path createExtdirs() {
 
209
    //    if (extdirs == null) {
 
210
    //        extdirs = new Path(project);
 
211
    //    }
 
212
    //    return extdirs.createPath();
 
213
    //}
 
214
 
 
215
    /**
 
216
     * Set the output file name.
 
217
     */
 
218
    public void setOutputFile(File outputFile) {
 
219
        this.outputFile = outputFile;
 
220
    }
 
221
 
 
222
    /**
 
223
     * Set the force-write flag.
 
224
     */
 
225
    public void setForce(boolean force) {
 
226
        this.force = force;
 
227
    }
 
228
 
 
229
    /**
 
230
     * Set the old flag.
 
231
     */
 
232
    public void setOld(boolean old) {
 
233
        this.old = old;
 
234
    }
 
235
 
 
236
    /**
 
237
     * Set the stubs flag.
 
238
     */
 
239
    public void setStubs(boolean stubs) {
 
240
        this.stubs = stubs;
 
241
    }
 
242
 
 
243
    /**
 
244
     * Set the verbose flag.
 
245
     */
 
246
    public void setVerbose(boolean verbose) {
 
247
        this.verbose = verbose;
 
248
    }
 
249
 
 
250
    /**
 
251
     * Executes the task.
 
252
     */
 
253
    public void execute() throws BuildException {
 
254
        // first off, make sure that we've got a srcdir
 
255
 
 
256
        if ((cls == null) && (classes.size() == 0)) {
 
257
            throw new BuildException("class attribute must be set!", location);
 
258
        }
 
259
 
 
260
        if ((cls != null) && (classes.size() > 0)) {
 
261
            throw new BuildException("set class attribute or class element, not both.", location);
 
262
        }
 
263
 
 
264
        if (destDir != null) {
 
265
            if (!destDir.isDirectory()) {
 
266
                throw new BuildException("destination directory \"" + destDir + "\" does not exist or is not a directory", location);
 
267
            }
 
268
            if (outputFile != null) {
 
269
                throw new BuildException("destdir and outputFile are mutually exclusive", location);
 
270
            }
 
271
        }
 
272
 
 
273
        if (classpath == null) {
 
274
            classpath = Path.systemClasspath;
 
275
        }
 
276
 
 
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) {
 
281
                compiler = "modern";
 
282
            } else {
 
283
                compiler = "classic";
 
284
            }
 
285
        }
 
286
 
 
287
        doClassicCompile();
 
288
    }
 
289
 
 
290
    // XXX
 
291
    // we need a way to not use the current classpath.
 
292
 
 
293
    /**
 
294
     * Peforms a compile using the classic compiler that shipped with
 
295
     * JDK 1.1 and 1.2.
 
296
     */
 
297
 
 
298
    private void doClassicCompile() throws BuildException {
 
299
        Commandline cmd = setupJavahCommand();
 
300
 
 
301
        // Use reflection to be able to build on all JDKs
 
302
        /*
 
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");
 
306
 
 
307
        if (!compiler.compile(cmd.getArguments())) {
 
308
            throw new BuildException("Compile failed");
 
309
        }
 
310
        */
 
311
        try {
 
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() );
 
318
            main.run();
 
319
        }
 
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);
 
324
        //}
 
325
        catch (Exception ex) {
 
326
            if (ex instanceof BuildException) {
 
327
                throw (BuildException) ex;
 
328
            } else {
 
329
                throw new BuildException("Error starting javah: ", ex, location);
 
330
            }
 
331
        }
 
332
    }
 
333
 
 
334
    /**
 
335
     * Does the command line argument processing common to classic and
 
336
     * modern.
 
337
     */
 
338
    private Commandline setupJavahCommand() {
 
339
        Commandline cmd = new Commandline();
 
340
 
 
341
        if (destDir != null) {
 
342
            cmd.createArgument().setValue("-d");
 
343
            cmd.createArgument().setFile(destDir);
 
344
        }
 
345
 
 
346
        if (outputFile != null) {
 
347
            cmd.createArgument().setValue("-o");
 
348
            cmd.createArgument().setFile(outputFile);
 
349
        }
 
350
 
 
351
        if (classpath != null) {
 
352
            cmd.createArgument().setValue("-classpath");
 
353
            cmd.createArgument().setPath(classpath);
 
354
        }
 
355
 
 
356
        // JDK1.1 is rather simpler than JDK1.2
 
357
        if (Project.getJavaVersion().startsWith("1.1")) {
 
358
            if (verbose) {
 
359
                cmd.createArgument().setValue("-v");
 
360
            }
 
361
        } else {
 
362
            if (verbose) {
 
363
                cmd.createArgument().setValue("-verbose");
 
364
            }
 
365
            if (old) {
 
366
                cmd.createArgument().setValue("-old");
 
367
            }
 
368
            if (force) {
 
369
                cmd.createArgument().setValue("-force");
 
370
            }
 
371
        }
 
372
 
 
373
        if (stubs) {
 
374
            if (!old) {
 
375
                throw new BuildException("stubs only available in old mode.", location);
 
376
            }
 
377
            cmd.createArgument().setValue("-stubs");
 
378
        }
 
379
        if (bootclasspath != null) {
 
380
            cmd.createArgument().setValue("-bootclasspath");
 
381
            cmd.createArgument().setPath(bootclasspath);
 
382
        }
 
383
 
 
384
        logAndAddFilesToCompile(cmd);
 
385
        return cmd;
 
386
    }
 
387
 
 
388
    /**
 
389
     * Logs the compilation parameters, adds the files to compile and logs the
 
390
     * &qout;niceSourceList&quot;
 
391
     */
 
392
    protected void logAndAddFilesToCompile(Commandline cmd) {
 
393
        int n = 0;
 
394
        log("Compilation args: " + cmd.toString(),
 
395
            Project.MSG_VERBOSE);
 
396
 
 
397
        StringBuffer niceClassList = new StringBuffer();
 
398
        if (cls != null) {
 
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);
 
404
                n++;
 
405
            }
 
406
        }
 
407
 
 
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);
 
414
            n++;
 
415
        }
 
416
 
 
417
        StringBuffer prefix = new StringBuffer("Class");
 
418
        if (n > 1) {
 
419
            prefix.append("es");
 
420
        }
 
421
        prefix.append(" to be compiled:");
 
422
        prefix.append(lSep);
 
423
 
 
424
        log(prefix.toString() + niceClassList.toString(), Project.MSG_VERBOSE);
 
425
    }
 
426
}
 
427