Add support for JavaH.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 8 May 2003 03:36:18 +0000 (03:36 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 8 May 2003 03:36:18 +0000 (03:36 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@674 fdb21ef1-2011-0410-befe-b5e4ea1792b1

bin/files
doc/man/scons.1
src/CHANGES.txt
src/engine/MANIFEST.in
src/engine/SCons/Tool/__init__.py
src/engine/SCons/Tool/javac.py
src/engine/SCons/Tool/javah.py [new file with mode: 0644]
test/JAVAC.py
test/JAVAH.py [new file with mode: 0644]
test/Repository/JavaH.py [new file with mode: 0644]

index 3af157283cda5385433fba7405b128f71d4f2feb..c22c426d777d42ca5523e0d86aed5571813f088b 100644 (file)
--- 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
index e6f72b974022ae02e7c42996c60d1c47e86ad960..2cbf048e2edd028e1fd9888dcf60a796d7718845 100644 (file)
@@ -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
index 6c6bcfb0ce14b8a8f7e5a6f338cc44202227a180..1cd8565d678e74ca7123598536df75b173c42873 100644 (file)
@@ -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.
index c028989eb4de583243cec538bc1ed6d8667f3218..03b2c04c401eafd0c95cce9485bd02555eb00dc5 100644 (file)
@@ -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
index 8f2f63ca59736c57ba9d52f5e7c4f433974fe657..25d746223bb9fb4d2f0d0193df43ef74470bb683 100644 (file)
@@ -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',
index 8606c02fba84e5a5059b664207e910cd7ab74230..be600f1afef4b190332a24a9103eca877a76168b 100644 (file)
@@ -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 (file)
index 0000000..45fa4af
--- /dev/null
@@ -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')
index 3bc84c7cdf85fe8de52e8a2eed8ffa583e2759b3..13d46703b7beef53d46a160ecb39469760391c2f 100644 (file)
@@ -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 (file)
index 0000000..beae7a9
--- /dev/null
@@ -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 (file)
index 0000000..c11ad2b
--- /dev/null
@@ -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()