summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGary Oberbrunner <garyo@oberbrunner.com>2012-05-19 22:16:42 (GMT)
committerGary Oberbrunner <garyo@oberbrunner.com>2012-05-19 22:16:42 (GMT)
commitbcff49f744d5ab7a69381e5b1ee24f172403378a (patch)
tree52e04144ac53a6efb7dc802b61f9b9e43efb5d41 /src
parentf011342d8018a0cd8ef18de017d84a12cd157f6d (diff)
parent65986dc7db253685d1e44753a49691b63cf53433 (diff)
downloadSCons-bcff49f744d5ab7a69381e5b1ee24f172403378a.zip
SCons-bcff49f744d5ab7a69381e5b1ee24f172403378a.tar.gz
SCons-bcff49f744d5ab7a69381e5b1ee24f172403378a.tar.bz2
Merge mortoray/SCons fix for #2821, copy Builders when env is cloned.
Diffstat (limited to 'src')
-rw-r--r--src/CHANGES.txt1
-rw-r--r--src/engine/SCons/Environment.py19
-rw-r--r--src/engine/SCons/Util.py14
3 files changed, 19 insertions, 15 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index cbaffb3..f759622 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -8,6 +8,7 @@ RELEASE 2.X.X -
From Mortoray:
- Make -s (silent mode) be silent about entering subdirs (#2976).
+ - Fix cloning of builders when cloning environment (#2821).
From Gary Oberbrunner:
- Show valid Visual Studio architectures in error message
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index b308765..529e3a3 100644
--- a/src/engine/SCons/Environment.py
+++ b/src/engine/SCons/Environment.py
@@ -72,6 +72,7 @@ CleanTargets = {}
CalculatorArgs = {}
semi_deepcopy = SCons.Util.semi_deepcopy
+semi_deepcopy_dict = SCons.Util.semi_deepcopy_dict
# Pull UserError into the global name space for the benefit of
# Environment().SourceSignatures(), which has some import statements
@@ -303,7 +304,9 @@ class BuilderDict(UserDict):
UserDict.__init__(self, dict)
def __semi_deepcopy__(self):
- return self.__class__(self.data, self.env)
+ # These cannot be copied since they would both modify the same builder object, and indeed
+ # just copying would modify the original builder
+ raise TypeError( 'cannot semi_deepcopy a BuilderDict' )
def __setitem__(self, item, val):
try:
@@ -1374,15 +1377,15 @@ class Base(SubstitutionEnvironment):
(like a function). There are no references to any mutable
objects in the original Environment.
"""
- clone = copy.copy(self)
- clone._dict = semi_deepcopy(self._dict)
-
try:
- cbd = clone._dict['BUILDERS']
+ builders = self._dict['BUILDERS']
except KeyError:
pass
- else:
- clone._dict['BUILDERS'] = BuilderDict(cbd, clone)
+
+ clone = copy.copy(self)
+ # BUILDERS is not safe to do a simple copy
+ clone._dict = semi_deepcopy_dict(self._dict, ['BUILDERS'])
+ clone._dict['BUILDERS'] = BuilderDict(builders, clone)
# Check the methods added via AddMethod() and re-bind them to
# the cloned environment. Only do this if the attribute hasn't
@@ -1733,7 +1736,7 @@ class Base(SubstitutionEnvironment):
except KeyError:
pass
else:
- kwbd = semi_deepcopy(kwbd)
+ kwbd = BuilderDict(kwbd,self)
del kw['BUILDERS']
self.__setitem__('BUILDERS', kwbd)
kw = copy_non_reserved_keywords(kw)
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index 2523eda..822d524 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -430,15 +430,15 @@ def to_String_for_signature(obj, to_String_for_subst=to_String_for_subst,
# references to anything else it finds.
#
# A special case is any object that has a __semi_deepcopy__() method,
-# which we invoke to create the copy, which is used by the BuilderDict
-# class because of its extra initialization argument.
+# which we invoke to create the copy. Currently only used by
+# BuilderDict to actually prevent the copy operation (as invalid on that object)
#
# The dispatch table approach used here is a direct rip-off from the
# normal Python copy module.
_semi_deepcopy_dispatch = d = {}
-def _semi_deepcopy_dict(x):
+def semi_deepcopy_dict(x, exclude = [] ):
copy = {}
for key, val in x.items():
# The regular Python copy.deepcopy() also deepcopies the key,
@@ -447,9 +447,10 @@ def _semi_deepcopy_dict(x):
# copy[semi_deepcopy(key)] = semi_deepcopy(val)
#
# Doesn't seem like we need to, but we'll comment it just in case.
- copy[key] = semi_deepcopy(val)
+ if key not in exclude:
+ copy[key] = semi_deepcopy(val)
return copy
-d[dict] = _semi_deepcopy_dict
+d[dict] = semi_deepcopy_dict
def _semi_deepcopy_list(x):
return list(map(semi_deepcopy, x))
@@ -467,14 +468,13 @@ def semi_deepcopy(x):
if hasattr(x, '__semi_deepcopy__') and callable(x.__semi_deepcopy__):
return x.__semi_deepcopy__()
elif isinstance(x, UserDict):
- return x.__class__(_semi_deepcopy_dict(x))
+ return x.__class__(semi_deepcopy_dict(x))
elif isinstance(x, UserList):
return x.__class__(_semi_deepcopy_list(x))
return x
-
class Proxy(object):
"""A simple generic Proxy class, forwarding all calls to
subject. So, for the benefit of the python newbie, what does