From 2b583646718acda52481b71f15c9a6723fb3eb81 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Tue, 8 Dec 2020 13:18:04 -0800 Subject: docstrings and minor code cleanup --- SCons/Environment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'SCons/Environment.py') diff --git a/SCons/Environment.py b/SCons/Environment.py index bb57e37c3..13eaf3c2b 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -1606,7 +1606,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 -- cgit v1.2.1 From 2d1bebd6f093bef2bae4d89d2063724a4ca3e102 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Fri, 1 Jan 2021 15:32:58 -0700 Subject: Fix awkward consvar code from ancient Python The Append* and Prepend* environment methods which add to existing construction variables had some deeply nested try blocks because according to the comments, Python 1.5.2 would not allow a continue statement inside a try block. This has now been aligned to more modern usage for better readability. Signed-off-by: Mats Wichmann --- SCons/Environment.py | 248 ++++++++++++++++++++++++--------------------------- 1 file changed, 119 insertions(+), 129 deletions(-) (limited to 'SCons/Environment.py') diff --git a/SCons/Environment.py b/SCons/Environment.py index 4ebd5156b..2b9b294d0 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -407,9 +407,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): @@ -635,7 +634,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. @@ -1173,92 +1172,85 @@ 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 - self.scanner_map_delete(kw) + orig[val] = None - # 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 - path = str(path) - if path and path[0] == '#': - path = str(self.fs.Dir(path)) - return path + self.scanner_map_delete(kw) def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep, delete_existing=0): @@ -1295,8 +1287,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] @@ -1682,68 +1673,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, @@ -1782,8 +1773,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] -- cgit v1.2.1 From b00cfec0f5d7236bd1d2b4d5a50407152c32a739 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Mon, 4 Jan 2021 12:52:21 -0700 Subject: Add back accidentally removed env._canonicalize() Signed-off-by: Mats Wichmann --- SCons/Environment.py | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'SCons/Environment.py') diff --git a/SCons/Environment.py b/SCons/Environment.py index 2b9b294d0..5352b6e7e 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -1252,6 +1252,17 @@ class Base(SubstitutionEnvironment): self.scanner_map_delete(kw) + def _canonicalize(self, path): + """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)) + return path + def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep, delete_existing=0): """Append path elements to the path 'name' in the 'ENV' -- cgit v1.2.1 From ab166424306583f2ba2eb56f975a83b3cf9fd612 Mon Sep 17 00:00:00 2001 From: Adam Gross Date: Tue, 5 Jan 2021 15:49:00 -0500 Subject: Don't allow duplicate side effects to be added SCons disallows adding duplicate sources, but does not place any limits on adding duplicate side effects. This change adds code to not allow adding duplicate side effects. I considered mimicking Node.sources_set by adding Node.side_effects_set but it seemed unnecessary and would make it harder for Environment.SideEffect to only return the list of side effects that were actually added. --- SCons/Environment.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'SCons/Environment.py') diff --git a/SCons/Environment.py b/SCons/Environment.py index 4ebd5156b..0c1315cc2 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -2249,6 +2249,7 @@ 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)) @@ -2256,8 +2257,10 @@ class Base(SubstitutionEnvironment): side_effect.side_effect = 1 self.Precious(side_effect) 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_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 -- cgit v1.2.1 From 97d424e9d5094127a04382de9339cf4db3ab5e8e Mon Sep 17 00:00:00 2001 From: Adam Gross Date: Tue, 5 Jan 2021 16:39:19 -0500 Subject: Fix bug where SideEffect() was returning duplicate entries My code was adding the side effect to the return list inside of a "for target in targets" loop, causing duplicate entries if there were multiple targets. Fix this by adding outside of the loop. --- SCons/Environment.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'SCons/Environment.py') diff --git a/SCons/Environment.py b/SCons/Environment.py index 0c1315cc2..3b720c86e 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -2256,10 +2256,13 @@ class Base(SubstitutionEnvironment): side_effect.add_source(targets) side_effect.side_effect = 1 self.Precious(side_effect) + added = False for target in targets: if side_effect not in target.side_effects: target.side_effects.append(side_effect) - added_side_effects.append(side_effect) + added = True + if added: + added_side_effects.append(side_effect) return added_side_effects def Split(self, arg): -- cgit v1.2.1 From d3c6a4a199beff6e4d28725da9c0b0a052349359 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Tue, 12 Jan 2021 07:48:33 -0700 Subject: Work around Py3.10 optimizing out a builder test BuilderBase class traps __bool__ call and raises InternalError. On Py 3.10a the unit test for this got optimized out, avoid this. While we're at it, eliminate remaining references to __nonzero__, which was a Py2-ism, replaced by __bool__. Closes #3860 Signed-off-by: Mats Wichmann --- SCons/Environment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'SCons/Environment.py') diff --git a/SCons/Environment.py b/SCons/Environment.py index 0b8a20adc..61128af36 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -1538,7 +1538,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 -- cgit v1.2.1 From e66a758ad087334076fb098993b7ee67ebd4dc61 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Fri, 15 Jan 2021 18:12:46 -0800 Subject: New solution to issue described in PR 3114. This should resolve an issue when creating a new cachedir and building -j > 1 which can cause a race condition --- SCons/Environment.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'SCons/Environment.py') diff --git a/SCons/Environment.py b/SCons/Environment.py index 312530a81..89bfa76c2 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -2000,6 +2000,11 @@ class Base(SubstitutionEnvironment): path = self.subst(path) self._CacheDir_path = path + # 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) -- cgit v1.2.1 From ea7f260bead374ee572763093ad8268233f335fa Mon Sep 17 00:00:00 2001 From: William Deegan Date: Sat, 16 Jan 2021 13:59:06 -0800 Subject: Ensure that when user runs scons -n/--no_exec the CacheDir's config file is not created --- SCons/Environment.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'SCons/Environment.py') diff --git a/SCons/Environment.py b/SCons/Environment.py index 89bfa76c2..9e2870c04 100644 --- a/SCons/Environment.py +++ b/SCons/Environment.py @@ -1995,15 +1995,16 @@ 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 - # 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() + 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 -- cgit v1.2.1