summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CHANGES.txt65
-rw-r--r--src/RELEASE.txt27
-rw-r--r--src/engine/SCons/Action.py6
-rw-r--r--src/engine/SCons/ActionTests.py8
-rw-r--r--src/engine/SCons/Builder.py9
-rw-r--r--src/engine/SCons/BuilderTests.py112
-rw-r--r--src/engine/SCons/Conftest.py2
-rw-r--r--src/engine/SCons/Environment.py20
-rw-r--r--src/engine/SCons/EnvironmentTests.py67
-rw-r--r--src/engine/SCons/Node/FS.py12
-rw-r--r--src/engine/SCons/Node/__init__.py23
-rw-r--r--src/engine/SCons/Platform/sunos.py2
-rw-r--r--src/engine/SCons/Scanner/LaTeX.py6
-rw-r--r--src/engine/SCons/Script/Main.py27
-rw-r--r--src/engine/SCons/Script/__init__.py1
-rw-r--r--src/engine/SCons/Taskmaster.py3
-rw-r--r--src/engine/SCons/TaskmasterTests.py9
-rw-r--r--src/engine/SCons/Tool/JavaCommon.py40
-rw-r--r--src/engine/SCons/Tool/JavaCommonTests.py24
-rw-r--r--src/engine/SCons/Tool/__init__.py5
-rw-r--r--src/engine/SCons/Tool/midl.py14
-rw-r--r--src/engine/SCons/Tool/mslink.py16
-rw-r--r--src/engine/SCons/Tool/msvs.py6
-rw-r--r--src/engine/SCons/Util.py76
-rw-r--r--src/engine/SCons/compat/builtins.py6
25 files changed, 470 insertions, 116 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index a47992a..9cf69e9 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -8,6 +8,71 @@
+RELEASE 0.97.X - XXX
+
+ From Mark Bertoglio:
+
+ - Fix listing multiple projects in Visual Studio 7.[01] solution files,
+ including generating individual project GUIDs instead of re-using
+ the solution GUID.
+
+ From Jean Brouwers:
+
+ - Add /opt/SUNWspro/bin to the default execution PATH on Solaris.
+
+ From Allan Erskine:
+
+ - Only expect the Microsoft IDL compiler to emit *_p.c and *_data.c
+ files if the /proxy and /dlldata switches are used (respectively).
+
+ From Steven Knight:
+
+ - Have --debug=explain report if a target is being rebuilt because
+ AlwaysBuild() is specified (instead of "unknown reasons").
+
+ - Support {Get,Set}Option('help') to make it easier for SConscript
+ files to tell if a help option (-h, --help, etc.) has been specified.
+
+ - Support {Get,Set}Option('random') so random-dependency interaction
+ with CacheDir() is controllable from SConscript files.
+
+ - Push and retrieve built symlinks to/from a CacheDir() as actual
+ symlinks, not by copying the file contents.
+
+ - Fix how the Action module handles stringifying the shared library
+ generator in the Tool/mingw.py module.
+
+ - When generating a config.h file, print "#define HAVE_{FEATURE} 1"
+ instad of just "#define HAVE_{FEATURE}", for more compatibility
+ with Autoconf-style projects.
+
+ - Fix expansion of $TARGET, $TARGETS, $SOURCE and $SOURCES keywords in
+ Visual C/C++ PDB file names.
+
+ - Fix locating Visual C/C++ PDB files in build directories.
+
+ - Support an env.AddMethod() method and an AddMethod() global function
+ for adding a new method, respectively, to a construction environment
+ or an arbitrary object (such as a class).
+
+ From Leanid Nazdrynau:
+
+ - When applying Tool modules after a construction environment has
+ already been created, don't overwrite existing $CFILESUFFIX and
+ $CXXFILESUFFIX value.
+
+ From Jan Nijtmans:
+
+ - Find Java anonymous classes when the next token after the name is
+ an open parenthesis.
+
+ From Sohail Somani:
+
+ - Add LaTeX scanner support for finding dependencies specified with
+ the \usepackage{} directive.
+
+
+
RELEASE 0.97 - Thu, 17 May 2007 08:59:41 -0500
From Steven Knight:
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index b19a39c..6dd66aa 100644
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -25,6 +25,33 @@ RELEASE 0.97 - Thu, 12 Apr 2007 12:36:25 -0500
This is the eighth beta release of SCons. Please consult the
CHANGES.txt file for a list of specific changes since last release.
+ Please note the following important changes since release 0.97:
+
+ -- THE DEFAULT EXECUTION PATH FOR Solaris HAS CHANGED
+
+ On Solaris systems, SCons now adds the "/opt/SUNWspro/bin"
+ directory to the default execution $PATH variable before the
+ "/usr/ccs/bin" directory. This was done to reflect the fact
+ that /opt/SUNWspro/ is the default for SUN tools, but it may
+ cause a different compiler to be used if you have compilers
+ installed in both directories.
+
+ -- GENERATED config.h FILES NOW SAY "#define HAVE_{FEATURE} 1"
+
+ When generating a "config.h" file, SCons now defines values that
+ record the existence of a feature with a "1" value:
+
+ #define HAVE_FEATURE 1
+
+ Instead of printing the line without a "1", as it used to:
+
+ #define HAVE_FEATURE
+
+ This should not cause any problems in the normal use of "#ifdef
+ HAVE_{FEATURE}" statements interpreted by a C preprocessor, but
+ might cause a compatibility issue if a script or other utility
+ was looking for an exact match of the previous text.
+
Please note the following important changes since release 0.96.93:
-- THE --debug=memoizer OPTION NOW REQUIRES PYTHON 2.2 OR LATER
diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py
index 438588b..a010c4a 100644
--- a/src/engine/SCons/Action.py
+++ b/src/engine/SCons/Action.py
@@ -515,9 +515,11 @@ class CommandGeneratorAction(ActionBase):
def __str__(self):
try:
- env = self.presub_env or {}
+ env = self.presub_env
except AttributeError:
- env = {}
+ env = None
+ if env is None:
+ env = SCons.Defaults.DefaultEnvironment()
act = self._generate([], [], env, 1)
return str(act)
diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py
index 08373c3..87fb4b0 100644
--- a/src/engine/SCons/ActionTests.py
+++ b/src/engine/SCons/ActionTests.py
@@ -1261,6 +1261,14 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
"""Test the pre-substitution strings for command generator Actions
"""
def f(target, source, env, for_signature, self=self):
+
+ # See if "env" is really a construction environment (or
+ # looks like one) by accessing the FindIxes attribute.
+ # (The Tool/mingw.py module has a generator that uses this,
+ # and the __str__() method used to cause problems by passing
+ # us a regular dictionary as a fallback.)
+
+ env.FindIxes
return "FOO"
a = SCons.Action.CommandGeneratorAction(f)
s = str(a)
diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py
index ecc93c0..c4b1d1d 100644
--- a/src/engine/SCons/Builder.py
+++ b/src/engine/SCons/Builder.py
@@ -520,6 +520,9 @@ class BuilderBase:
t.builder_set(self)
new_targets.append(t)
+ orig_tlist = tlist[:]
+ orig_slist = slist[:]
+
target, source = self.emitter(target=tlist, source=slist, env=env)
# Now delete the temporary builders that we attached to any
@@ -533,8 +536,10 @@ class BuilderBase:
# Have to call arg2nodes yet again, since it is legal for
# emitters to spit out strings as well as Node instances.
- tlist = env.arg2nodes(target, target_factory)
- slist = env.arg2nodes(source, source_factory)
+ tlist = env.arg2nodes(target, target_factory,
+ target=orig_tlist, source=orig_slist)
+ slist = env.arg2nodes(source, source_factory,
+ target=orig_tlist, source=orig_slist)
return tlist, slist
diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py
index bb5a69a..3996d5c 100644
--- a/src/engine/SCons/BuilderTests.py
+++ b/src/engine/SCons/BuilderTests.py
@@ -33,6 +33,7 @@ def Func():
import os.path
import sys
import types
+import StringIO
import unittest
import UserList
@@ -43,6 +44,8 @@ import SCons.Builder
import SCons.Environment
import SCons.Errors
+sys.stdout = StringIO.StringIO()
+
# Initial setup of the common environment for all tests,
# a temporary working directory containing a
# script for writing arguments to an output file.
@@ -95,7 +98,7 @@ class Environment:
source=None, dict=None, conv=None):
return SCons.Util.scons_subst_list(string, self, raw, target,
source, dict, conv)
- def arg2nodes(self, args, factory):
+ def arg2nodes(self, args, factory, **kw):
global env_arg2nodes_called
env_arg2nodes_called = 1
if not SCons.Util.is_List(args):
@@ -1210,28 +1213,32 @@ class BuilderTestCase(unittest.TestCase):
assert 'baz' in map(str, tgt.sources), map(str, tgt.sources)
assert 'bar' in map(str, tgt.sources), map(str, tgt.sources)
- # Test that, if an emitter sets a builder on the passed-in
- # targets and passes back new targets, the new builder doesn't
- # get overwritten.
+ def test_emitter_preserve_builder(self):
+ """Test an emitter not overwriting a newly-set builder"""
+ env = Environment()
+
new_builder = SCons.Builder.Builder(action='new')
node = MyNode('foo8')
new_node = MyNode('foo8.new')
- def emit3(target, source, env, nb=new_builder, nn=new_node):
+
+ def emit(target, source, env, nb=new_builder, nn=new_node):
for t in target:
t.builder = nb
return [nn], source
- builder3=SCons.Builder.Builder(action='foo',
- emitter=emit3,
- target_factory=MyNode,
- source_factory=MyNode)
- tgt = builder3(env, target=node, source='bar')[0]
+ builder=SCons.Builder.Builder(action='foo',
+ emitter=emit,
+ target_factory=MyNode,
+ source_factory=MyNode)
+ tgt = builder(env, target=node, source='bar')[0]
assert tgt is new_node, tgt
- assert tgt.builder is builder3, tgt.builder
+ assert tgt.builder is builder, tgt.builder
assert node.builder is new_builder, node.builder
- # Test use of a dictionary mapping file suffixes to
- # emitter functions
+ def test_emitter_suffix_map(self):
+ """Test mapping file suffixes to emitter functions"""
+ env = Environment()
+
def emit4a(target, source, env):
source = map(str, source)
target = map(lambda x: 'emit4a-' + x[:-3], source)
@@ -1240,61 +1247,86 @@ class BuilderTestCase(unittest.TestCase):
source = map(str, source)
target = map(lambda x: 'emit4b-' + x[:-3], source)
return (target, source)
- builder4 = SCons.Builder.Builder(action='foo',
- emitter={'.4a':emit4a,
- '.4b':emit4b},
- target_factory=MyNode,
- source_factory=MyNode)
- tgt = builder4(env, None, source='aaa.4a')[0]
+
+ builder = SCons.Builder.Builder(action='foo',
+ emitter={'.4a':emit4a,
+ '.4b':emit4b},
+ target_factory=MyNode,
+ source_factory=MyNode)
+ tgt = builder(env, None, source='aaa.4a')[0]
assert str(tgt) == 'emit4a-aaa', str(tgt)
- tgt = builder4(env, None, source='bbb.4b')[0]
+ tgt = builder(env, None, source='bbb.4b')[0]
assert str(tgt) == 'emit4b-bbb', str(tgt)
- tgt = builder4(env, None, source='ccc.4c')[0]
+ tgt = builder(env, None, source='ccc.4c')[0]
assert str(tgt) == 'ccc', str(tgt)
def emit4c(target, source, env):
source = map(str, source)
target = map(lambda x: 'emit4c-' + x[:-3], source)
return (target, source)
- builder4.add_emitter('.4c', emit4c)
- tgt = builder4(env, None, source='ccc.4c')[0]
+
+ builder.add_emitter('.4c', emit4c)
+ tgt = builder(env, None, source='ccc.4c')[0]
assert str(tgt) == 'emit4c-ccc', str(tgt)
- # Test a list of emitter functions.
- def emit5a(target, source, env):
+ def test_emitter_function_list(self):
+ """Test lists of emitter functions"""
+ env = Environment()
+
+ def emit1a(target, source, env):
source = map(str, source)
- target = target + map(lambda x: 'emit5a-' + x[:-2], source)
+ target = target + map(lambda x: 'emit1a-' + x[:-2], source)
return (target, source)
- def emit5b(target, source, env):
+ def emit1b(target, source, env):
source = map(str, source)
- target = target + map(lambda x: 'emit5b-' + x[:-2], source)
+ target = target + map(lambda x: 'emit1b-' + x[:-2], source)
return (target, source)
- builder5 = SCons.Builder.Builder(action='foo',
- emitter=[emit5a, emit5b],
+ builder1 = SCons.Builder.Builder(action='foo',
+ emitter=[emit1a, emit1b],
node_factory=MyNode)
- tgts = builder5(env, target='target-5', source='aaa.5')
+ tgts = builder1(env, target='target-1', source='aaa.1')
tgts = map(str, tgts)
- assert tgts == ['target-5', 'emit5a-aaa', 'emit5b-aaa'], tgts
+ assert tgts == ['target-1', 'emit1a-aaa', 'emit1b-aaa'], tgts
# Test a list of emitter functions through the environment.
- def emit6a(target, source, env):
+ def emit2a(target, source, env):
source = map(str, source)
- target = target + map(lambda x: 'emit6a-' + x[:-2], source)
+ target = target + map(lambda x: 'emit2a-' + x[:-2], source)
return (target, source)
- def emit6b(target, source, env):
+ def emit2b(target, source, env):
source = map(str, source)
- target = target + map(lambda x: 'emit6b-' + x[:-2], source)
+ target = target + map(lambda x: 'emit2b-' + x[:-2], source)
return (target, source)
- builder6 = SCons.Builder.Builder(action='foo',
+ builder2 = SCons.Builder.Builder(action='foo',
emitter='$EMITTERLIST',
node_factory=MyNode)
- env = Environment(EMITTERLIST = [emit6a, emit6b])
+ env = Environment(EMITTERLIST = [emit2a, emit2b])
- tgts = builder6(env, target='target-6', source='aaa.6')
+ tgts = builder2(env, target='target-2', source='aaa.2')
tgts = map(str, tgts)
- assert tgts == ['target-6', 'emit6a-aaa', 'emit6b-aaa'], tgts
+ assert tgts == ['target-2', 'emit2a-aaa', 'emit2b-aaa'], tgts
+
+ def test_emitter_TARGET_SOURCE(self):
+ """Test use of $TARGET and $SOURCE in emitter results"""
+
+ env = SCons.Environment.Environment()
+
+ def emit(target, source, env):
+ return (target + ['${SOURCE}.s1', '${TARGET}.t1'],
+ source + ['${TARGET}.t2', '${SOURCE}.s2'])
+
+ builder = SCons.Builder.Builder(action='foo',
+ emitter = emit,
+ node_factory = MyNode)
+
+ targets = builder(env, target = 'TTT', source ='SSS')
+ sources = targets[0].sources
+ targets = map(str, targets)
+ sources = map(str, sources)
+ assert targets == ['TTT', 'SSS.s1', 'TTT.t1'], targets
+ assert sources == ['SSS', 'TTT.t2', 'SSS.s2'], targets
def test_no_target(self):
"""Test deducing the target from the source."""
diff --git a/src/engine/SCons/Conftest.py b/src/engine/SCons/Conftest.py
index 81a8ee4..bb3be56 100644
--- a/src/engine/SCons/Conftest.py
+++ b/src/engine/SCons/Conftest.py
@@ -462,7 +462,7 @@ def _Have(context, key, have):
key_up = re.sub('[^A-Z0-9_]', '_', key_up)
context.havedict[key_up] = have
if have == 1:
- line = "#define %s\n" % key_up
+ line = "#define %s 1\n" % key_up
elif have == 0:
line = "/* #undef %s */\n" % key_up
elif type(have) == IntType:
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index e5eb40c..94cdf74 100644
--- a/src/engine/SCons/Environment.py
+++ b/src/engine/SCons/Environment.py
@@ -327,7 +327,7 @@ class SubstitutionEnvironment:
def items(self):
return self._dict.items()
- def arg2nodes(self, args, node_factory=_null, lookup_list=_null):
+ def arg2nodes(self, args, node_factory=_null, lookup_list=_null, **kw):
if node_factory is _null:
node_factory = self.fs.File
if lookup_list is _null:
@@ -351,7 +351,9 @@ class SubstitutionEnvironment:
break
if not n is None:
if SCons.Util.is_String(n):
- n = self.subst(n, raw=1)
+ # n = self.subst(n, raw=1, **kw)
+ kw['raw'] = 1
+ n = apply(self.subst, (n,), kw)
if node_factory:
n = node_factory(n)
if SCons.Util.is_List(n):
@@ -359,7 +361,9 @@ class SubstitutionEnvironment:
else:
nodes.append(n)
elif node_factory:
- v = node_factory(self.subst(v, raw=1))
+ # v = node_factory(self.subst(v, raw=1, **kw))
+ kw['raw'] = 1
+ v = node_factory(apply(self.subst, (v,), kw))
if SCons.Util.is_List(v):
nodes.extend(v)
else:
@@ -473,6 +477,14 @@ class SubstitutionEnvironment:
raise OSError("'%s' exited %d" % (command, status))
return out
+ def AddMethod(self, function, name=None):
+ """
+ Adds the specified function as a method of this construction
+ environment with the specified name. If the name is omitted,
+ the default name is the name of the function itself.
+ """
+ SCons.Util.AddMethod(self, function, name)
+
def Override(self, overrides):
"""
Produce a modified environment whose variables are overriden by
@@ -1453,7 +1465,7 @@ class Base(SubstitutionEnvironment):
def AlwaysBuild(self, *targets):
tlist = []
for t in targets:
- tlist.extend(self.arg2nodes(t, self.fs.File))
+ tlist.extend(self.arg2nodes(t, self.fs.Entry))
for t in tlist:
t.set_always_build()
return tlist
diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py
index 70f9026..a8b718d 100644
--- a/src/engine/SCons/EnvironmentTests.py
+++ b/src/engine/SCons/EnvironmentTests.py
@@ -357,6 +357,22 @@ class SubstitutionTestCase(unittest.TestCase):
assert not hasattr(nodes[1], 'bbbb'), nodes[0]
assert nodes[1].c == 1, nodes[1]
+ def test_arg2nodes_target_source(self):
+ """Test the arg2nodes method with target= and source= keywords
+ """
+ targets = [DummyNode('t1'), DummyNode('t2')]
+ sources = [DummyNode('s1'), DummyNode('s2')]
+ env = SubstitutionEnvironment()
+ nodes = env.arg2nodes(['${TARGET}-a',
+ '${SOURCE}-b',
+ '${TARGETS[1]}-c',
+ '${SOURCES[1]}-d'],
+ DummyNode,
+ target=targets,
+ source=sources)
+ names = map(lambda n: n.name, nodes)
+ assert names == ['t1-a', 's1-b', 't2-c', 's2-d'], names
+
def test_gvars(self):
"""Test the base class gvars() method"""
env = SubstitutionEnvironment()
@@ -626,6 +642,38 @@ sys.exit(1)
finally:
sys.stderr = save_stderr
+ def test_AddMethod(self):
+ """Test the AddMethod() method"""
+ env = SubstitutionEnvironment(FOO = 'foo')
+
+ def func(self):
+ return 'func-' + self['FOO']
+
+ assert not hasattr(env, 'func')
+ env.AddMethod(func)
+ r = env.func()
+ assert r == 'func-foo', r
+
+ assert not hasattr(env, 'bar')
+ env.AddMethod(func, 'bar')
+ r = env.bar()
+ assert r == 'func-foo', r
+
+ def func2(self, arg=''):
+ return 'func2-' + self['FOO'] + arg
+
+ env.AddMethod(func2)
+ r = env.func2()
+ assert r == 'func2-foo', r
+ r = env.func2('-xxx')
+ assert r == 'func2-foo-xxx', r
+
+ env.AddMethod(func2, 'func')
+ r = env.func()
+ assert r == 'func2-foo', r
+ r = env.func('-yyy')
+ assert r == 'func2-foo-yyy', r
+
def test_Override(self):
"Test overriding construction variables"
env = SubstitutionEnvironment(ONE=1, TWO=2, THREE=3, FOUR=4)
@@ -2390,22 +2438,29 @@ def generate(env):
def test_AlwaysBuild(self):
"""Test the AlwaysBuild() method"""
env = self.TestEnvironment(FOO='fff', BAR='bbb')
- t = env.AlwaysBuild('a', 'b$FOO', ['c', 'd'], '$BAR')
- assert t[0].__class__.__name__ == 'File'
+ t = env.AlwaysBuild('a', 'b$FOO', ['c', 'd'], '$BAR',
+ env.fs.Dir('dir'), env.fs.File('file'))
+ assert t[0].__class__.__name__ == 'Entry'
assert t[0].path == 'a'
assert t[0].always_build
- assert t[1].__class__.__name__ == 'File'
+ assert t[1].__class__.__name__ == 'Entry'
assert t[1].path == 'bfff'
assert t[1].always_build
- assert t[2].__class__.__name__ == 'File'
+ assert t[2].__class__.__name__ == 'Entry'
assert t[2].path == 'c'
assert t[2].always_build
- assert t[3].__class__.__name__ == 'File'
+ assert t[3].__class__.__name__ == 'Entry'
assert t[3].path == 'd'
assert t[3].always_build
- assert t[4].__class__.__name__ == 'File'
+ assert t[4].__class__.__name__ == 'Entry'
assert t[4].path == 'bbb'
assert t[4].always_build
+ assert t[5].__class__.__name__ == 'Dir'
+ assert t[5].path == 'dir'
+ assert t[5].always_build
+ assert t[6].__class__.__name__ == 'File'
+ assert t[6].path == 'file'
+ assert t[6].always_build
def test_BuildDir(self):
"""Test the BuildDir() method"""
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index a16fee4..c9a1443 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -232,7 +232,10 @@ def CacheRetrieveFunc(target, source, env):
return 1
fs.CacheDebug('CacheRetrieve(%s): retrieving from %s\n', t, cachefile)
if SCons.Action.execute_actions:
- fs.copy2(cachefile, t.path)
+ if fs.islink(cachefile):
+ fs.symlink(fs.readlink(cachefile), t.path)
+ else:
+ fs.copy2(cachefile, t.path)
st = fs.stat(cachefile)
fs.chmod(t.path, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
return 0
@@ -272,7 +275,10 @@ def CachePushFunc(target, source, env):
tempfile = cachefile+'.tmp'
try:
- fs.copy2(t.path, tempfile)
+ if fs.islink(t.path):
+ fs.symlink(fs.readlink(t.path), tempfile)
+ else:
+ fs.copy2(t.path, tempfile)
fs.rename(tempfile, cachefile)
st = fs.stat(t.path)
fs.chmod(cachefile, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
@@ -2269,8 +2275,6 @@ class File(Base):
self.binfo = self.gen_binfo(calc)
return self._cur2()
def _cur2(self):
- if self.always_build:
- return None
if not self.exists():
# The file doesn't exist locally...
r = self.rfile()
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 6644d7a..f550b5b 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -1046,32 +1046,27 @@ class Node:
if not self.exists():
return "building `%s' because it doesn't exist\n" % self
+ if self.always_build:
+ return "rebuilding `%s' because AlwaysBuild() is specified\n" % self
+
old = self.get_stored_info()
if old is None:
return None
old.prepare_dependencies()
- def dictify(result, kids, sigs):
- for k, s in zip(kids, sigs):
- result[k] = s
-
try:
- osig = {}
- dictify(osig, old.bsources, old.bsourcesigs)
- dictify(osig, old.bdepends, old.bdependsigs)
- dictify(osig, old.bimplicit, old.bimplicitsigs)
+ old_bkids = old.bsources + old.bdepends + old.bimplicit
+ old_bkidsigs = old.bsourcesigs + old.bdependsigs + old.bimplicitsigs
except AttributeError:
return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self
new = self.get_binfo()
- nsig = {}
- dictify(nsig, new.bsources, new.bsourcesigs)
- dictify(nsig, new.bdepends, new.bdependsigs)
- dictify(nsig, new.bimplicit, new.bimplicitsigs)
+ new_bkids = new.bsources + new.bdepends + new.bimplicit
+ new_bkidsigs = new.bsourcesigs + new.bdependsigs + new.bimplicitsigs
- old_bkids = old.bsources + old.bdepends + old.bimplicit
- new_bkids = new.bsources + new.bdepends + new.bimplicit
+ osig = dict(zip(old_bkids, old_bkidsigs))
+ nsig = dict(zip(new_bkids, new_bkidsigs))
# The sources and dependencies we'll want to report are all stored
# as relative paths to this target's directory, but we want to
diff --git a/src/engine/SCons/Platform/sunos.py b/src/engine/SCons/Platform/sunos.py
index ed9521e..5029860 100644
--- a/src/engine/SCons/Platform/sunos.py
+++ b/src/engine/SCons/Platform/sunos.py
@@ -41,4 +41,4 @@ def generate(env):
env['MAXLINELENGTH'] = 1045320
env['PKGINFO'] = 'pkginfo'
env['PKGCHK'] = '/usr/sbin/pkgchk'
- env['ENV']['PATH'] = env['ENV']['PATH'] + ':/usr/ccs/bin'
+ env['ENV']['PATH'] = env['ENV']['PATH'] + ':/opt/SUNWspro/bin:/usr/ccs/bin'
diff --git a/src/engine/SCons/Scanner/LaTeX.py b/src/engine/SCons/Scanner/LaTeX.py
index d875e6e..645a894 100644
--- a/src/engine/SCons/Scanner/LaTeX.py
+++ b/src/engine/SCons/Scanner/LaTeX.py
@@ -39,7 +39,7 @@ def LaTeXScanner(fs = SCons.Node.FS.default_fs):
ds = LaTeX(name = "LaTeXScanner",
suffixes = '$LATEXSUFFIXES',
path_variable = 'TEXINPUTS',
- regex = '\\\\(include|includegraphics(?:\[[^\]]+\])?|input|bibliography){([^}]*)}',
+ regex = '\\\\(include|includegraphics(?:\[[^\]]+\])?|input|bibliography|usepackage){([^}]*)}',
recursive = 0)
return ds
@@ -72,6 +72,10 @@ class LaTeX(SCons.Scanner.Classic):
base, ext = os.path.splitext( filename )
if ext == "":
filename = filename + '.bib'
+ if include[0] == 'usepackage':
+ base, ext = os.path.splitext( filename )
+ if ext == "":
+ filename = filename + '.sty'
return filename
def sort_key(self, include):
return SCons.Node.FS._my_normcase(self.latex_name(include))
diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py
index ca7f68c..d80050d 100644
--- a/src/engine/SCons/Script/Main.py
+++ b/src/engine/SCons/Script/Main.py
@@ -40,7 +40,6 @@ import SCons.compat
import os
import os.path
-import random
import string
import sys
import time
@@ -789,7 +788,7 @@ class OptParser(OptionParser):
help="Read FILE as the top-level SConstruct file.")
self.add_option('-h', '--help', action="store_true", default=0,
- dest="help_msg",
+ dest="help",
help="Print defined help message, or this one.")
self.add_option("-H", "--help-options",
@@ -988,13 +987,18 @@ class SConscriptSettableOptions:
# This dictionary stores the defaults for all the SConscript
# settable options, as well as indicating which options
- # are SConscript settable.
- self.settable = {'num_jobs':1,
- 'max_drift':SCons.Node.FS.default_max_drift,
- 'implicit_cache':0,
- 'clean':0,
- 'duplicate':'hard-soft-copy',
- 'diskcheck':diskcheck_all}
+ # are SConscript settable (and gettable, which for options
+ # like 'help' is far more important than being settable).
+ self.settable = {
+ 'clean' : 0,
+ 'diskcheck' : diskcheck_all,
+ 'duplicate' : 'hard-soft-copy',
+ 'help' : 0,
+ 'implicit_cache' : 0,
+ 'max_drift' : SCons.Node.FS.default_max_drift,
+ 'num_jobs' : 1,
+ 'random' : 0,
+ }
def get(self, name):
if not self.settable.has_key(name):
@@ -1118,7 +1122,7 @@ def _main(args, parser):
scripts.append(sfile)
if not scripts:
- if options.help_msg:
+ if options.help:
# There's no SConstruct, but they specified -h.
# Give them the options usage now, before we fail
# trying to read a non-existent SConstruct file.
@@ -1225,7 +1229,7 @@ def _main(args, parser):
fs.chdir(fs.Top)
- if options.help_msg:
+ if ssoptions.get('help'):
help_text = SCons.Script.help_text
if help_text is None:
# They specified -h, but there was no Help() inside the
@@ -1341,6 +1345,7 @@ def _main(args, parser):
if options.random:
def order(dependencies):
"""Randomize the dependencies."""
+ import random
# This is cribbed from the implementation of
# random.shuffle() in Python 2.X.
d = dependencies
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index fde4997..e970989 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -131,6 +131,7 @@ call_stack = _SConscript.call_stack
#
Action = SCons.Action.Action
+AddMethod = SCons.Util.AddMethod
AllowSubstExceptions = SCons.Subst.SetAllowableExceptions
BoolOption = SCons.Options.BoolOption
Builder = SCons.Builder.Builder
diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py
index 9a5011b..acb8c9b 100644
--- a/src/engine/SCons/Taskmaster.py
+++ b/src/engine/SCons/Taskmaster.py
@@ -275,8 +275,9 @@ class Task:
"""
self.out_of_date = []
for t in self.targets:
+ t.disambiguate()
try:
- is_up_to_date = t.disambiguate().current()
+ is_up_to_date = not t.always_build and t.current()
except EnvironmentError, e:
raise SCons.Errors.BuildError(node=t, errstr=e.strerror, filename=e.filename)
if is_up_to_date:
diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py
index 757306f..718851d 100644
--- a/src/engine/SCons/TaskmasterTests.py
+++ b/src/engine/SCons/TaskmasterTests.py
@@ -63,6 +63,7 @@ class Node:
self.postprocessed = None
self._bsig_val = None
self._current_val = 0
+ self.always_build = None
def disambiguate(self):
return self
@@ -495,7 +496,10 @@ class TaskmasterTestCase(unittest.TestCase):
n3 = Node("n3")
c4 = Node("c4")
c4._current_val = 1
- tm = SCons.Taskmaster.Taskmaster(targets = [n1, c2, n3, c4],
+ a5 = Node("a5")
+ a5._current_val = 1
+ a5.always_build = 1
+ tm = SCons.Taskmaster.Taskmaster(targets = [n1, c2, n3, c4, a5],
tasker = TaskGen)
del ood[:]
@@ -514,6 +518,9 @@ class TaskmasterTestCase(unittest.TestCase):
t = tm.next_task()
assert ood == [], ood
+ del ood[:]
+ t = tm.next_task()
+ assert ood == [a5], ood
def test_make_ready_exception(self):
"""Test handling exceptions from Task.make_ready()
diff --git a/src/engine/SCons/Tool/JavaCommon.py b/src/engine/SCons/Tool/JavaCommon.py
index 177d579..d340d5b 100644
--- a/src/engine/SCons/Tool/JavaCommon.py
+++ b/src/engine/SCons/Tool/JavaCommon.py
@@ -53,7 +53,7 @@ if java_parsing:
# array declarations "[]";
# semi-colons;
# periods.
- _reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"\{\}\;\.]|' +
+ _reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"\{\}\;\.\(\)]|' +
r'[A-Za-z_][\w\.]*|/\*|\*/|\[\])')
class OuterState:
@@ -90,6 +90,7 @@ if java_parsing:
try:
return self.anonState
except AttributeError:
+ self.outer_state = self
ret = SkipState(1, AnonClassState(self))
self.anonState = ret
return ret
@@ -154,23 +155,36 @@ if java_parsing:
class AnonClassState:
"""A state that looks for anonymous inner classes."""
- def __init__(self, outer_state):
+ def __init__(self, old_state):
# outer_state is always an instance of OuterState
- self.outer_state = outer_state
- self.tokens_to_find = 2
+ self.outer_state = old_state.outer_state
+ self.old_state = old_state
+ self.brace_level = 0
def parseToken(self, token):
- # This is an anonymous class if and only if the next
- # non-whitespace token is a bracket
- if token == '\n':
+ # This is an anonymous class if and only if the next
+ # non-whitespace token is a bracket. Everything between
+ # braces should be parsed as normal java code.
+ if token[:2] == '//':
+ return IgnoreState('\n', self)
+ elif token == '/*':
+ return IgnoreState('*/', self)
+ elif token == '\n':
+ return self
+ elif token == '(':
+ self.brace_level = self.brace_level + 1
+ return self
+ if self.brace_level > 0:
+ if token == 'new':
+ # look further for anonymous inner class
+ return SkipState(1, AnonClassState(self))
+ elif token in [ '"', "'" ]:
+ return IgnoreState(token, self)
+ elif token == ')':
+ self.brace_level = self.brace_level - 1
return self
if token == '{':
- self.outer_state.openBracket()
self.outer_state.addAnonClass()
- elif token == '}':
- self.outer_state.closeBracket()
- elif token in ['"', "'"]:
- return IgnoreState(token, self)
- return self.outer_state
+ return self.old_state.parseToken(token)
class SkipState:
"""A state that will skip a specified number of tokens before
diff --git a/src/engine/SCons/Tool/JavaCommonTests.py b/src/engine/SCons/Tool/JavaCommonTests.py
index 853afd4..e848bf9 100644
--- a/src/engine/SCons/Tool/JavaCommonTests.py
+++ b/src/engine/SCons/Tool/JavaCommonTests.py
@@ -329,6 +329,30 @@ public class A {
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("""\
+import java.io.File;
+
+public class Foo {
+ public static void main(String[] args) {
+ File f = new File(
+ new File("a") {
+ public String toString() {
+ return "b";
+ }
+ } to String()
+ ) {
+ public String toString() {
+ return "c";
+ }
+ };
+ }
+}
+""")
+ assert classes == ['Foo$1', 'Foo$2', 'Foo'], classes
+
+
if __name__ == "__main__":
diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py
index b2e2eff..dea77fd 100644
--- a/src/engine/SCons/Tool/__init__.py
+++ b/src/engine/SCons/Tool/__init__.py
@@ -316,7 +316,8 @@ def createCFileBuilders(env):
emitter = {},
suffix = {None:'$CFILESUFFIX'})
env['BUILDERS']['CFile'] = c_file
- env['CFILESUFFIX'] = '.c'
+
+ env.SetDefault(CFILESUFFIX = '.c')
try:
cxx_file = env['BUILDERS']['CXXFile']
@@ -325,7 +326,7 @@ def createCFileBuilders(env):
emitter = {},
suffix = {None:'$CXXFILESUFFIX'})
env['BUILDERS']['CXXFile'] = cxx_file
- env['CXXFILESUFFIX'] = '.cc'
+ env.SetDefault(CXXFILESUFFIX = '.cc')
return (c_file, cxx_file)
diff --git a/src/engine/SCons/Tool/midl.py b/src/engine/SCons/Tool/midl.py
index 67579e9..811d573 100644
--- a/src/engine/SCons/Tool/midl.py
+++ b/src/engine/SCons/Tool/midl.py
@@ -33,6 +33,8 @@ selection method.
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+import string
+
import SCons.Action
import SCons.Builder
import SCons.Defaults
@@ -46,11 +48,17 @@ def midl_emitter(target, source, env):
tlb = target[0]
incl = base + '.h'
interface = base + '_i.c'
- proxy = base + '_p.c'
- dlldata = base + '_data.c'
+ t = [tlb, incl, interface]
- t = [tlb, incl, interface, proxy, dlldata]
+ midlcom = env['MIDLCOM']
+ if string.find(midlcom, '/proxy') != -1:
+ proxy = base + '_p.c'
+ t.append(proxy)
+ if string.find(midlcom, '/dlldata') != -1:
+ dlldata = base + '_data.c'
+ t.append(dlldata)
+
return (t,source)
idl_scanner = SCons.Scanner.IDL.IDLScan()
diff --git a/src/engine/SCons/Tool/mslink.py b/src/engine/SCons/Tool/mslink.py
index 4b90e3d..c071aa7 100644
--- a/src/engine/SCons/Tool/mslink.py
+++ b/src/engine/SCons/Tool/mslink.py
@@ -45,10 +45,10 @@ import SCons.Tool.msvs
import SCons.Util
def pdbGenerator(env, target, source, for_signature):
- if target and env.has_key('PDB') and env['PDB']:
- return ['/PDB:%s'%target[0].File(env['PDB']).get_string(for_signature),
- '/DEBUG']
- return None
+ try:
+ return ['/PDB:%s' % target[0].attributes.pdb, '/DEBUG']
+ except (AttributeError, IndexError):
+ return None
def windowsShlinkTargets(target, source, env, for_signature):
listCmd = []
@@ -99,7 +99,9 @@ def windowsLibEmitter(target, source, env):
"WINDOWSSHLIBMANIFESTPREFIX", "WINDOWSSHLIBMANIFESTSUFFIX"))
if env.has_key('PDB') and env['PDB']:
- target.append(env['PDB'])
+ pdb = env.arg2nodes('$PDB', target=target, source=source)[0]
+ target.append(pdb)
+ target[0].attributes.pdb = pdb
if not no_import_lib and \
not env.FindIxes(target, "LIBPREFIX", "LIBSUFFIX"):
@@ -129,7 +131,9 @@ def prog_emitter(target, source, env):
"WINDOWSPROGMANIFESTPREFIX", "WINDOWSPROGMANIFESTSUFFIX"))
if env.has_key('PDB') and env['PDB']:
- target.append(env['PDB'])
+ pdb = env.arg2nodes('$PDB', target=target, source=source)[0]
+ target.append(pdb)
+ target[0].attributes.pdb = pdb
return (target,source)
diff --git a/src/engine/SCons/Tool/msvs.py b/src/engine/SCons/Tool/msvs.py
index db8e8fd..138f920 100644
--- a/src/engine/SCons/Tool/msvs.py
+++ b/src/engine/SCons/Tool/msvs.py
@@ -1018,8 +1018,10 @@ class _GenerateV7DSW(_DSWGenerator):
self.file.write('\t\t%s.%s|%s.ActiveCfg = %s|%s\n'
'\t\t%s.%s|%s.Build.0 = %s|%s\n' % (guid,variant,platform,variant,platform,guid,variant,platform,variant,platform))
else:
- self.file.write('\t\t%s.%s.ActiveCfg = %s|%s\n'
- '\t\t%s.%s.Build.0 = %s|%s\n' %(self.slnguid,variant,variant,platform,self.slnguid,variant,variant,platform))
+ for p in self.dspfiles:
+ guid = _generateGUID(p, '')
+ self.file.write('\t\t%s.%s.ActiveCfg = %s|%s\n'
+ '\t\t%s.%s.Build.0 = %s|%s\n' %(guid,variant,variant,platform,guid,variant,variant,platform))
self.file.write('\tEndGlobalSection\n')
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index f1e856b..a5ea859 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -950,3 +950,79 @@ class Unbuffered:
self.file.flush()
def __getattr__(self, attr):
return getattr(self.file, attr)
+
+# The original idea for AddMethod() and RenameFunction() come from the
+# following post to the ActiveState Python Cookbook:
+#
+# ASPN: Python Cookbook : Install bound methods in an instance
+# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/223613
+#
+# That code was a little fragile, though, so the following changes
+# have been wrung on it:
+#
+# * Switched the installmethod() "object" and "function" arguments,
+# so the order reflects that the left-hand side is the thing being
+# "assigned to" and the right-hand side is the value being assigned.
+#
+# * Changed explicit type-checking to the "try: klass = object.__class__"
+# block in installmethod() below so that it still works with the
+# old-style classes that SCons uses.
+#
+# * Replaced the by-hand creation of methods and functions with use of
+# the "new" module, as alluded to in Alex Martelli's response to the
+# following Cookbook post:
+#
+# ASPN: Python Cookbook : Dynamically added methods to a class
+# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732
+
+def AddMethod(object, function, name = None):
+ """
+ Adds either a bound method to an instance or an unbound method to
+ a class. If name is ommited the name of the specified function
+ is used by default.
+ Example:
+ a = A()
+ def f(self, x, y):
+ self.z = x + y
+ AddMethod(f, A, "add")
+ a.add(2, 4)
+ print a.z
+ AddMethod(lambda self, i: self.l[i], a, "listIndex")
+ print a.listIndex(5)
+ """
+ import new
+
+ if name is None:
+ name = function.func_name
+ else:
+ function = RenameFunction(function, name)
+
+ try:
+ klass = object.__class__
+ except AttributeError:
+ # "object" is really a class, so it gets an unbound method.
+ object.__dict__[name] = new.instancemethod(function, None, object)
+ else:
+ # "object" is really an instance, so it gets a bound method.
+ object.__dict__[name] = new.instancemethod(function, object, klass)
+
+def RenameFunction(function, name):
+ """
+ Returns a function identical to the specified function, but with
+ the specified name.
+ """
+ import new
+
+ # Compatibility for Python 1.5 and 2.1. Can be removed in favor of
+ # passing function.func_defaults directly to new.function() once
+ # we base on Python 2.2 or later.
+ func_defaults = function.func_defaults
+ if func_defaults is None:
+ func_defaults = ()
+
+ return new.function(function.func_code,
+ function.func_globals,
+ name,
+ func_defaults)
+
+del __revision__
diff --git a/src/engine/SCons/compat/builtins.py b/src/engine/SCons/compat/builtins.py
index a477a48..1124cf0 100644
--- a/src/engine/SCons/compat/builtins.py
+++ b/src/engine/SCons/compat/builtins.py
@@ -76,11 +76,13 @@ try:
dict
except NameError:
# Pre-2.2 Python has no dict() keyword.
- def dict(*arg, **kwargs):
+ def dict(seq=[], **kwargs):
"""
New dictionary initialization.
"""
- d = apply(types.DictType, arg)
+ d = {}
+ for k, v in seq:
+ d[k] = v
d.update(kwargs)
return d
__builtin__.dict = dict