summaryrefslogtreecommitdiff
path: root/SCons/Environment.py
diff options
context:
space:
mode:
authorWilliam Deegan <bill@baddogconsulting.com>2021-03-07 10:15:03 -0800
committerGitHub <noreply@github.com>2021-03-07 10:15:03 -0800
commit34a02088041f094d2a0a23d065547b88f90595ce (patch)
treef6f403c743e4b3fc5131666bf931466236d40780 /SCons/Environment.py
parentca18475fb0fbc901c6bcd6520d9f8c649c071b9d (diff)
parent98ebdf77bcef9c266d9d6a1776408b6c1a78f935 (diff)
downloadscons-git-34a02088041f094d2a0a23d065547b88f90595ce.tar.gz
Merge branch 'master' into topic/grossag/newhashes
Diffstat (limited to 'SCons/Environment.py')
-rw-r--r--SCons/Environment.py269
1 files changed, 141 insertions, 128 deletions
diff --git a/SCons/Environment.py b/SCons/Environment.py
index e730b34bb..902d8f786 100644
--- a/SCons/Environment.py
+++ b/SCons/Environment.py
@@ -406,9 +406,8 @@ class SubstitutionEnvironment:
# key and we don't need to check. If we do check, using a
# global, pre-compiled regular expression directly is more
# efficient than calling another function or a method.
- if key not in self._dict \
- and not _is_valid_var.match(key):
- raise UserError("Illegal construction variable `%s'" % key)
+ if key not in self._dict and not _is_valid_var.match(key):
+ raise UserError("Illegal construction variable `%s'" % key)
self._dict[key] = value
def get(self, key, default=None):
@@ -634,7 +633,7 @@ class SubstitutionEnvironment:
Parse ``flags`` and return a dict with the flags distributed into
the appropriate construction variable names. The flags are treated
as a typical set of command-line flags for a GNU-like toolchain,
- such as might have been generated by one of the \*-config scripts,
+ such as might have been generated by one of the {foo}-config scripts,
and used to populate the entries based on knowledge embedded in
this method - the choices are not expected to be portable to other
toolchains.
@@ -1172,88 +1171,92 @@ class Base(SubstitutionEnvironment):
#######################################################################
def Append(self, **kw):
- """Append values to existing construction variables in an Environment."""
+ """Append values to construction variables in an Environment.
+
+ The variable is created if it is not already present.
+ """
+
kw = copy_non_reserved_keywords(kw)
for key, val in kw.items():
- # It would be easier on the eyes to write this using
- # "continue" statements whenever we finish processing an item,
- # but Python 1.5.2 apparently doesn't let you use "continue"
- # within try:-except: blocks, so we have to nest our code.
try:
if key == 'CPPDEFINES' and is_String(self._dict[key]):
self._dict[key] = [self._dict[key]]
orig = self._dict[key]
except KeyError:
- # No existing variable in the environment, so just set
- # it to the new value.
+ # No existing var in the environment, so set to the new value.
if key == 'CPPDEFINES' and is_String(val):
self._dict[key] = [val]
else:
self._dict[key] = val
- else:
+ continue
+
+ try:
+ # Check if the original looks like a dict: has .update?
+ update_dict = orig.update
+ except AttributeError:
try:
- # Check if the original looks like a dictionary.
- # If it is, we can't just try adding the value because
- # dictionaries don't have __add__() methods, and
- # things like UserList will incorrectly coerce the
- # original dict to a list (which we don't want).
- update_dict = orig.update
- except AttributeError:
+ # Just try to add them together. This will work
+ # in most cases, when the original and new values
+ # are compatible types.
+ self._dict[key] = orig + val
+ except (KeyError, TypeError):
try:
- # Most straightforward: just try to add them
- # together. This will work in most cases, when the
- # original and new values are of compatible types.
- self._dict[key] = orig + val
- except (KeyError, TypeError):
- try:
- # Check if the original is a list.
- add_to_orig = orig.append
- except AttributeError:
- # The original isn't a list, but the new
- # value is (by process of elimination),
- # so insert the original in the new value
- # (if there's one to insert) and replace
- # the variable with it.
- if orig:
- val.insert(0, orig)
- self._dict[key] = val
+ # Check if the original is a list: has .append?
+ add_to_orig = orig.append
+ except AttributeError:
+ # The original isn't a list, but the new
+ # value is (by process of elimination),
+ # so insert the original in the new value
+ # (if there's one to insert) and replace
+ # the variable with it.
+ if orig:
+ val.insert(0, orig)
+ self._dict[key] = val
+ else:
+ # The original is a list, so append the new
+ # value to it (if there's a value to append).
+ if val:
+ add_to_orig(val)
+ continue
+
+ # The original looks like a dictionary, so update it
+ # based on what we think the value looks like.
+ # We can't just try adding the value because
+ # dictionaries don't have __add__() methods, and
+ # things like UserList will incorrectly coerce the
+ # original dict to a list (which we don't want).
+ if is_List(val):
+ if key == 'CPPDEFINES':
+ tmp = []
+ for (k, v) in orig.items():
+ if v is not None:
+ tmp.append((k, v))
else:
- # The original is a list, so append the new
- # value to it (if there's a value to append).
- if val:
- add_to_orig(val)
+ tmp.append((k,))
+ orig = tmp
+ orig += val
+ self._dict[key] = orig
else:
- # The original looks like a dictionary, so update it
- # based on what we think the value looks like.
- if is_List(val):
- if key == 'CPPDEFINES':
- tmp = []
- for (k, v) in orig.items():
- if v is not None:
- tmp.append((k, v))
- else:
- tmp.append((k,))
- orig = tmp
- orig += val
- self._dict[key] = orig
- else:
- for v in val:
- orig[v] = None
+ for v in val:
+ orig[v] = None
+ else:
+ try:
+ update_dict(val)
+ except (AttributeError, TypeError, ValueError):
+ if is_Dict(val):
+ for k, v in val.items():
+ orig[k] = v
else:
- try:
- update_dict(val)
- except (AttributeError, TypeError, ValueError):
- if is_Dict(val):
- for k, v in val.items():
- orig[k] = v
- else:
- orig[val] = None
+ orig[val] = None
+
self.scanner_map_delete(kw)
- # allow Dirs and strings beginning with # for top-relative
- # Note this uses the current env's fs (in self).
def _canonicalize(self, path):
- if not is_String(path): # typically a Dir
+ """Allow Dirs and strings beginning with # for top-relative.
+
+ Note this uses the current env's fs (in self).
+ """
+ if not is_String(path): # typically a Dir
path = str(path)
if path and path[0] == '#':
path = str(self.fs.Dir(path))
@@ -1294,8 +1297,7 @@ class Base(SubstitutionEnvironment):
val = _delete_duplicates(val, delete_existing)
if key not in self._dict or self._dict[key] in ('', None):
self._dict[key] = val
- elif is_Dict(self._dict[key]) and \
- is_Dict(val):
+ elif is_Dict(self._dict[key]) and is_Dict(val):
self._dict[key].update(val)
elif is_List(val):
dk = self._dict[key]
@@ -1534,7 +1536,7 @@ class Base(SubstitutionEnvironment):
def Dictionary(self, *args):
- """Return construction variables from an environment.
+ r"""Return construction variables from an environment.
Args:
\*args (optional): variable names to look up
@@ -1611,7 +1613,7 @@ class Base(SubstitutionEnvironment):
prefix = self.subst('$'+prefix)
for path in paths:
- dir,name = os.path.split(str(path))
+ name = os.path.basename(str(path))
if name[:len(prefix)] == prefix and name[-len(suffix):] == suffix:
return path
@@ -1680,68 +1682,68 @@ class Base(SubstitutionEnvironment):
return SCons.Platform.Platform(platform)(self)
def Prepend(self, **kw):
- """Prepend values to existing construction variables
- in an Environment.
+ """Prepend values to construction variables in an Environment.
+
+ The variable is created if it is not already present.
"""
+
kw = copy_non_reserved_keywords(kw)
for key, val in kw.items():
- # It would be easier on the eyes to write this using
- # "continue" statements whenever we finish processing an item,
- # but Python 1.5.2 apparently doesn't let you use "continue"
- # within try:-except: blocks, so we have to nest our code.
try:
orig = self._dict[key]
except KeyError:
- # No existing variable in the environment, so just set
- # it to the new value.
+ # No existing var in the environment so set to the new value.
self._dict[key] = val
- else:
+ continue
+
+ try:
+ # Check if the original looks like a dict: has .update?
+ update_dict = orig.update
+ except AttributeError:
try:
- # Check if the original looks like a dictionary.
- # If it is, we can't just try adding the value because
- # dictionaries don't have __add__() methods, and
- # things like UserList will incorrectly coerce the
- # original dict to a list (which we don't want).
- update_dict = orig.update
- except AttributeError:
+ # Just try to add them together. This will work
+ # in most cases, when the original and new values
+ # are compatible types.
+ self._dict[key] = val + orig
+ except (KeyError, TypeError):
try:
- # Most straightforward: just try to add them
- # together. This will work in most cases, when the
- # original and new values are of compatible types.
- self._dict[key] = val + orig
- except (KeyError, TypeError):
- try:
- # Check if the added value is a list.
- add_to_val = val.append
- except AttributeError:
- # The added value isn't a list, but the
- # original is (by process of elimination),
- # so insert the the new value in the original
- # (if there's one to insert).
- if val:
- orig.insert(0, val)
- else:
- # The added value is a list, so append
- # the original to it (if there's a value
- # to append).
- if orig:
- add_to_val(orig)
- self._dict[key] = val
- else:
- # The original looks like a dictionary, so update it
- # based on what we think the value looks like.
- if is_List(val):
- for v in val:
- orig[v] = None
+ # Check if the added value is a list: has .append?
+ add_to_val = val.append
+ except AttributeError:
+ # The added value isn't a list, but the
+ # original is (by process of elimination),
+ # so insert the the new value in the original
+ # (if there's one to insert).
+ if val:
+ orig.insert(0, val)
else:
- try:
- update_dict(val)
- except (AttributeError, TypeError, ValueError):
- if is_Dict(val):
- for k, v in val.items():
- orig[k] = v
- else:
- orig[val] = None
+ # The added value is a list, so append
+ # the original to it (if there's a value
+ # to append) and replace the original.
+ if orig:
+ add_to_val(orig)
+ self._dict[key] = val
+ continue
+
+ # The original looks like a dictionary, so update it
+ # based on what we think the value looks like.
+ # We can't just try adding the value because
+ # dictionaries don't have __add__() methods, and
+ # things like UserList will incorrectly coerce the
+ # original dict to a list (which we don't want).
+ if is_List(val):
+ for v in val:
+ orig[v] = None
+ else:
+ try:
+ update_dict(val)
+ except (AttributeError, TypeError, ValueError):
+ if is_Dict(val):
+ for k, v in val.items():
+ orig[k] = v
+ else:
+ orig[val] = None
+
self.scanner_map_delete(kw)
def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep,
@@ -1780,8 +1782,7 @@ class Base(SubstitutionEnvironment):
val = _delete_duplicates(val, not delete_existing)
if key not in self._dict or self._dict[key] in ('', None):
self._dict[key] = val
- elif is_Dict(self._dict[key]) and \
- is_Dict(val):
+ elif is_Dict(self._dict[key]) and is_Dict(val):
self._dict[key].update(val)
elif is_List(val):
dk = self._dict[key]
@@ -1992,11 +1993,17 @@ class Base(SubstitutionEnvironment):
return SCons.Builder.Builder(**nkw)
def CacheDir(self, path):
- import SCons.CacheDir
if path is not None:
path = self.subst(path)
self._CacheDir_path = path
+ if SCons.Action.execute_actions:
+ # Only initialize the CacheDir if -n/-no_exec was NOT specified.
+ # Now initialized the CacheDir and prevent a race condition which can
+ # happen when there's no existing cache dir and you are building with
+ # multiple threads, but initializing it before the task walk starts
+ self.get_CacheDir()
+
def Clean(self, targets, files):
global CleanTargets
tlist = self.arg2nodes(targets, self.fs.Entry)
@@ -2247,15 +2254,21 @@ class Base(SubstitutionEnvironment):
side_effects = self.arg2nodes(side_effect, self.fs.Entry)
targets = self.arg2nodes(target, self.fs.Entry)
+ added_side_effects = []
for side_effect in side_effects:
if side_effect.multiple_side_effect_has_builder():
raise UserError("Multiple ways to build the same target were specified for: %s" % str(side_effect))
side_effect.add_source(targets)
side_effect.side_effect = 1
self.Precious(side_effect)
+ added = False
for target in targets:
- target.side_effects.append(side_effect)
- return side_effects
+ if side_effect not in target.side_effects:
+ target.side_effects.append(side_effect)
+ added = True
+ if added:
+ added_side_effects.append(side_effect)
+ return added_side_effects
def Split(self, arg):
"""This function converts a string or list into a list of strings