summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2003-05-08 03:36:18 (GMT)
committerSteven Knight <knight@baldmt.com>2003-05-08 03:36:18 (GMT)
commitd5aff94f2c90a162e2c36775b0fc80cabdc7ad64 (patch)
tree73310e2d7ed667650164c2c509aed9387af83b07
parent28cc07ab75b300171d03395b7dedfae5a77cdc2d (diff)
downloadSCons-d5aff94f2c90a162e2c36775b0fc80cabdc7ad64.zip
SCons-d5aff94f2c90a162e2c36775b0fc80cabdc7ad64.tar.gz
SCons-d5aff94f2c90a162e2c36775b0fc80cabdc7ad64.tar.bz2
Add support for JavaH.
-rw-r--r--bin/files3
-rw-r--r--doc/man/scons.159
-rw-r--r--src/CHANGES.txt4
-rw-r--r--src/engine/MANIFEST.in3
-rw-r--r--src/engine/SCons/Tool/__init__.py2
-rw-r--r--src/engine/SCons/Tool/javac.py42
-rw-r--r--src/engine/SCons/Tool/javah.py124
-rw-r--r--test/JAVAC.py44
-rw-r--r--test/JAVAH.py286
-rw-r--r--test/Repository/JavaH.py295
10 files changed, 821 insertions, 41 deletions
diff --git a/bin/files b/bin/files
index 3af1572..c22c426 100644
--- a/bin/files
+++ b/bin/files
@@ -50,6 +50,9 @@
./SCons/Tool/icc.py
./SCons/Tool/ifl.py
./SCons/Tool/ilink.py
+./SCons/Tool/jar.py
+./SCons/Tool/javac.py
+./SCons/Tool/javah.py
./SCons/Tool/latex.py
./SCons/Tool/lex.py
./SCons/Tool/link.py
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index e6f72b9..2cbf048 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -1329,6 +1329,45 @@ Example:
env.Java(target = 'classes', source = 'src')
.EE
+.IP JavaH
+Builds C header and source files for
+implementing Java native methods.
+The target can be either a directory
+in which the header files will be written,
+or a header file name which
+will contain all of the definitions.
+The source can be either the names of .class files,
+or the objects returned from the
+.B Java
+builder.
+
+If the construction variable
+.B JAVACLASSDIR
+is set, either in the environment
+or in the call to the
+.B JavaH
+builder itself,
+then the value of the variable
+will be stripped from the
+beginning of any .class file names.
+
+Examples:
+
+.ES
+# builds java_native.h
+classes = env.Java(target = 'classdir', source = 'src')
+env.JavaH(target = 'java_native.h', source = classes)
+
+# builds include/package_foo.h and include/package_bar.h
+env.JavaH(target = 'include',
+ source = ['package/foo.class', 'package/bar.class'])
+
+# builds export/foo.h and export/bar.h
+env.JavaH(target = 'export',
+ source = ['classes/foo.class', 'classes/bar.class'],
+ JAVACLASSDIR = 'classes')
+.EE
+
.IP TypeLibrary
Builds a Windows type library (.tlb) file from and input IDL file
(.idl). In addition, it will build the associated inteface stub and
@@ -2385,11 +2424,31 @@ are included on this command line.
.IP JAVACFLAGS
General options that are passed to the Java compiler.
+.IP JAVACLASSDIR
+The directory in which Java class files may be found.
+This is stripped from the beginning of any Java .class
+file names supplied to the
+.B JavaH
+builder.
+
.IP JAVACLASSSUFFIX
The suffix for Java class files;
.B .class
by default.
+.IP JAVAH
+The Java generator for C header and stub files.
+
+.IP JAVAHCOM
+The command line used to generate C header and stub files
+from Java classes.
+Any options specified in the $JAVAHFLAGS construction variable
+are included on this command line.
+
+.IP JAVAHFLAGS
+General options passed to the C header and stub file generator
+for Java classes.
+
.IP JAVASUFFIX
The suffix for Java files;
.B .java
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 6c6bcfb..1cd8565 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -48,7 +48,7 @@ RELEASE 0.14 - XXX
- Parse the source .java files for class names (including inner class
names) to figure out the target .class files that will be created.
- - Fix Java support with Repositories and SConscriptChdir(0).
+ - Make Java support work with Repositories and SConscriptChdir(0).
- Pass Nodes, not strings, to Builder emitter functions.
@@ -57,7 +57,7 @@ RELEASE 0.14 - XXX
From Steven Knight:
- - Add support for Java (javac and jar).
+ - Add Java support (javac, javah and jar).
- Propagate the external SYSTEMROOT environment variable into ENV on
Win32 systems, so external commands that use sockets will work.
diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in
index c028989..03b2c04 100644
--- a/src/engine/MANIFEST.in
+++ b/src/engine/MANIFEST.in
@@ -58,8 +58,9 @@ SCons/Tool/gnulink.py
SCons/Tool/gs.py
SCons/Tool/hpcc.py
SCons/Tool/hplink.py
-SCons/Tool/javac.py
SCons/Tool/jar.py
+SCons/Tool/javac.py
+SCons/Tool/javah.py
SCons/Tool/icc.py
SCons/Tool/ifl.py
SCons/Tool/ilink.py
diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py
index 8f2f63c..25d7462 100644
--- a/src/engine/SCons/Tool/__init__.py
+++ b/src/engine/SCons/Tool/__init__.py
@@ -223,7 +223,7 @@ def tool_list(platform, env):
other_tools = FindAllTools(['BitKeeper', 'CVS',
'dvipdf', 'dvips', 'gs',
- 'jar', 'javac',
+ 'jar', 'javac', 'javah',
'latex', 'lex', 'midl',
'pdflatex', 'pdftex', 'Perforce',
'RCS', 'SCCS',
diff --git a/src/engine/SCons/Tool/javac.py b/src/engine/SCons/Tool/javac.py
index 8606c02..be600f1 100644
--- a/src/engine/SCons/Tool/javac.py
+++ b/src/engine/SCons/Tool/javac.py
@@ -33,6 +33,7 @@ selection method.
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+import os
import os.path
import re
import string
@@ -225,55 +226,66 @@ else:
"""
return os.path.split(file)
-def emit_java_files(target, source, env):
+def classname(path):
+ """Turn a string (path name) into a Java class name."""
+ return string.replace(os.path.normpath(path), os.sep, '.')
+
+def emit_java_classes(target, source, env):
"""Create and return lists of source java files
and their corresponding target class files.
"""
- env['_JAVACLASSDIR'] = target[0]
- env['_JAVASRCDIR'] = source[0].rdir()
java_suffix = env.get('JAVASUFFIX', '.java')
class_suffix = env.get('JAVACLASSSUFFIX', '.class')
-
+
slist = []
js = _my_normcase(java_suffix)
def visit(arg, dirname, names, js=js, dirnode=source[0].rdir()):
java_files = filter(lambda n, js=js:
- _my_normcase(n[-len(js):]) == js,
+ _my_normcase(n[-len(js):]) == js,
names)
mydir = dirnode.Dir(dirname)
java_paths = map(lambda f, d=mydir: d.File(f), java_files)
arg.extend(java_paths)
os.path.walk(source[0].rdir().get_abspath(), visit, slist)
-
+
tlist = []
for file in slist:
pkg_dir, classes = parse_java(file.get_abspath())
if pkg_dir:
for c in classes:
- tlist.append(target[0].Dir(pkg_dir).File(c+class_suffix))
+ t = target[0].Dir(pkg_dir).File(c+class_suffix)
+ t.attributes.java_classdir = target[0]
+ t.attributes.java_classname = classname(pkg_dir + os.sep + c)
+ tlist.append(t)
elif classes:
for c in classes:
- tlist.append(target[0].File(c+class_suffix))
+ t = target[0].File(c+class_suffix)
+ t.attributes.java_classdir = target[0]
+ t.attributes.java_classname = classname(c)
+ tlist.append(t)
else:
# This is an odd end case: no package and no classes.
# Just do our best based on the source file name.
- tlist.append(target[0].File(str(file)[:-len(java_suffix)] + class_suffix))
-
+ base = str(file)[:-len(java_suffix)]
+ t = target[0].File(base + class_suffix)
+ t.attributes.java_classdir = target[0]
+ t.attributes.java_classname = classname(base)
+ tlist.append(t)
+
return tlist, slist
JavaBuilder = SCons.Builder.Builder(action = '$JAVACCOM',
- emitter = emit_java_files,
- target_factory = SCons.Node.FS.default_fs.Dir,
- source_factory = SCons.Node.FS.default_fs.Dir)
+ emitter = emit_java_classes,
+ target_factory = SCons.Node.FS.default_fs.Dir,
+ source_factory = SCons.Node.FS.default_fs.Dir)
def generate(env):
"""Add Builders and construction variables for javac to an Environment."""
-
env['BUILDERS']['Java'] = JavaBuilder
env['JAVAC'] = 'javac'
env['JAVACFLAGS'] = ''
- env['JAVACCOM'] = '$JAVAC $JAVACFLAGS -d $_JAVACLASSDIR -sourcepath $_JAVASRCDIR $SOURCES'
+ env['JAVACCOM'] = '$JAVAC $JAVACFLAGS -d ${TARGET.attributes.java_classdir} -sourcepath ${SOURCE.dir.rdir()} $SOURCES'
env['JAVACLASSSUFFIX'] = '.class'
env['JAVASUFFIX'] = '.java'
diff --git a/src/engine/SCons/Tool/javah.py b/src/engine/SCons/Tool/javah.py
new file mode 100644
index 0000000..45fa4af
--- /dev/null
+++ b/src/engine/SCons/Tool/javah.py
@@ -0,0 +1,124 @@
+"""SCons.Tool.javah
+
+Tool-specific initialization for javah.
+
+There normally shouldn't be any need to import this module directly.
+It will usually be imported through the generic SCons.Tool.Tool()
+selection method.
+
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os.path
+import re
+import string
+
+import SCons.Builder
+import SCons.Node.FS
+
+def emit_java_headers(target, source, env):
+ """Create and return lists of Java stub header files that will
+ be created from a set of class files.
+ """
+ class_suffix = env.get('JAVACLASSSUFFIX', '.class')
+ classdir = env.get('JAVACLASSDIR')
+
+ if not classdir:
+ try:
+ s = source[0]
+ except IndexError:
+ classdir = '.'
+ else:
+ try:
+ classdir = s.attributes.java_classdir
+ except:
+ pass
+ classdir = SCons.Node.FS.default_fs.Dir(classdir).rdir()
+ if str(classdir) == '.':
+ c_ = None
+ else:
+ c_ = str(classdir) + os.sep
+
+ slist = []
+ for src in source:
+ try:
+ classname = src.attributes.java_classname
+ except AttributeError:
+ classname = str(src)
+ if c_ and classname[:len(c_)] == c_:
+ classname = classname[len(c_):]
+ if class_suffix and classname[:-len(class_suffix)] == class_suffix:
+ classname = classname[-len(class_suffix):]
+ s = src.rfile()
+ s.attributes.java_classdir = classdir
+ s.attributes.java_classname = classname
+ slist.append(s)
+
+ if target[0].__class__ is SCons.Node.FS.File:
+ tlist = target
+ else:
+ if not isinstance(target[0], SCons.Node.FS.Dir):
+ target[0].__class__ = SCons.Node.FS.Dir
+ target[0]._morph()
+ File = SCons.Node.FS.default_fs.File
+ tlist = []
+ for s in source:
+ fname = string.replace(s.attributes.java_classname, '.', '_') + '.h'
+ t = target[0].File(fname)
+ t.attributes.java_lookupdir = target[0]
+ tlist.append(t)
+
+ return tlist, source
+
+def JavaHOutFlagGenerator(target, source, env, for_signature):
+ try:
+ t = target[0]
+ except AttributeError, TypeError:
+ t = target
+ try:
+ return '-d ' + str(t.attributes.java_lookupdir)
+ except AttributeError:
+ return '-o ' + str(t)
+
+JavaHBuilder = SCons.Builder.Builder(action = '$JAVAHCOM',
+ emitter = emit_java_headers,
+ src_suffix = '$JAVACLASSSUFFIX',
+ target_factory = SCons.Node.FS.default_fs.Entry,
+ source_factory = SCons.Node.FS.default_fs.File)
+
+def generate(env):
+ """Add Builders and construction variables for javah to an Environment."""
+ env['BUILDERS']['JavaH'] = JavaHBuilder
+
+ env['_JAVAHOUTFLAG'] = JavaHOutFlagGenerator
+ env['JAVAH'] = 'javah'
+ env['JAVAHFLAGS'] = ''
+ env['JAVAHCOM'] = '$JAVAH $JAVAHFLAGS $_JAVAHOUTFLAG -classpath ${SOURCE.attributes.java_classdir} ${SOURCES.attributes.java_classname}'
+ env['JAVACLASSSUFFIX'] = '.class'
+
+def exists(env):
+ return env.Detect('javah')
diff --git a/test/JAVAC.py b/test/JAVAC.py
index 3bc84c7..13d4670 100644
--- a/test/JAVAC.py
+++ b/test/JAVAC.py
@@ -109,9 +109,9 @@ foo = Environment(tools = ['javac'],
JAVAC = '/usr/local/j2sdk1.3.1/bin/javac')
javac = foo.Dictionary('JAVAC')
bar = foo.Copy(JAVAC = r'%s wrapper.py ' + javac)
-foo.Java(target = 'classes', source = 'com/sub/foo')
-bar.Java(target = 'classes', source = 'com/sub/bar')
-foo.Java(target = 'classes', source = 'src')
+foo.Java(target = 'class1', source = 'com/sub/foo')
+bar.Java(target = 'class2', source = 'com/sub/bar')
+foo.Java(target = 'class3', source = 'src')
""" % python)
test.subdir('com',
@@ -265,25 +265,25 @@ class Private {
test.run(arguments = '.')
-test.fail_test(test.read('wrapper.out') != "wrapper.py /usr/local/j2sdk1.3.1/bin/javac -d classes -sourcepath com/sub/bar com/sub/bar/Example4.java com/sub/bar/Example5.java com/sub/bar/Example6.java\n")
-
-test.fail_test(not os.path.exists(test.workpath('classes', 'com', 'sub', 'foo', 'Example1.class')))
-test.fail_test(not os.path.exists(test.workpath('classes', 'com', 'other', 'Example2.class')))
-test.fail_test(not os.path.exists(test.workpath('classes', 'com', 'sub', 'foo', 'Example3.class')))
-
-test.fail_test(not os.path.exists(test.workpath('classes', 'com', 'sub', 'bar', 'Example4.class')))
-test.fail_test(not os.path.exists(test.workpath('classes', 'com', 'other', 'Example5.class')))
-test.fail_test(not os.path.exists(test.workpath('classes', 'com', 'sub', 'bar', 'Example6.class')))
-
-test.fail_test(not os.path.exists(test.workpath('classes', 'Empty.class')))
-test.fail_test(not os.path.exists(test.workpath('classes', 'Listener.class')))
-test.fail_test(not os.path.exists(test.workpath('classes', 'Private.class')))
-test.fail_test(not os.path.exists(test.workpath('classes', 'Private$1.class')))
-test.fail_test(not os.path.exists(test.workpath('classes', 'Test.class')))
-test.fail_test(not os.path.exists(test.workpath('classes', 'Test$1.class')))
-test.fail_test(not os.path.exists(test.workpath('classes', 'Test$2.class')))
-test.fail_test(not os.path.exists(test.workpath('classes', 'Test$3.class')))
-test.fail_test(not os.path.exists(test.workpath('classes', 'Test$Inner.class')))
+test.fail_test(test.read('wrapper.out') != "wrapper.py /usr/local/j2sdk1.3.1/bin/javac -d class2 -sourcepath com/sub/bar com/sub/bar/Example4.java com/sub/bar/Example5.java com/sub/bar/Example6.java\n")
+
+test.fail_test(not os.path.exists(test.workpath('class1', 'com', 'sub', 'foo', 'Example1.class')))
+test.fail_test(not os.path.exists(test.workpath('class1', 'com', 'other', 'Example2.class')))
+test.fail_test(not os.path.exists(test.workpath('class1', 'com', 'sub', 'foo', 'Example3.class')))
+
+test.fail_test(not os.path.exists(test.workpath('class2', 'com', 'sub', 'bar', 'Example4.class')))
+test.fail_test(not os.path.exists(test.workpath('class2', 'com', 'other', 'Example5.class')))
+test.fail_test(not os.path.exists(test.workpath('class2', 'com', 'sub', 'bar', 'Example6.class')))
+
+test.fail_test(not os.path.exists(test.workpath('class3', 'Empty.class')))
+test.fail_test(not os.path.exists(test.workpath('class3', 'Listener.class')))
+test.fail_test(not os.path.exists(test.workpath('class3', 'Private.class')))
+test.fail_test(not os.path.exists(test.workpath('class3', 'Private$1.class')))
+test.fail_test(not os.path.exists(test.workpath('class3', 'Test.class')))
+test.fail_test(not os.path.exists(test.workpath('class3', 'Test$1.class')))
+test.fail_test(not os.path.exists(test.workpath('class3', 'Test$2.class')))
+test.fail_test(not os.path.exists(test.workpath('class3', 'Test$3.class')))
+test.fail_test(not os.path.exists(test.workpath('class3', 'Test$Inner.class')))
test.up_to_date(arguments = '.')
diff --git a/test/JAVAH.py b/test/JAVAH.py
new file mode 100644
index 0000000..beae7a9
--- /dev/null
+++ b/test/JAVAH.py
@@ -0,0 +1,286 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os
+import string
+import sys
+import TestSCons
+
+python = TestSCons.python
+
+test = TestSCons.TestSCons()
+
+test.write('myjavah.py', r"""
+import sys
+args = sys.argv[1:]
+while args:
+ a = args[0]
+ if a == '-d':
+ args = args[1:]
+ elif a == '-sourcepath':
+ args = args[1:]
+ else:
+ break
+ args = args[1:]
+for file in args:
+ infile = open(file, 'rb')
+ outfile = open(file[:-5] + '.class', 'wb')
+ for l in infile.readlines():
+ if l[:9] != '/*javah*/':
+ outfile.write(l)
+sys.exit(0)
+""")
+
+test.write('SConstruct', """
+env = Environment(tools = ['javah'],
+ JAVAH = r'%s myjavah.py')
+env.JavaH(target = 'test1.class', source = 'test1.java')
+""" % (python))
+
+test.write('test1.java', """\
+test1.java
+/*javah*/
+line 3
+""")
+
+#test.run(arguments = '.', stderr = None)
+
+#test.fail_test(test.read('test1.class') != "test1.java\nline 3\n")
+
+if os.path.normcase('.java') == os.path.normcase('.JAVA'):
+
+ test.write('SConstruct', """\
+env = Environment(tools = ['javah'],
+ JAVAH = r'%s myjavah.py')
+env.Java(target = 'test2.class', source = 'test2.JAVA')
+""" % python)
+
+ test.write('test2.JAVA', """\
+test2.JAVA
+/*javah*/
+line 3
+""")
+
+ test.run(arguments = '.', stderr = None)
+
+ test.fail_test(test.read('test2.class') != "test2.JAVA\nline 3\n")
+
+
+if not os.path.exists('/usr/local/j2sdk1.3.1/bin/javah'):
+ print "Could not find Java, skipping test(s)."
+ test.pass_test(1)
+
+
+
+test.write("wrapper.py", """\
+import os
+import string
+import sys
+open('%s', 'ab').write("wrapper.py %%s\\n" %% string.join(sys.argv[1:]))
+os.system(string.join(sys.argv[1:], " "))
+""" % string.replace(test.workpath('wrapper.out'), '\\', '\\\\'))
+
+test.write('SConstruct', """
+foo = Environment(tools = ['javac', 'javah'],
+ JAVAC = '/usr/local/j2sdk1.3.1/bin/javac',
+ JAVAH = '/usr/local/j2sdk1.3.1/bin/javah')
+javah = foo.Dictionary('JAVAH')
+bar = foo.Copy(JAVAH = r'%s wrapper.py ' + javah)
+fff = foo.Java(target = 'class1', source = 'com/sub/foo')
+bar_classes = bar.Java(target = 'class2', source = 'com/sub/bar')
+foo_classes = foo.Java(target = 'class3', source = 'src')
+foo.JavaH(target = 'outdir1',
+ source = ['class1/com/sub/foo/Example1.class',
+ 'class1/com/other/Example2',
+ 'class1/com/sub/foo/Example3'],
+ JAVACLASSDIR = 'class1')
+bar.JavaH(target = 'outdir2', source = bar_classes)
+foo.JavaH(target = File('output.h'), source = foo_classes)
+""" % python)
+
+test.subdir('com',
+ ['com', 'sub'],
+ ['com', 'sub', 'foo'],
+ ['com', 'sub', 'bar'],
+ 'src')
+
+test.write(['com', 'sub', 'foo', 'Example1.java'], """\
+package com.sub.foo;
+
+public class Example1
+{
+
+ public static void main(String[] args)
+ {
+
+ }
+
+}
+""")
+
+test.write(['com', 'sub', 'foo', 'Example2.java'], """\
+package com.other;
+
+public class Example2
+{
+
+ public static void main(String[] args)
+ {
+
+ }
+
+}
+""")
+
+test.write(['com', 'sub', 'foo', 'Example3.java'], """\
+package com.sub.foo;
+
+public class Example3
+{
+
+ public static void main(String[] args)
+ {
+
+ }
+
+}
+""")
+
+test.write(['com', 'sub', 'bar', 'Example4.java'], """\
+package com.sub.bar;
+
+public class Example4
+{
+
+ public static void main(String[] args)
+ {
+
+ }
+
+}
+""")
+
+test.write(['com', 'sub', 'bar', 'Example5.java'], """\
+package com.other;
+
+public class Example5
+{
+
+ public static void main(String[] args)
+ {
+
+ }
+
+}
+""")
+
+test.write(['com', 'sub', 'bar', 'Example6.java'], """\
+package com.sub.bar;
+
+public class Example6
+{
+
+ public static void main(String[] args)
+ {
+
+ }
+
+}
+""")
+
+test.write(['src', 'Test.java'], """\
+class Empty {
+}
+
+interface Listener {
+ public void execute();
+}
+
+public
+class
+Test {
+ class Inner {
+ void go() {
+ use(new Listener() {
+ public void execute() {
+ System.out.println("In Inner");
+ }
+ });
+ }
+ String s1 = "class A";
+ String s2 = "new Listener() { }";
+ /* class B */
+ /* new Listener() { } */
+ }
+
+ public static void main(String[] args) {
+ new Test().run();
+ }
+
+ void run() {
+ use(new Listener() {
+ public void execute() {
+ use(new Listener( ) {
+ public void execute() {
+ System.out.println("Inside execute()");
+ }
+ });
+ }
+ });
+
+ new Inner().go();
+ }
+
+ void use(Listener l) {
+ l.execute();
+ }
+}
+
+class Private {
+ void run() {
+ new Listener() {
+ public void execute() {
+ }
+ };
+ }
+}
+""")
+
+test.run(arguments = '.')
+
+test.fail_test(test.read('wrapper.out') != "wrapper.py /usr/local/j2sdk1.3.1/bin/javah -d outdir2 -classpath class2 com.sub.bar.Example4 com.other.Example5 com.sub.bar.Example6\n")
+
+test.fail_test(not os.path.exists(test.workpath('outdir1', 'com_sub_foo_Example1.h')))
+test.fail_test(not os.path.exists(test.workpath('outdir1', 'com_other_Example2.h')))
+test.fail_test(not os.path.exists(test.workpath('outdir1', 'com_sub_foo_Example3.h')))
+
+test.fail_test(not os.path.exists(test.workpath('outdir2', 'com_sub_bar_Example4.h')))
+test.fail_test(not os.path.exists(test.workpath('outdir2', 'com_other_Example5.h')))
+test.fail_test(not os.path.exists(test.workpath('outdir2', 'com_sub_bar_Example6.h')))
+
+test.up_to_date(arguments = '.')
+
+test.pass_test()
diff --git a/test/Repository/JavaH.py b/test/Repository/JavaH.py
new file mode 100644
index 0000000..c11ad2b
--- /dev/null
+++ b/test/Repository/JavaH.py
@@ -0,0 +1,295 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test building Java applications when using Repositories.
+"""
+
+import os
+import string
+import sys
+import TestSCons
+
+python = TestSCons.python
+
+test = TestSCons.TestSCons()
+
+java = '/usr/local/j2sdk1.3.1/bin/java'
+javac = '/usr/local/j2sdk1.3.1/bin/javac'
+javah = '/usr/local/j2sdk1.3.1/bin/javah'
+
+if not os.path.exists(javac):
+ print "Could not find Java (javac), skipping test(s)."
+ test.pass_test(1)
+
+if not os.path.exists(javah):
+ print "Could not find Java (javah), skipping test(s)."
+ test.pass_test(1)
+
+###############################################################################
+
+#
+test.subdir('rep1', ['rep1', 'src'],
+ 'work1',
+ 'work2',
+ 'work3')
+
+#
+rep1_classes = test.workpath('rep1', 'classes')
+work1_classes = test.workpath('work1', 'classes')
+work3_classes = test.workpath('work3', 'classes')
+
+#
+opts = '-Y ' + test.workpath('rep1')
+
+#
+test.write(['rep1', 'SConstruct'], """
+env = Environment(tools = ['javac', 'javah'],
+ JAVAC = r'%s',
+ JAVAH = r'%s')
+classes = env.Java(target = 'classes', source = 'src')
+env.JavaH(target = 'outdir', source = classes)
+""" % (javac, javah))
+
+test.write(['rep1', 'src', 'Foo1.java'], """\
+public class Foo1
+{
+ public static void main(String[] args)
+ {
+ System.out.println("rep1/src/Foo1.java");
+
+ }
+}
+""")
+
+test.write(['rep1', 'src', 'Foo2.java'], """\
+public class Foo2
+{
+ public static void main(String[] args)
+ {
+ System.out.println("rep1/src/Foo2.java");
+
+ }
+}
+""")
+
+test.write(['rep1', 'src', 'Foo3.java'], """\
+public class Foo3
+{
+ public static void main(String[] args)
+ {
+ System.out.println("rep1/src/Foo3.java");
+
+ }
+}
+""")
+
+# Make the repository non-writable,
+# so we'll detect if we try to write into it accidentally.
+test.writable('repository', 0)
+
+#
+test.run(chdir = 'work1', options = opts, arguments = ".")
+
+test.run(program = java,
+ arguments = "-cp %s Foo1" % work1_classes,
+ stdout = "rep1/src/Foo1.java\n")
+
+test.run(program = java,
+ arguments = "-cp %s Foo2" % work1_classes,
+ stdout = "rep1/src/Foo2.java\n")
+
+test.run(program = java,
+ arguments = "-cp %s Foo3" % work1_classes,
+ stdout = "rep1/src/Foo3.java\n")
+
+test.fail_test(not os.path.exists(test.workpath('work1', 'outdir', 'Foo1.h')))
+test.fail_test(not os.path.exists(test.workpath('work1', 'outdir', 'Foo2.h')))
+test.fail_test(not os.path.exists(test.workpath('work1', 'outdir', 'Foo3.h')))
+
+test.up_to_date(chdir = 'work1', options = opts, arguments = ".")
+
+#
+test.subdir(['work1', 'src'])
+
+test.write(['work1', 'src', 'Foo1.java'], """\
+public class Foo1
+{
+ public static void main(String[] args)
+ {
+ System.out.println("work1/src/Foo1.java");
+
+ }
+}
+""")
+
+test.write(['work1', 'src', 'Foo2.java'], """\
+public class Foo2
+{
+ public static void main(String[] args)
+ {
+ System.out.println("work1/src/Foo2.java");
+
+ }
+}
+""")
+
+test.write(['work1', 'src', 'Foo3.java'], """\
+public class Foo3
+{
+ public static void main(String[] args)
+ {
+ System.out.println("work1/src/Foo3.java");
+
+ }
+}
+""")
+
+test.run(chdir = 'work1', options = opts, arguments = ".")
+
+test.run(program = java,
+ arguments = "-cp %s Foo1" % work1_classes,
+ stdout = "work1/src/Foo1.java\n")
+
+test.run(program = java,
+ arguments = "-cp %s Foo2" % work1_classes,
+ stdout = "work1/src/Foo2.java\n")
+
+test.run(program = java,
+ arguments = "-cp %s Foo3" % work1_classes,
+ stdout = "work1/src/Foo3.java\n")
+
+test.up_to_date(chdir = 'work1', options = opts, arguments = ".")
+
+#
+test.writable('rep1', 1)
+
+test.run(chdir = 'rep1', options = opts, arguments = ".")
+
+test.run(program = java,
+ arguments = "-cp %s Foo1" % rep1_classes,
+ stdout = "rep1/src/Foo1.java\n")
+
+test.run(program = java,
+ arguments = "-cp %s Foo2" % rep1_classes,
+ stdout = "rep1/src/Foo2.java\n")
+
+test.run(program = java,
+ arguments = "-cp %s Foo3" % rep1_classes,
+ stdout = "rep1/src/Foo3.java\n")
+
+test.up_to_date(chdir = 'rep1', options = opts, arguments = ".")
+
+#
+test.writable('repository', 0)
+
+#
+test.up_to_date(chdir = 'work2', options = opts, arguments = ".")
+
+#
+test.write(['work3', 'SConstruct'], """
+env = Environment(tools = ['javac', 'javah'],
+ JAVAC = r'%s',
+ JAVAH = r'%s')
+classes = env.Java(target = 'classes', source = 'src')
+hfiles = env.JavaH(target = 'outdir', source = classes)
+Local(hfiles)
+""" % (javac, javah))
+
+test.run(chdir = 'work3', options = opts, arguments = ".")
+
+test.fail_test(os.path.exists(test.workpath('work3', 'classes', 'Foo1.class')))
+test.fail_test(os.path.exists(test.workpath('work3', 'classes', 'Foo2.class')))
+test.fail_test(os.path.exists(test.workpath('work3', 'classes', 'Foo3.class')))
+
+test.fail_test(not os.path.exists(test.workpath('work3', 'outdir', 'Foo1.h')))
+test.fail_test(not os.path.exists(test.workpath('work3', 'outdir', 'Foo2.h')))
+test.fail_test(not os.path.exists(test.workpath('work3', 'outdir', 'Foo3.h')))
+
+#
+# If the Java builder were to interact with Repositories like the
+# other builders, then we'd uncomment the following test(s).
+#
+# This tests that, if the .class files are built in the repository,
+# then a local build says that everything is up-to-date. However,
+# because the destination target is a directory ("classes") not a
+# file, we don't detect that the individual .class files are
+# already there, and think things must be rebuilt.
+#
+#test.up_to_date(chdir = 'work2', options = opts, arguments = ".")
+#
+#test.subdir(['work2', 'src'])
+#
+#test.write(['work2', 'src', 'Foo1.java'], """\
+#public class Foo1
+#{
+# public static void main(String[] args)
+# {
+# System.out.println("work2/src/Foo1.java");
+#
+# }
+#}
+#""")
+#
+#test.write(['work2', 'src', 'Foo2.java'], """\
+#public class Foo2
+#{
+# public static void main(String[] args)
+# {
+# System.out.println("work2/src/Foo2.java");
+#
+# }
+#}
+#""")
+#
+#test.write(['work2', 'src', 'Foo3.java'], """\
+#public class Foo3
+#{
+# public static void main(String[] args)
+# {
+# System.out.println("work2/src/Foo3.java");
+#
+# }
+#}
+#""")
+#
+#test.run(chdir = 'work2', options = opts, arguments = ".")
+#
+#test.run(program = java,
+# arguments = "-cp %s Foo1" % work2_classes,
+# stdout = "work2/src/Foo1.java\n")
+#
+#test.run(program = java,
+# arguments = "-cp %s Foo2" % work2_classes,
+# stdout = "work2/src/Foo2.java\n")
+#
+#test.run(program = java,
+# arguments = "-cp %s Foo3" % work2_classes,
+# stdout = "work2/src/Foo3.java\n")
+#
+#test.up_to_date(chdir = 'work2', options = opts, arguments = ".")
+
+test.pass_test()