diff options
author | Steven Knight <knight@baldmt.com> | 2007-07-14 15:30:04 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2007-07-14 15:30:04 (GMT) |
commit | c1c5babea02556d1dbf3280d7644aa3323f1b876 (patch) | |
tree | 0637b8519aaebc4e457f58553899ead8dedb1252 /src | |
parent | 0bef9160a93a51ab9671c0a19d144ca027355e24 (diff) | |
download | SCons-c1c5babea02556d1dbf3280d7644aa3323f1b876.zip SCons-c1c5babea02556d1dbf3280d7644aa3323f1b876.tar.gz SCons-c1c5babea02556d1dbf3280d7644aa3323f1b876.tar.bz2 |
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).
........
Diffstat (limited to 'src')
-rw-r--r-- | src/CHANGES.txt | 8 | ||||
-rw-r--r-- | src/engine/SCons/EnvironmentTests.py | 28 | ||||
-rw-r--r-- | src/engine/SCons/SubstTests.py | 2 | ||||
-rw-r--r-- | src/engine/SCons/Tool/JavaCommon.py | 44 | ||||
-rw-r--r-- | src/engine/SCons/Tool/JavaCommonTests.py | 167 | ||||
-rw-r--r-- | src/engine/SCons/Tool/javac.py | 3 | ||||
-rw-r--r-- | src/engine/SCons/Tool/javac.xml | 21 | ||||
-rw-r--r-- | src/engine/SCons/Tool/swig.py | 27 | ||||
-rw-r--r-- | src/engine/SCons/Tool/swig.xml | 12 |
9 files changed, 227 insertions, 85 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 70519bf..f34b02f 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 a8b718d..d4e6bc5 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 7ba2477..b6e5b71 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 d340d5b..5097c67 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 e848bf9..40f0a47 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 44a4bd0..85dfc3f 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 6c28e8c..248eda2 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. </summary> </cvar> + +<cvar name="JAVAVERSION"> +<summary> +Specifies the Java version being used by the &b-Java; builder. +This is <emphasis>not</emphasis> 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 <literal>1.4</literal>. + +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 <literal>1.5</literal> +(or <literal>1.6</literal>, as appropriate) +can make &SCons; realize that a Java 1.5 or 1.6 +build is actually up to date. +</summary> +</cvar> diff --git a/src/engine/SCons/Tool/swig.py b/src/engine/SCons/Tool/swig.py index 04c3b2a..5326e8d 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 d277d64..679d683 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. </summary> </cvar> + +<cvar name="SWIGOUTDIR"> +<summary> +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 +<literal>swig -outdir</literal> option on the command line. +</summary> +</cvar> |