From 98d8496f421bccbd1263f8bc6e83affd8b6936be Mon Sep 17 00:00:00 2001 From: stevenknight Date: Sat, 14 Jul 2007 15:30:04 +0000 Subject: [PATCH] Merged revisions 2121-2135 via svnmerge from http://scons.tigris.org/svn/scons/branches/core ........ r2128 | stevenknight | 2007-07-13 06:27:11 -0500 (Fri, 13 Jul 2007) | 2 lines Use the "swig -classic" option on pre-2.0 Python versions. ........ r2130 | stevenknight | 2007-07-13 09:42:45 -0500 (Fri, 13 Jul 2007) | 2 lines Remove left-over cut-and-paste stuff about loadable modules and frameworks. ........ r2131 | stevenknight | 2007-07-13 12:08:37 -0500 (Fri, 13 Jul 2007) | 4 lines Refactor the structure of the tests to make the java input strings separate from the parse_java() calls. (Prep for enhancing the parser for Java 1.5 anonymous class files.) ........ r2132 | stevenknight | 2007-07-13 12:24:09 -0500 (Fri, 13 Jul 2007) | 3 lines Copy the Java 1.4 nested-anonymous-class test case from test/Java/live.py. Remove a commented-out unit test already added elsewhere. ........ r2133 | stevenknight | 2007-07-13 16:16:51 -0500 (Fri, 13 Jul 2007) | 4 lines Support the changed naming of .class files for nested anonymous inner classes in Java 1.5 by adding a new $JAVAVERSION variable that can be set to reflect the javac version being used. ........ r2134 | stevenknight | 2007-07-13 20:28:34 -0500 (Fri, 13 Jul 2007) | 5 lines Add a $SWIGOUTDIR variable. Add it, when set, to the command line as an argument to -outdir. Have the emitter use it to figure out where the generated .java files will be (something we didn't do at all before, -outdir aside). ........ r2135 | stevenknight | 2007-07-13 23:51:21 -0500 (Fri, 13 Jul 2007) | 2 lines Minor unit test fixes for old Python versions (1.6 and 2.0). ........ git-svn-id: http://scons.tigris.org/svn/scons/trunk@2136 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- doc/scons.mod | 1 + src/CHANGES.txt | 8 + src/engine/SCons/EnvironmentTests.py | 28 +- src/engine/SCons/SubstTests.py | 2 + src/engine/SCons/Tool/JavaCommon.py | 44 ++- src/engine/SCons/Tool/JavaCommonTests.py | 167 +++++++---- src/engine/SCons/Tool/javac.py | 3 +- src/engine/SCons/Tool/javac.xml | 21 ++ src/engine/SCons/Tool/swig.py | 27 +- src/engine/SCons/Tool/swig.xml | 12 + test/Java/{live.py => Java-1.4.py} | 11 +- test/Java/Java-1.5.py | 352 +++++++++++++++++++++++ test/Java/Java-1.6.py | 352 +++++++++++++++++++++++ test/SWIG/SWIGOUTDIR.py | 66 +++++ test/SWIG/implicit-dependencies.py | 26 +- test/SWIG/live.py | 5 + test/SWIG/remove-modules.py | 5 + 17 files changed, 1017 insertions(+), 113 deletions(-) rename test/Java/{live.py => Java-1.4.py} (97%) create mode 100644 test/Java/Java-1.5.py create mode 100644 test/Java/Java-1.6.py create mode 100644 test/SWIG/SWIGOUTDIR.py diff --git a/doc/scons.mod b/doc/scons.mod index bbb20f07..652787a9 100644 --- a/doc/scons.mod +++ b/doc/scons.mod @@ -47,6 +47,7 @@ SCons"> scons"> ScCons"> +swig"> tar"> tex"> touch"> diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 70519bfb..f34b02fd 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -61,6 +61,9 @@ RELEASE 0.97.X - XXX - Fix the --debug=time option when the -j option is specified and all files are up to date. + - Add a $SWIGOUTDIR variable to allow setting the swig -outdir option, + and use it to identify files created by the swig -java option. + From Leanid Nazdrynau: - When applying Tool modules after a construction environment has @@ -72,6 +75,11 @@ RELEASE 0.97.X - XXX - Find Java anonymous classes when the next token after the name is an open parenthesis. + From Tilo Prutz: + + - Add support for the file names that Java 1.5 (and 1.6) generates for + nested anonymous inner classes, which are different from Java 1.4. + From Adam Simpkins: - Allow worker threads to terminate gracefully when all jobs are diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index a8b718da..d4e6bc58 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -1499,13 +1499,13 @@ def exists(env): env['CLVar'] = CLVar([]) env.AppendUnique(CLVar = 'bar') result = env['CLVar'] - if sys.version[0] == '1': - # Python 1.5.2 has a quirky behavior where CLVar([]) actually - # matches '' and [] due to different __coerce__() semantics - # in the UserList implementation. It isn't worth a lot of - # effort to get this corner case to work identically (support - # for Python 1.5 support will die soon anyway), so just treat - # it separately for now. + if sys.version[0] == '1' or sys.version[:3] == '2.0': + # Python 2.0 and before have a quirky behavior where CLVar([]) + # actually matches '' and [] due to different __coerce__() + # semantics in the UserList implementation. It isn't worth a + # lot of effort to get this corner case to work identically + # (support for Python 1.5 support will die soon anyway), + # so just treat it separately for now. assert result == 'bar', result else: assert isinstance(result, CLVar), repr(result) @@ -2125,13 +2125,13 @@ f5: \ env['CLVar'] = CLVar([]) env.PrependUnique(CLVar = 'bar') result = env['CLVar'] - if sys.version[0] == '1': - # Python 1.5.2 has a quirky behavior where CLVar([]) actually - # matches '' and [] due to different __coerce__() semantics - # in the UserList implementation. It isn't worth a lot of - # effort to get this corner case to work identically (support - # for Python 1.5 support will die soon anyway), so just treat - # it separately for now. + if sys.version[0] == '1' or sys.version[:3] == '2.0': + # Python 2.0 and before have a quirky behavior where CLVar([]) + # actually matches '' and [] due to different __coerce__() + # semantics in the UserList implementation. It isn't worth a + # lot of effort to get this corner case to work identically + # (support for Python 1.5 support will die soon anyway), + # so just treat it separately for now. assert result == 'bar', result else: assert isinstance(result, CLVar), repr(result) diff --git a/src/engine/SCons/SubstTests.py b/src/engine/SCons/SubstTests.py index 7ba24779..b6e5b71d 100644 --- a/src/engine/SCons/SubstTests.py +++ b/src/engine/SCons/SubstTests.py @@ -466,6 +466,7 @@ class SubstTestCase(unittest.TestCase): expect = [ "AttributeError `bar' trying to evaluate `${foo.bar}'", "AttributeError `Foo instance has no attribute 'bar'' trying to evaluate `${foo.bar}'", + "AttributeError `'Foo' instance has no attribute 'bar'' trying to evaluate `${foo.bar}'", ] assert str(e) in expect, e else: @@ -985,6 +986,7 @@ class SubstTestCase(unittest.TestCase): expect = [ "AttributeError `bar' trying to evaluate `${foo.bar}'", "AttributeError `Foo instance has no attribute 'bar'' trying to evaluate `${foo.bar}'", + "AttributeError `'Foo' instance has no attribute 'bar'' trying to evaluate `${foo.bar}'", ] assert str(e) in expect, e else: diff --git a/src/engine/SCons/Tool/JavaCommon.py b/src/engine/SCons/Tool/JavaCommon.py index d340d5b1..5097c673 100644 --- a/src/engine/SCons/Tool/JavaCommon.py +++ b/src/engine/SCons/Tool/JavaCommon.py @@ -36,6 +36,8 @@ import string java_parsing = 1 +default_java_version = '1.4' + if java_parsing: # Parse Java files for class names. # @@ -59,12 +61,20 @@ if java_parsing: class OuterState: """The initial state for parsing a Java file for classes, interfaces, and anonymous inner classes.""" - def __init__(self): + def __init__(self, version=default_java_version): + + if not version in ('1.1', '1.2', '1.3','1.4', '1.5', '1.6'): + msg = "Java version %s not supported" % version + raise NotImplementedError, msg + + self.version = version self.listClasses = [] self.listOutputs = [] self.stackBrackets = [] self.brackets = 0 self.nextAnon = 1 + self.stackAnonClassBrackets = [] + self.anonStacksStack = [[0]] self.package = None def trace(self): @@ -102,6 +112,9 @@ if java_parsing: ret = SkipState(1, self) self.skipState = ret return ret + + def __getAnonStack(self): + return self.anonStacksStack[-1] def openBracket(self): self.brackets = self.brackets + 1 @@ -112,7 +125,12 @@ if java_parsing: self.brackets == self.stackBrackets[-1]: self.listOutputs.append(string.join(self.listClasses, '$')) self.listClasses.pop() + self.anonStacksStack.pop() self.stackBrackets.pop() + if len(self.stackAnonClassBrackets) and \ + self.brackets == self.stackAnonClassBrackets[-1]: + self.__getAnonStack().pop() + self.stackAnonClassBrackets.pop() def parseToken(self, token): if token[:2] == '//': @@ -146,9 +164,20 @@ if java_parsing: def addAnonClass(self): """Add an anonymous inner class""" - clazz = self.listClasses[0] - self.listOutputs.append('%s$%d' % (clazz, self.nextAnon)) + if self.version in ('1.1', '1.2', '1.3', '1.4'): + clazz = self.listClasses[0] + self.listOutputs.append('%s$%d' % (clazz, self.nextAnon)) + elif self.version in ('1.5', '1.6'): + self.stackAnonClassBrackets.append(self.brackets) + className = [] + className.extend(self.listClasses) + self.__getAnonStack()[-1] = self.__getAnonStack()[-1] + 1 + for anon in self.__getAnonStack(): + className.append(str(anon)) + self.listOutputs.append(string.join(className, '$')) + self.nextAnon = self.nextAnon + 1 + self.__getAnonStack().append(0) def setPackage(self, package): self.package = package @@ -208,6 +237,7 @@ if java_parsing: if token == '\n': return self self.outer_state.listClasses.append(token) + self.outer_state.anonStacksStack.append([0]) return self.outer_state class IgnoreState: @@ -231,15 +261,15 @@ if java_parsing: self.outer_state.setPackage(token) return self.outer_state - def parse_java_file(fn): - return parse_java(open(fn, 'r').read()) + def parse_java_file(fn, version=default_java_version): + return parse_java(open(fn, 'r').read(), version) - def parse_java(contents, trace=None): + def parse_java(contents, version=default_java_version, trace=None): """Parse a .java file and return a double of package directory, plus a list of .class files that compiling that .java file will produce""" package = None - initial = OuterState() + initial = OuterState(version) currstate = initial for token in _reToken.findall(contents): # The regex produces a bunch of groups, but only one will diff --git a/src/engine/SCons/Tool/JavaCommonTests.py b/src/engine/SCons/Tool/JavaCommonTests.py index e848bf9b..40f0a47f 100644 --- a/src/engine/SCons/Tool/JavaCommonTests.py +++ b/src/engine/SCons/Tool/JavaCommonTests.py @@ -30,9 +30,9 @@ import unittest import SCons.Tool.JavaCommon -# Adding this trace to any of the calls below to the parse_java() method -# will cause the parser to spit out trace messages of the tokens it sees -# and state transitions. +# Adding trace=trace to any of the parse_jave() calls below will cause +# the parser to spit out trace messages of the tokens it sees and the +# attendant transitions. def trace(token, newstate): from SCons.Debug import Trace @@ -44,7 +44,7 @@ class parse_javaTestCase(unittest.TestCase): def test_bare_bones(self): """Test a bare-bones class""" - pkg_dir, classes = SCons.Tool.JavaCommon.parse_java("""\ + input = """\ package com.sub.bar; public class Foo @@ -59,7 +59,8 @@ public class Foo } } -""") +""" + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input) assert pkg_dir == os.path.join('com', 'sub', 'bar'), pkg_dir assert classes == ['Foo'], classes @@ -67,7 +68,7 @@ public class Foo def test_inner_classes(self): """Test parsing various forms of inner classes""" - pkg_dir, classes = SCons.Tool.JavaCommon.parse_java("""\ + input = """\ class Empty { } @@ -132,8 +133,9 @@ class Private { }; } } -""") - +""" + + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.4') assert pkg_dir is None, pkg_dir expect = [ 'Empty', @@ -150,11 +152,29 @@ class Private { ] assert classes == expect, classes + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.5') + assert pkg_dir is None, pkg_dir + expect = [ + 'Empty', + 'Listener', + 'Test$Inner$1', + 'Test$Inner', + 'Test$Inner2', + 'Test$Inner3', + 'Test$1', + 'Test$1$1', + 'Test', + 'Private$1', + 'Private', + ] + assert classes == expect, (expect, classes) + + def test_comments(self): """Test a class with comments""" - pkg_dir, classes = SCons.Tool.JavaCommon.parse_java("""\ + input = """\ package com.sub.foo; import java.rmi.Naming; @@ -189,8 +209,9 @@ public class Example1 extends UnicastRemoteObject implements Hello { } } } -""") +""" + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input) assert pkg_dir == os.path.join('com', 'sub', 'foo'), pkg_dir assert classes == ['Example1'], classes @@ -198,7 +219,7 @@ public class Example1 extends UnicastRemoteObject implements Hello { def test_arrays(self): """Test arrays of class instances""" - pkg_dir, classes = SCons.Tool.JavaCommon.parse_java("""\ + input = """\ public class Test { MyClass abc = new MyClass(); MyClass xyz = new MyClass(); @@ -207,41 +228,18 @@ public class Test { xyz } } -""") +""" + + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input) assert pkg_dir == None, pkg_dir assert classes == ['Test'], classes -# This test comes from bug report #1197470: -# -# http://sourceforge.net/tracker/index.php?func=detail&aid=1194740&group_id=30337&atid=398971 -# -# I've captured it here so that someone with a better grasp of Java syntax -# and the parse_java() state machine can uncomment it and fix it some day. -# -# def test_arrays_in_decls(self): -# """Test how arrays in method declarations affect class detection""" -# -# pkg_dir, classes = SCons.Tool.JavaCommon.parse_java("""\ -#public class A { -# public class B{ -# public void F(Object[] o) { -# F(new Object[] {Object[].class}); -# } -# public void G(Object[] o) { -# F(new Object[] {}); -# } -# } -#} -#""") -# assert pkg_dir == None, pkg_dir -# assert classes == ['A$B', 'A'], classes - def test_backslash(self): """Test backslash handling""" - pkg_dir, classes = SCons.Tool.JavaCommon.parse_java("""\ + input = """\ public class MyTabs { private class MyInternal @@ -249,7 +247,9 @@ public class MyTabs } private final static String PATH = "images\\\\"; } -""") +""" + + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input) assert pkg_dir == None, pkg_dir assert classes == ['MyTabs$MyInternal', 'MyTabs'], classes @@ -257,17 +257,20 @@ public class MyTabs def test_enum(self): """Test the Java 1.5 enum keyword""" - pkg_dir, classes = SCons.Tool.JavaCommon.parse_java("""\ + input = """\ package p; public enum a {} -""") +""" + + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input) assert pkg_dir == 'p', pkg_dir assert classes == ['a'], classes def test_anon_classes(self): """Test anonymous classes""" - pkg_dir, classes = SCons.Tool.JavaCommon.parse_java("""\ + + input = """\ public abstract class TestClass { public void completed() @@ -281,14 +284,17 @@ public abstract class TestClass }.start(); } } -""") +""" + + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input) assert pkg_dir == None, pkg_dir assert classes == ['TestClass$1', 'TestClass$2', 'TestClass'], classes def test_closing_bracket(self): """Test finding a closing bracket instead of an anonymous class""" - pkg_dir, classes = SCons.Tool.JavaCommon.parse_java("""\ + + input = """\ class TestSCons { public static void main(String[] args) { Foo[] fooArray = new Foo[] { new Foo() }; @@ -296,14 +302,17 @@ class TestSCons { } class Foo { } -""") +""" + + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input) assert pkg_dir == None, pkg_dir assert classes == ['TestSCons', 'Foo'], classes def test_dot_class_attributes(self): """Test handling ".class" attributes""" - pkg_dir, classes = SCons.Tool.JavaCommon.parse_java("""\ + + input = """\ public class Test extends Object { static { @@ -311,10 +320,12 @@ public class Test extends Object Object[] s = new Object[] {}; } } -""") +""" + + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input) assert classes == ['Test'], classes - pkg_dir, classes = SCons.Tool.JavaCommon.parse_java("""\ + input = """\ public class A { public class B { public void F(Object[] o) { @@ -325,13 +336,16 @@ public class A { } } } -""") +""" + + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input) assert pkg_dir == None, pkg_dir assert classes == ['A$B', 'A'], classes def test_anonymous_classes_with_parentheses(self): """Test finding anonymous classes marked by parentheses""" - pkg_dir, classes = SCons.Tool.JavaCommon.parse_java("""\ + + input = """\ import java.io.File; public class Foo { @@ -349,9 +363,60 @@ public class Foo { }; } } -""") +""" + + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.4') assert classes == ['Foo$1', 'Foo$2', 'Foo'], classes + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.5') + assert classes == ['Foo$1', 'Foo$1$1', 'Foo'], classes + + + + def test_nested_anonymous_inner_classes(self): + """Test finding nested anonymous inner classes""" + + input = """\ +// import java.util.*; + +public class NestedExample +{ + public NestedExample() + { + Thread t = new Thread() { + public void start() + { + Thread t = new Thread() { + public void start() + { + try {Thread.sleep(200);} + catch (Exception e) {} + } + }; + while (true) + { + try {Thread.sleep(200);} + catch (Exception e) {} + } + } + }; + } + + + public static void main(String argv[]) + { + NestedExample e = new NestedExample(); + } +} +""" + + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.4') + expect = [ 'NestedExample$1', 'NestedExample$2', 'NestedExample' ] + assert expect == classes, (expect, classes) + + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.5') + expect = [ 'NestedExample$1', 'NestedExample$1$1', 'NestedExample' ] + assert expect == classes, (expect, classes) diff --git a/src/engine/SCons/Tool/javac.py b/src/engine/SCons/Tool/javac.py index 44a4bd04..85dfc3fd 100644 --- a/src/engine/SCons/Tool/javac.py +++ b/src/engine/SCons/Tool/javac.py @@ -71,7 +71,8 @@ def emit_java_classes(target, source, env): tlist = [] for f in slist: - pkg_dir, classes = parse_java_file(f.get_abspath()) + version = env.get('JAVAVERSION', '1.4') + pkg_dir, classes = parse_java_file(f.get_abspath(), version) if pkg_dir: for c in classes: t = target[0].Dir(pkg_dir).File(c+class_suffix) diff --git a/src/engine/SCons/Tool/javac.xml b/src/engine/SCons/Tool/javac.xml index 6c28e8cc..248eda2a 100644 --- a/src/engine/SCons/Tool/javac.xml +++ b/src/engine/SCons/Tool/javac.xml @@ -122,3 +122,24 @@ The suffix for Java files; by default. + + + +Specifies the Java version being used by the &b-Java; builder. +This is not currently used to select one +version of the Java compiler vs. another. +Instead, you should set this to specify the version of Java +supported by your &javac; compiler. +The default is 1.4. + +This is sometimes necessary because +Java 1.5 changed the file names that are created +for nested anonymous inner classes, +which can cause a mismatch with the files +that &SCons; expects will be generated by the &javac; compiler. +Setting &cv-JAVAVERSION; to 1.5 +(or 1.6, as appropriate) +can make &SCons; realize that a Java 1.5 or 1.6 +build is actually up to date. + + diff --git a/src/engine/SCons/Tool/swig.py b/src/engine/SCons/Tool/swig.py index 04c3b2ab..5326e8d2 100644 --- a/src/engine/SCons/Tool/swig.py +++ b/src/engine/SCons/Tool/swig.py @@ -83,19 +83,21 @@ def _scanSwig(node, env, path): def _swigEmitter(target, source, env): for src in source: src = str(src) - mname = None flags = SCons.Util.CLVar(env.subst("$SWIGFLAGS")) + mnames = None if "-python" in flags and "-noproxy" not in flags: - f = open(src) - try: - for l in f.readlines(): - m = _reModule.match(l) - if m: - mname = m.group(1) - finally: - f.close() - if mname is not None: - target.append(mname + ".py") + if mnames is None: + mnames = _reModule.findall(open(src).read()) + target.extend(map(lambda m: m + ".py", mnames)) + if "-java" in flags: + if mnames is None: + mnames = _reModule.findall(open(src).read()) + java_files = map(lambda m: [m + ".java", m + "JNI.java"], mnames) + java_files = SCons.Util.flatten(java_files) + outdir = env.subst('$SWIGOUTDIR') + if outdir: + java_files = map(lambda j, o=outdir: os.path.join(o, j), java_files) + target.extend(java_files) return (target, source) def generate(env): @@ -114,7 +116,8 @@ def generate(env): env['SWIGFLAGS'] = SCons.Util.CLVar('') env['SWIGCFILESUFFIX'] = '_wrap$CFILESUFFIX' env['SWIGCXXFILESUFFIX'] = '_wrap$CXXFILESUFFIX' - env['SWIGCOM'] = '$SWIG $SWIGFLAGS -o $TARGET $SOURCES' + env['_SWIGOUTDIR'] = '${"-outdir " + SWIGOUTDIR}' + env['SWIGCOM'] = '$SWIG -o $TARGET ${_SWIGOUTDIR} $SWIGFLAGS $SOURCES' env.Append(SCANNERS=Scanner(function=_scanSwig, skeys=[".i"])) def exists(env): diff --git a/src/engine/SCons/Tool/swig.xml b/src/engine/SCons/Tool/swig.xml index d277d642..679d6832 100644 --- a/src/engine/SCons/Tool/swig.xml +++ b/src/engine/SCons/Tool/swig.xml @@ -93,3 +93,15 @@ with the extension that is specified as the variable. + + + +Specifies the output directory in which +the scripting language wrapper and interface generator +should place generated language-specific files. +This will be used by SCons to identify +the files that will be generated by the &swig; call, +and translated into the +swig -outdir option on the command line. + + diff --git a/test/Java/live.py b/test/Java/Java-1.4.py similarity index 97% rename from test/Java/live.py rename to test/Java/Java-1.4.py index 5ad21947..8c3af594 100644 --- a/test/Java/live.py +++ b/test/Java/Java-1.4.py @@ -25,7 +25,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" """ -Test Java compilation with a live "javac" compiler. +Test Java compilation with a live Java 1.4 "javac" compiler. """ import os @@ -51,6 +51,7 @@ if not where_javac: test.write('SConstruct', """ env = Environment(tools = ['javac'], + JAVAVERSION = '1.4', JAVAC = r'%(where_javac)s') env.Java(target = 'class1', source = 'com/sub/foo') env.Java(target = 'class2', source = 'com/sub/bar') @@ -326,6 +327,8 @@ expect_5 = [ test.workpath('class5', 'TestSCons.class'), ] +failed = None + def classes_must_match(dir, expect, got): if expect != got: sys.stderr.write("Expected the following class files in '%s':\n" % dir) @@ -334,13 +337,15 @@ def classes_must_match(dir, expect, got): sys.stderr.write("Got the following class files in '%s':\n" % dir) for c in got: sys.stderr.write(' %s\n' % c) - test.fail_test() + failed = 1 classes_must_match('class1', expect_1, classes_1) classes_must_match('class2', expect_2, classes_2) classes_must_match('class3', expect_3, classes_3) classes_must_match('class4', expect_4, classes_4) -test.up_to_date(arguments = '.') +test.fail_test(failed) + +test.up_to_date(options='--debug=explain', arguments = '.') test.pass_test() diff --git a/test/Java/Java-1.5.py b/test/Java/Java-1.5.py new file mode 100644 index 00000000..0b3ba27a --- /dev/null +++ b/test/Java/Java-1.5.py @@ -0,0 +1,352 @@ +#!/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 Java compilation with a live Java 1.5 "javac" compiler. +""" + +import os +import os.path +import string +import sys +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +ENV = test.java_ENV() +ENV['PATH'] = '/usr/lib/jvm/java-1.5.0-sun-1.5.0.11/bin' + os.pathsep + os.environ['PATH'] + +if test.detect_tool('javac', ENV=ENV): + where_javac = test.detect('JAVAC', 'javac', ENV=ENV) +else: + where_javac = test.where_is('javac') +if not where_javac: + test.skip_test("Could not find Java javac, skipping test(s).\n") + + + +test.write('SConstruct', """ +env = Environment(tools = ['javac'], + JAVAVERSION = '1.5', + JAVAC = r'%(where_javac)s') +env.Java(target = 'class1', source = 'com/sub/foo') +env.Java(target = 'class2', source = 'com/sub/bar') +env.Java(target = 'class3', source = ['src1', 'src2']) +env.Java(target = 'class4', source = ['src4']) +env.Java(target = 'class5', source = ['src5']) +""" % locals()) + +test.subdir('com', + ['com', 'sub'], + ['com', 'sub', 'foo'], + ['com', 'sub', 'bar'], + 'src1', + 'src2', + 'src4', + 'src5') + +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(['src1', 'Example7.java'], """\ +public class Example7 +{ + + public static void main(String[] args) + { + + } + +} +""") + +# Acid-test file for parsing inner Java classes, courtesy Chad Austin. +test.write(['src2', '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() { + } + }; + } +} +""") + +# Testing nested anonymous inner classes, courtesy Brandon Mansfield. +test.write(['src4', 'NestedExample.java'], """\ +// import java.util.*; + +public class NestedExample +{ + public NestedExample() + { + Thread t = new Thread() { + public void start() + { + Thread t = new Thread() { + public void start() + { + try {Thread.sleep(200);} + catch (Exception e) {} + } + }; + while (true) + { + try {Thread.sleep(200);} + catch (Exception e) {} + } + } + }; + } + + + public static void main(String argv[]) + { + NestedExample e = new NestedExample(); + } +} +""") + +# Test not finding an anonymous class when the second token after a +# "new" is a closing brace. This duplicates a test from the unit tests, +# but lets us make sure that we correctly determine that everything is +# up-to-date after the build. +test.write(['src5', 'TestSCons.java'], """\ +class TestSCons { + public static void main(String[] args) { + Foo[] fooArray = new Foo[] { new Foo() }; + } +} + +class Foo { } +""") + +test.run(arguments = '.') + +def get_class_files(dir): + def find_class_files(arg, dirname, fnames): + for fname in fnames: + if fname[-6:] == '.class': + arg.append(os.path.join(dirname, fname)) + result = [] + os.path.walk(dir, find_class_files, result) + result.sort() + return result + +classes_1 = get_class_files(test.workpath('class1')) +classes_2 = get_class_files(test.workpath('class2')) +classes_3 = get_class_files(test.workpath('class3')) +classes_4 = get_class_files(test.workpath('class4')) +classes_5 = get_class_files(test.workpath('class5')) + +expect_1 = [ + test.workpath('class1', 'com', 'other', 'Example2.class'), + test.workpath('class1', 'com', 'sub', 'foo', 'Example1.class'), + test.workpath('class1', 'com', 'sub', 'foo', 'Example3.class'), +] + +expect_2 = [ + test.workpath('class2', 'com', 'other', 'Example5.class'), + test.workpath('class2', 'com', 'sub', 'bar', 'Example4.class'), + test.workpath('class2', 'com', 'sub', 'bar', 'Example6.class'), +] + +expect_3 = [ + test.workpath('class3', 'Empty.class'), + test.workpath('class3', 'Example7.class'), + test.workpath('class3', 'Listener.class'), + test.workpath('class3', 'Private$1.class'), + test.workpath('class3', 'Private.class'), + test.workpath('class3', 'Test$1$1.class'), + test.workpath('class3', 'Test$1.class'), + test.workpath('class3', 'Test$Inner$1.class'), + test.workpath('class3', 'Test$Inner.class'), + test.workpath('class3', 'Test.class'), +] + +expect_4 = [ + test.workpath('class4', 'NestedExample$1$1.class'), + test.workpath('class4', 'NestedExample$1.class'), + test.workpath('class4', 'NestedExample.class'), +] + +expect_5 = [ + test.workpath('class5', 'Foo.class'), + test.workpath('class5', 'TestSCons.class'), +] + +failed = None + +def classes_must_match(dir, expect, got): + if expect != got: + sys.stderr.write("Expected the following class files in '%s':\n" % dir) + for c in expect: + sys.stderr.write(' %s\n' % c) + sys.stderr.write("Got the following class files in '%s':\n" % dir) + for c in got: + sys.stderr.write(' %s\n' % c) + failed = 1 + +classes_must_match('class1', expect_1, classes_1) +classes_must_match('class2', expect_2, classes_2) +classes_must_match('class3', expect_3, classes_3) +classes_must_match('class4', expect_4, classes_4) + +test.fail_test(failed) + +test.up_to_date(options='--debug=explain', arguments = '.') + +test.pass_test() diff --git a/test/Java/Java-1.6.py b/test/Java/Java-1.6.py new file mode 100644 index 00000000..0b4ddd7e --- /dev/null +++ b/test/Java/Java-1.6.py @@ -0,0 +1,352 @@ +#!/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 Java compilation with a live Java 1.6 "javac" compiler. +""" + +import os +import os.path +import string +import sys +import TestSCons + +_python_ = TestSCons._python_ + +test = TestSCons.TestSCons() + +ENV = test.java_ENV() +ENV['PATH'] = '/usr/lib/jvm/java-6-sun-1.6.0.00/bin' + os.pathsep + os.environ['PATH'] + +if test.detect_tool('javac', ENV=ENV): + where_javac = test.detect('JAVAC', 'javac', ENV=ENV) +else: + where_javac = test.where_is('javac') +if not where_javac: + test.skip_test("Could not find Java javac, skipping test(s).\n") + + + +test.write('SConstruct', """ +env = Environment(tools = ['javac'], + JAVAVERSION = '1.6', + JAVAC = r'%(where_javac)s') +env.Java(target = 'class1', source = 'com/sub/foo') +env.Java(target = 'class2', source = 'com/sub/bar') +env.Java(target = 'class3', source = ['src1', 'src2']) +env.Java(target = 'class4', source = ['src4']) +env.Java(target = 'class5', source = ['src5']) +""" % locals()) + +test.subdir('com', + ['com', 'sub'], + ['com', 'sub', 'foo'], + ['com', 'sub', 'bar'], + 'src1', + 'src2', + 'src4', + 'src5') + +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(['src1', 'Example7.java'], """\ +public class Example7 +{ + + public static void main(String[] args) + { + + } + +} +""") + +# Acid-test file for parsing inner Java classes, courtesy Chad Austin. +test.write(['src2', '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() { + } + }; + } +} +""") + +# Testing nested anonymous inner classes, courtesy Brandon Mansfield. +test.write(['src4', 'NestedExample.java'], """\ +// import java.util.*; + +public class NestedExample +{ + public NestedExample() + { + Thread t = new Thread() { + public void start() + { + Thread t = new Thread() { + public void start() + { + try {Thread.sleep(200);} + catch (Exception e) {} + } + }; + while (true) + { + try {Thread.sleep(200);} + catch (Exception e) {} + } + } + }; + } + + + public static void main(String argv[]) + { + NestedExample e = new NestedExample(); + } +} +""") + +# Test not finding an anonymous class when the second token after a +# "new" is a closing brace. This duplicates a test from the unit tests, +# but lets us make sure that we correctly determine that everything is +# up-to-date after the build. +test.write(['src5', 'TestSCons.java'], """\ +class TestSCons { + public static void main(String[] args) { + Foo[] fooArray = new Foo[] { new Foo() }; + } +} + +class Foo { } +""") + +test.run(arguments = '.') + +def get_class_files(dir): + def find_class_files(arg, dirname, fnames): + for fname in fnames: + if fname[-6:] == '.class': + arg.append(os.path.join(dirname, fname)) + result = [] + os.path.walk(dir, find_class_files, result) + result.sort() + return result + +classes_1 = get_class_files(test.workpath('class1')) +classes_2 = get_class_files(test.workpath('class2')) +classes_3 = get_class_files(test.workpath('class3')) +classes_4 = get_class_files(test.workpath('class4')) +classes_5 = get_class_files(test.workpath('class5')) + +expect_1 = [ + test.workpath('class1', 'com', 'other', 'Example2.class'), + test.workpath('class1', 'com', 'sub', 'foo', 'Example1.class'), + test.workpath('class1', 'com', 'sub', 'foo', 'Example3.class'), +] + +expect_2 = [ + test.workpath('class2', 'com', 'other', 'Example5.class'), + test.workpath('class2', 'com', 'sub', 'bar', 'Example4.class'), + test.workpath('class2', 'com', 'sub', 'bar', 'Example6.class'), +] + +expect_3 = [ + test.workpath('class3', 'Empty.class'), + test.workpath('class3', 'Example7.class'), + test.workpath('class3', 'Listener.class'), + test.workpath('class3', 'Private$1.class'), + test.workpath('class3', 'Private.class'), + test.workpath('class3', 'Test$1$1.class'), + test.workpath('class3', 'Test$1.class'), + test.workpath('class3', 'Test$Inner$1.class'), + test.workpath('class3', 'Test$Inner.class'), + test.workpath('class3', 'Test.class'), +] + +expect_4 = [ + test.workpath('class4', 'NestedExample$1$1.class'), + test.workpath('class4', 'NestedExample$1.class'), + test.workpath('class4', 'NestedExample.class'), +] + +expect_5 = [ + test.workpath('class5', 'Foo.class'), + test.workpath('class5', 'TestSCons.class'), +] + +failed = None + +def classes_must_match(dir, expect, got): + if expect != got: + sys.stderr.write("Expected the following class files in '%s':\n" % dir) + for c in expect: + sys.stderr.write(' %s\n' % c) + sys.stderr.write("Got the following class files in '%s':\n" % dir) + for c in got: + sys.stderr.write(' %s\n' % c) + failed = 1 + +classes_must_match('class1', expect_1, classes_1) +classes_must_match('class2', expect_2, classes_2) +classes_must_match('class3', expect_3, classes_3) +classes_must_match('class4', expect_4, classes_4) + +test.fail_test(failed) + +test.up_to_date(options='--debug=explain', arguments = '.') + +test.pass_test() diff --git a/test/SWIG/SWIGOUTDIR.py b/test/SWIG/SWIGOUTDIR.py new file mode 100644 index 00000000..69d535cb --- /dev/null +++ b/test/SWIG/SWIGOUTDIR.py @@ -0,0 +1,66 @@ +#!/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__" + +""" +Verify that use of the $SWIGOUTDIR variable causes SCons to recognize +that Java files are created in the specified output directory. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +test.write(['SConstruct'], """\ +env = Environment(tools = ['default', 'swig']) + +Java_foo_interface = env.SharedLibrary( + 'Java_foo_interface', + 'Java_foo_interface.i', + SWIGOUTDIR = 'java/build', + SWIGFLAGS = '-c++ -java -Wall', + SWIGCXXFILESUFFIX = "_wrap.cpp") +""" % locals()) + +test.write('Java_foo_interface.i', """\ +%module foopack +""") + +# SCons should realize that it needs to create the java/build +# subdirectory to hold the generate .java files. +test.run(arguments = '.') + +# SCons should remove the built .java files. +test.run(arguments = '-c java/build/foopack.java java/build/foopackJNI.java') + +test.must_not_exist('java/build/foopackJNI.java') +test.must_not_exist('java/build/foopack.java') + +# SCons should realize it needs to rebuild the removed .java files. +test.not_up_to_date(arguments = '.') + + + +test.pass_test() diff --git a/test/SWIG/implicit-dependencies.py b/test/SWIG/implicit-dependencies.py index 55645a4e..81e3cf9b 100644 --- a/test/SWIG/implicit-dependencies.py +++ b/test/SWIG/implicit-dependencies.py @@ -43,13 +43,6 @@ else: python = TestSCons.python _python_ = TestSCons._python_ -# swig-python expects specific filenames. -# the platform specific suffix won't necessarily work. -if sys.platform == 'win32': - _dll = '.dll' -else: - _dll = '.so' - test = TestSCons.TestSCons() swig = test.where_is('swig') @@ -61,17 +54,6 @@ if not swig: version = sys.version[:3] # see also sys.prefix documentation -# handle testing on other platforms: -ldmodule_prefix = '_' - -frameworks = '' -platform_sys_prefix = sys.prefix -if sys.platform == 'darwin': - # OS X has a built-in Python but no static libpython - # so you should link to it using apple's 'framework' scheme. - # (see top of file for further explanation) - frameworks = '-framework Python' - platform_sys_prefix = '/System/Library/Frameworks/Python.framework/Versions/%s/' % version test.write("dependency.i", """\ %module dependency @@ -84,13 +66,7 @@ test.write("dependent.i", """\ """) test.write('SConstruct', """ -foo = Environment(SWIGFLAGS='-python', - CPPPATH='%(platform_sys_prefix)s/include/python%(version)s/', - LDMODULEPREFIX='%(ldmodule_prefix)s', - LDMODULESUFFIX='%(_dll)s', - FRAMEWORKSFLAGS='%(frameworks)s', - ) - +foo = Environment(SWIGFLAGS='-python') swig = foo.Dictionary('SWIG') bar = foo.Clone(SWIG = r'%(_python_)s wrapper.py ' + swig) foo.CFile(target = 'dependent', source = ['dependent.i']) diff --git a/test/SWIG/live.py b/test/SWIG/live.py index 93336ca1..d319af78 100644 --- a/test/SWIG/live.py +++ b/test/SWIG/live.py @@ -99,6 +99,11 @@ foo = Environment(SWIGFLAGS='-python', FRAMEWORKSFLAGS='%(frameworks)s', ) +import sys +if sys.version[0] == '1': + # SWIG requires the -classic flag on pre-2.0 Python versions. + foo.Append(SWIGFLAGS = ' -classic') + swig = foo.Dictionary('SWIG') bar = foo.Clone(SWIG = r'%(_python_)s wrapper.py ' + swig) foo.LoadableModule(target = 'foo', source = ['foo.c', 'foo.i']) diff --git a/test/SWIG/remove-modules.py b/test/SWIG/remove-modules.py index 1a48c9ee..f5d4010f 100644 --- a/test/SWIG/remove-modules.py +++ b/test/SWIG/remove-modules.py @@ -85,6 +85,11 @@ foo = Environment(SWIGFLAGS='-python', FRAMEWORKSFLAGS='%(frameworks)s', ) +import sys +if sys.version[0] == '1': + # SWIG requires the -classic flag on pre-2.0 Python versions. + foo.Append(SWIGFLAGS = ' -classic') + foo.LoadableModule(target = 'modulename', source = ['module.i']) """ % locals()) -- 2.26.2