summaryrefslogtreecommitdiff
path: root/SCons/Environment.py
diff options
context:
space:
mode:
Diffstat (limited to 'SCons/Environment.py')
-rw-r--r--SCons/Environment.py488
1 files changed, 305 insertions, 183 deletions
diff --git a/SCons/Environment.py b/SCons/Environment.py
index 7212c89ea..b074af77d 100644
--- a/SCons/Environment.py
+++ b/SCons/Environment.py
@@ -35,7 +35,7 @@ import os
import sys
import re
import shlex
-from collections import UserDict
+from collections import UserDict, deque
import SCons.Action
import SCons.Builder
@@ -65,6 +65,7 @@ from SCons.Util import (
flatten,
is_Dict,
is_List,
+ is_Scalar,
is_Sequence,
is_String,
is_Tuple,
@@ -86,7 +87,7 @@ _warn_target_signatures_deprecated = True
CleanTargets = {}
CalculatorArgs = {}
-def alias_builder(env, target, source):
+def alias_builder(env, target, source) -> None:
pass
AliasBuilder = SCons.Builder.Builder(
@@ -98,7 +99,7 @@ AliasBuilder = SCons.Builder.Builder(
name='AliasBuilder',
)
-def apply_tools(env, tools, toolpath):
+def apply_tools(env, tools, toolpath) -> None:
# Store the toolpath in the Environment.
# This is expected to work even if no tools are given, so do this first.
if toolpath is not None:
@@ -144,11 +145,11 @@ def copy_non_reserved_keywords(dict):
del result[k]
return result
-def _set_reserved(env, key, value):
+def _set_reserved(env, key, value) -> None:
msg = "Ignoring attempt to set reserved variable `$%s'"
SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg % key)
-def _set_future_reserved(env, key, value):
+def _set_future_reserved(env, key, value) -> None:
env._dict[key] = value
msg = "`$%s' will be reserved in a future release and setting it will become ignored"
SCons.Warnings.warn(SCons.Warnings.FutureReservedVariableWarning, msg % key)
@@ -166,11 +167,11 @@ def _set_BUILDERS(env, key, value):
raise UserError('%s is not a Builder.' % repr(v))
bd.update(value)
-def _del_SCANNERS(env, key):
+def _del_SCANNERS(env, key) -> None:
del env._dict[key]
env.scanner_map_delete()
-def _set_SCANNERS(env, key, value):
+def _set_SCANNERS(env, key, value) -> None:
env._dict[key] = value
env.scanner_map_delete()
@@ -193,6 +194,206 @@ def _delete_duplicates(l, keep_last):
return result
+def _add_cppdefines(
+ env_dict: dict,
+ val, # add annotation?
+ prepend: bool = False,
+ unique: bool = False,
+ delete_existing: bool = False,
+) -> None:
+ """Adds to ``CPPDEFINES``, using the rules for C preprocessor macros.
+
+ This is split out from regular construction variable addition because
+ these entries can express either a macro with a replacement value or
+ one without. A macro with replacement value can be supplied as *val*
+ in three ways: as a combined string ``"name=value"``; as a tuple
+ ``(name, value)``, or as an entry in a dictionary ``{"name": value}``.
+ A list argument with multiple macros can also be given.
+
+ Additions can be unconditional (duplicates allowed) or uniquing (no dupes).
+
+ Note if a replacement value is supplied, *unique* requires a full
+ match to decide uniqueness - both the macro name and the replacement.
+ The inner :func:`_is_in` is used to figure that out.
+
+ Args:
+ env_dict: the dictionary containing the ``CPPDEFINES`` to be modified.
+ val: the value to add, can be string, sequence or dict
+ prepend: whether to put *val* in front or back.
+ unique: whether to add *val* if it already exists.
+ delete_existing: if *unique* is true, add *val* after removing previous.
+
+ .. versionadded:: 4.5.0
+ """
+
+ def _add_define(item, defines: deque, prepend: bool = False) -> None:
+ """Convenience function to prepend/append a single value.
+
+ Sole purpose is to shorten code in the outer function.
+ """
+ if prepend:
+ defines.appendleft(item)
+ else:
+ defines.append(item)
+
+
+ def _is_in(item, defines: deque):
+ """Returns match for *item* if found in *defines*.
+
+ Accounts for type differences: tuple ("FOO", "BAR"), list
+ ["FOO", "BAR"], string "FOO=BAR" and dict {"FOO": "BAR"} all
+ differ as far as Python equality comparison is concerned, but
+ are the same for purposes of creating the preprocessor macro.
+ Also an unvalued string should match something like ``("FOO", None)``.
+ Since the caller may wish to remove a matched entry, we need to
+ return it - cannot remove *item* itself unless it happened to
+ be an exact (type) match.
+
+ Called from a place we know *defines* is always a deque, and
+ *item* will not be a dict, so don't need to do much type checking.
+ If this ends up used more generally, would need to adjust that.
+
+ Note implied assumption that members of a list-valued define
+ will not be dicts - we cannot actually guarantee this, since
+ if the initial add is a list its contents are not converted.
+ """
+ def _macro_conv(v) -> list:
+ """Normalizes a macro to a list for comparisons."""
+ if is_Tuple(v):
+ return list(v)
+ elif is_String(v):
+ rv = v.split("=")
+ if len(rv) == 1:
+ return [v, None]
+ return rv
+ return v
+
+ if item in defines: # cheap check first
+ return item
+
+ item = _macro_conv(item)
+ for define in defines:
+ if item == _macro_conv(define):
+ return define
+
+ return False
+
+ key = 'CPPDEFINES'
+ try:
+ defines = env_dict[key]
+ except KeyError:
+ # This is a new entry, just save it as is. Defer conversion to
+ # preferred type until someone tries to amend the value.
+ # processDefines has no problem with unconverted values if it
+ # gets called without any later additions.
+ if is_String(val):
+ env_dict[key] = val.split()
+ else:
+ env_dict[key] = val
+ return
+
+ # Convert type of existing to deque (if necessary) to simplify processing
+ # of additions - inserting at either end is cheap. Deferred conversion
+ # is also useful in case CPPDEFINES was set initially without calling
+ # through here (e.g. Environment kwarg, or direct assignment).
+ if isinstance(defines, deque):
+ # Already a deque? do nothing. Explicit check is so we don't get
+ # picked up by the is_list case below.
+ pass
+ elif is_String(defines):
+ env_dict[key] = deque(defines.split())
+ elif is_Tuple(defines):
+ if len(defines) > 2:
+ raise SCons.Errors.UserError(
+ f"Invalid tuple in CPPDEFINES: {defines!r}, must be a two-tuple"
+ )
+ env_dict[key] = deque([defines])
+ elif is_List(defines):
+ # a little extra work in case the initial container has dict
+ # item(s) inside it, so those can be matched by _is_in().
+ result = deque()
+ for define in defines:
+ if is_Dict(define):
+ result.extend(define.items())
+ else:
+ result.append(define)
+ env_dict[key] = result
+ elif is_Dict(defines):
+ env_dict[key] = deque(defines.items())
+ else:
+ env_dict[key] = deque(defines)
+ defines = env_dict[key] # in case we reassigned due to conversion
+
+ # now actually do the addition.
+ if is_Dict(val):
+ # Unpack the dict while applying to existing
+ for item in val.items():
+ if unique:
+ match = _is_in(item, defines)
+ if match and delete_existing:
+ defines.remove(match)
+ _add_define(item, defines, prepend)
+ elif not match:
+ _add_define(item, defines, prepend)
+ else:
+ _add_define(item, defines, prepend)
+
+ elif is_String(val):
+ for v in val.split():
+ if unique:
+ match = _is_in(v, defines)
+ if match and delete_existing:
+ defines.remove(match)
+ _add_define(v, defines, prepend)
+ elif not match:
+ _add_define(v, defines, prepend)
+ else:
+ _add_define(v, defines, prepend)
+
+ # A tuple appended to anything should yield -Dkey=value
+ elif is_Tuple(val):
+ if len(val) > 2:
+ raise SCons.Errors.UserError(
+ f"Invalid tuple added to CPPDEFINES: {val!r}, "
+ "must be a two-tuple"
+ )
+ if len(val) == 1:
+ val = (val[0], None) # normalize
+ if not is_Scalar(val[0]) or not is_Scalar(val[1]):
+ raise SCons.Errors.UserError(
+ f"Invalid tuple added to CPPDEFINES: {val!r}, "
+ "values must be scalar"
+ )
+ if unique:
+ match = _is_in(val, defines)
+ if match and delete_existing:
+ defines.remove(match)
+ _add_define(val, defines, prepend)
+ elif not match:
+ _add_define(val, defines, prepend)
+ else:
+ _add_define(val, defines, prepend)
+
+ elif is_List(val):
+ tmp = []
+ for item in val:
+ if unique:
+ match = _is_in(item, defines)
+ if match and delete_existing:
+ defines.remove(match)
+ tmp.append(item)
+ elif not match:
+ tmp.append(item)
+ else:
+ tmp.append(item)
+
+ if prepend:
+ defines.extendleft(tmp)
+ else:
+ defines.extend(tmp)
+
+ # else: # are there any other cases? processDefines doesn't think so.
+
# The following is partly based on code in a comment added by Peter
# Shannon at the following page (there called the "transplant" class):
@@ -237,10 +438,10 @@ class BuilderWrapper(MethodWrapper):
source = [source]
return super().__call__(target, source, *args, **kw)
- def __repr__(self):
+ def __repr__(self) -> str:
return '<BuilderWrapper %s>' % repr(self.name)
- def __str__(self):
+ def __str__(self) -> str:
return self.__repr__()
def __getattr__(self, name):
@@ -251,7 +452,7 @@ class BuilderWrapper(MethodWrapper):
else:
raise AttributeError(name)
- def __setattr__(self, name, value):
+ def __setattr__(self, name, value) -> None:
if name == 'env':
self.object = value
elif name == 'builder':
@@ -275,7 +476,7 @@ class BuilderDict(UserDict):
the Builders. We need to do this because every time someone changes
the Builders in the Environment's BUILDERS dictionary, we must
update the Environment's attributes."""
- def __init__(self, mapping, env):
+ def __init__(self, mapping, env) -> None:
# Set self.env before calling the superclass initialization,
# because it will end up calling our other methods, which will
# need to point the values in this dictionary to self.env.
@@ -287,7 +488,7 @@ class BuilderDict(UserDict):
# just copying would modify the original builder
raise TypeError( 'cannot semi_deepcopy a BuilderDict' )
- def __setitem__(self, item, val):
+ def __setitem__(self, item, val) -> None:
try:
method = getattr(self.env, item).method
except AttributeError:
@@ -297,11 +498,11 @@ class BuilderDict(UserDict):
super().__setitem__(item, val)
BuilderWrapper(self.env, val, item)
- def __delitem__(self, item):
+ def __delitem__(self, item) -> None:
super().__delitem__(item)
delattr(self.env, item)
- def update(self, mapping):
+ def update(self, mapping) -> None:
for i, v in mapping.items():
self.__setitem__(i, v)
@@ -343,7 +544,7 @@ class SubstitutionEnvironment:
class actually becomes useful.)
"""
- def __init__(self, **kw):
+ def __init__(self, **kw) -> None:
"""Initialization of an underlying SubstitutionEnvironment class.
"""
if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.SubstitutionEnvironment')
@@ -355,7 +556,7 @@ class SubstitutionEnvironment:
self.added_methods = []
#self._memo = {}
- def _init_special(self):
+ def _init_special(self) -> None:
"""Initial the dispatch tables for special handling of
special construction variables."""
self._special_del = {}
@@ -376,7 +577,7 @@ class SubstitutionEnvironment:
def __eq__(self, other):
return self._dict == other._dict
- def __delitem__(self, key):
+ def __delitem__(self, key) -> None:
special = self._special_del.get(key)
if special:
special(self, key)
@@ -413,7 +614,7 @@ class SubstitutionEnvironment:
"""Emulates the get() method of dictionaries."""
return self._dict.get(key, default)
- def __contains__(self, key):
+ def __contains__(self, key) -> bool:
return key in self._dict
def keys(self):
@@ -481,7 +682,7 @@ class SubstitutionEnvironment:
def lvars(self):
return {}
- def subst(self, string, raw=0, target=None, source=None, conv=None, executor=None, overrides=False):
+ def subst(self, string, raw: int=0, target=None, source=None, conv=None, executor=None, overrides: bool=False):
"""Recursively interpolates construction variables from the
Environment into the specified string, returning the expanded
result. Construction variables are specified by a $ prefix
@@ -498,7 +699,7 @@ class SubstitutionEnvironment:
lvars.update(executor.get_lvars())
return SCons.Subst.scons_subst(string, self, raw, target, source, gvars, lvars, conv, overrides=overrides)
- def subst_kw(self, kw, raw=0, target=None, source=None):
+ def subst_kw(self, kw, raw: int=0, target=None, source=None):
nkw = {}
for k, v in kw.items():
k = self.subst(k, raw, target, source)
@@ -507,7 +708,7 @@ class SubstitutionEnvironment:
nkw[k] = v
return nkw
- def subst_list(self, string, raw=0, target=None, source=None, conv=None, executor=None, overrides=False):
+ def subst_list(self, string, raw: int=0, target=None, source=None, conv=None, executor=None, overrides: bool=False):
"""Calls through to SCons.Subst.scons_subst_list(). See
the documentation for that function."""
gvars = self.gvars()
@@ -598,7 +799,7 @@ class SubstitutionEnvironment:
return out
- def AddMethod(self, function, name=None):
+ def AddMethod(self, function, name=None) -> None:
"""
Adds the specified function as a method of this construction
environment with the specified name. If the name is omitted,
@@ -607,7 +808,7 @@ class SubstitutionEnvironment:
method = MethodWrapper(self, function, name)
self.added_methods.append(method)
- def RemoveMethod(self, function):
+ def RemoveMethod(self, function) -> None:
"""
Removes the specified function's MethodWrapper from the
added_methods list, so we don't re-bind it when making a clone.
@@ -672,7 +873,7 @@ class SubstitutionEnvironment:
'RPATH' : [],
}
- def do_parse(arg):
+ def do_parse(arg) -> None:
# if arg is a sequence, recurse with each element
if not arg:
return
@@ -686,7 +887,7 @@ class SubstitutionEnvironment:
arg = self.backtick(arg[1:])
# utility function to deal with -D option
- def append_define(name, mapping=mapping):
+ def append_define(name, mapping=mapping) -> None:
t = name.split('=')
if len(t) == 1:
mapping['CPPDEFINES'].append(name)
@@ -834,14 +1035,20 @@ class SubstitutionEnvironment:
do_parse(arg)
return mapping
- def MergeFlags(self, args, unique=True) -> None:
+ def MergeFlags(self, args, unique: bool=True) -> None:
"""Merge flags into construction variables.
- Merges the flags from ``args`` into this construction environent.
- If ``args`` is not a dict, it is first converted to one with
+ Merges the flags from *args* into this construction environent.
+ If *args* is not a dict, it is first converted to one with
flags distributed into appropriate construction variables.
See :meth:`ParseFlags`.
+ As a side effect, if *unique* is true, a new object is created
+ for each modified construction variable by the loop at the end.
+ This is silently expected by the :meth:`Override` *parse_flags*
+ functionality, which does not want to share the list (or whatever)
+ with the environment being overridden.
+
Args:
args: flags to merge
unique: merge flags rather than appending (default: True).
@@ -876,6 +1083,16 @@ class SubstitutionEnvironment:
try:
orig = orig + value
except (KeyError, TypeError):
+ # If CPPDEFINES is a deque, adding value (a list)
+ # results in TypeError, so we handle that case here.
+ # Just in case we got called from Override, make
+ # sure we make a copy, because we don't go through
+ # the cleanup loops at the end of the outer for loop,
+ # which implicitly gives us a new object.
+ if isinstance(orig, deque):
+ self[key] = self[key].copy()
+ self.AppendUnique(CPPDEFINES=value, delete_existing=True)
+ continue
try:
add_to_orig = orig.append
except AttributeError:
@@ -894,6 +1111,7 @@ class SubstitutionEnvironment:
for v in orig[::-1]:
if v not in t:
t.insert(0, v)
+
self[key] = t
@@ -948,7 +1166,7 @@ class Base(SubstitutionEnvironment):
variables=None,
parse_flags=None,
**kw
- ):
+ ) -> None:
"""Initialization of a basic SCons construction environment.
Sets up special construction variables like BUILDER,
@@ -1086,7 +1304,7 @@ class Base(SubstitutionEnvironment):
self._last_CacheDir = cd
return cd
- def get_factory(self, factory, default='File'):
+ def get_factory(self, factory, default: str='File'):
"""Return a factory function for creating Nodes for this
construction environment.
"""
@@ -1155,7 +1373,7 @@ class Base(SubstitutionEnvironment):
skey = skey.lower()
return self._gsm().get(skey)
- def scanner_map_delete(self, kw=None):
+ def scanner_map_delete(self, kw=None) -> None:
"""Delete the cached scanner map (if we need to).
"""
try:
@@ -1163,14 +1381,14 @@ class Base(SubstitutionEnvironment):
except KeyError:
pass
- def _update(self, other):
+ def _update(self, other) -> None:
"""Private method to update an environment's consvar dict directly.
Bypasses the normal checks that occur when users try to set items.
"""
self._dict.update(other)
- def _update_onlynew(self, other):
+ def _update_onlynew(self, other) -> None:
"""Private method to add new items to an environment's consvar dict.
Only adds items from `other` whose keys do not already appear in
@@ -1207,7 +1425,7 @@ class Base(SubstitutionEnvironment):
# an Environment's construction variables.
#######################################################################
- def Append(self, **kw):
+ def Append(self, **kw) -> None:
"""Append values to construction variables in an Environment.
The variable is created if it is not already present.
@@ -1215,16 +1433,15 @@ class Base(SubstitutionEnvironment):
kw = copy_non_reserved_keywords(kw)
for key, val in kw.items():
+ if key == 'CPPDEFINES':
+ _add_cppdefines(self._dict, val)
+ continue
+
try:
- if key == 'CPPDEFINES' and is_String(self._dict[key]):
- self._dict[key] = [self._dict[key]]
orig = self._dict[key]
except KeyError:
# 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
+ self._dict[key] = val
continue
try:
@@ -1263,19 +1480,8 @@ class Base(SubstitutionEnvironment):
# 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:
- 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)
@@ -1299,8 +1505,8 @@ class Base(SubstitutionEnvironment):
path = str(self.fs.Dir(path))
return path
- def AppendENVPath(self, name, newpath, envname='ENV',
- sep=os.pathsep, delete_existing=False):
+ def AppendENVPath(self, name, newpath, envname: str='ENV',
+ sep=os.pathsep, delete_existing: bool=False) -> None:
"""Append path elements to the path *name* in the *envname*
dictionary for this environment. Will only add any particular
path once, and will normpath and normcase all paths to help
@@ -1322,7 +1528,7 @@ class Base(SubstitutionEnvironment):
self._dict[envname][name] = nv
- def AppendUnique(self, delete_existing=False, **kw):
+ def AppendUnique(self, delete_existing: bool=False, **kw) -> None:
"""Append values to existing construction variables
in an Environment, if they're not already there.
If delete_existing is True, removes existing values first, so
@@ -1330,6 +1536,9 @@ class Base(SubstitutionEnvironment):
"""
kw = copy_non_reserved_keywords(kw)
for key, val in kw.items():
+ if key == 'CPPDEFINES':
+ _add_cppdefines(self._dict, val, unique=True, delete_existing=delete_existing)
+ continue
if is_List(val):
val = _delete_duplicates(val, delete_existing)
if key not in self._dict or self._dict[key] in ('', None):
@@ -1338,46 +1547,8 @@ class Base(SubstitutionEnvironment):
self._dict[key].update(val)
elif is_List(val):
dk = self._dict[key]
- if key == 'CPPDEFINES':
- tmp = []
- for i in val:
- if is_List(i):
- if len(i) >= 2:
- tmp.append((i[0], i[1]))
- else:
- tmp.append((i[0],))
- elif is_Tuple(i):
- tmp.append(i)
- else:
- tmp.append((i,))
- val = tmp
- # Construct a list of (key, value) tuples.
- if is_Dict(dk):
- tmp = []
- for (k, v) in dk.items():
- if v is not None:
- tmp.append((k, v))
- else:
- tmp.append((k,))
- dk = tmp
- elif is_String(dk):
- dk = [(dk,)]
- else:
- tmp = []
- for i in dk:
- if is_List(i):
- if len(i) >= 2:
- tmp.append((i[0], i[1]))
- else:
- tmp.append((i[0],))
- elif is_Tuple(i):
- tmp.append(i)
- else:
- tmp.append((i,))
- dk = tmp
- else:
- if not is_List(dk):
- dk = [dk]
+ if not is_List(dk):
+ dk = [dk]
if delete_existing:
dk = [x for x in dk if x not in val]
else:
@@ -1386,70 +1557,15 @@ class Base(SubstitutionEnvironment):
else:
dk = self._dict[key]
if is_List(dk):
- if key == 'CPPDEFINES':
- tmp = []
- for i in dk:
- if is_List(i):
- if len(i) >= 2:
- tmp.append((i[0], i[1]))
- else:
- tmp.append((i[0],))
- elif is_Tuple(i):
- tmp.append(i)
- else:
- tmp.append((i,))
- dk = tmp
- # Construct a list of (key, value) tuples.
- if is_Dict(val):
- tmp = []
- for (k, v) in val.items():
- if v is not None:
- tmp.append((k, v))
- else:
- tmp.append((k,))
- val = tmp
- elif is_String(val):
- val = [(val,)]
- if delete_existing:
- dk = list(filter(lambda x, val=val: x not in val, dk))
- self._dict[key] = dk + val
- else:
- dk = [x for x in dk if x not in val]
- self._dict[key] = dk + val
+ # By elimination, val is not a list. Since dk is a
+ # list, wrap val in a list first.
+ if delete_existing:
+ dk = list(filter(lambda x, val=val: x not in val, dk))
+ self._dict[key] = dk + [val]
else:
- # By elimination, val is not a list. Since dk is a
- # list, wrap val in a list first.
- if delete_existing:
- dk = list(filter(lambda x, val=val: x not in val, dk))
+ if val not in dk:
self._dict[key] = dk + [val]
- else:
- if val not in dk:
- self._dict[key] = dk + [val]
else:
- if key == 'CPPDEFINES':
- if is_String(dk):
- dk = [dk]
- elif is_Dict(dk):
- tmp = []
- for (k, v) in dk.items():
- if v is not None:
- tmp.append((k, v))
- else:
- tmp.append((k,))
- dk = tmp
- if is_String(val):
- if val in dk:
- val = []
- else:
- val = [val]
- elif is_Dict(val):
- tmp = []
- for i,j in val.items():
- if j is not None:
- tmp.append((i,j))
- else:
- tmp.append(i)
- val = tmp
if delete_existing:
dk = [x for x in dk if x not in val]
self._dict[key] = dk + val
@@ -1588,7 +1704,7 @@ class Base(SubstitutionEnvironment):
return dlist
- def Dump(self, key=None, format='pretty'):
+ def Dump(self, key=None, format: str='pretty'):
""" Return construction variables serialized to a string.
Args:
@@ -1648,7 +1764,7 @@ class Base(SubstitutionEnvironment):
return path
- def ParseConfig(self, command, function=None, unique=True):
+ def ParseConfig(self, command, function=None, unique: bool=True):
"""Parse the result of running a command to update construction vars.
Use ``function`` to parse the output of running ``command``
@@ -1674,7 +1790,7 @@ class Base(SubstitutionEnvironment):
return function(self, self.backtick(command), unique)
- def ParseDepends(self, filename, must_exist=None, only_one=False):
+ def ParseDepends(self, filename, must_exist=None, only_one: bool=False):
"""
Parse a mkdep-style file for explicit dependencies. This is
completely abusable, and should be unnecessary in the "normal"
@@ -1718,7 +1834,7 @@ class Base(SubstitutionEnvironment):
platform = self.subst(platform)
return SCons.Platform.Platform(platform)(self)
- def Prepend(self, **kw):
+ def Prepend(self, **kw) -> None:
"""Prepend values to construction variables in an Environment.
The variable is created if it is not already present.
@@ -1726,6 +1842,9 @@ class Base(SubstitutionEnvironment):
kw = copy_non_reserved_keywords(kw)
for key, val in kw.items():
+ if key == 'CPPDEFINES':
+ _add_cppdefines(self._dict, val, prepend=True)
+ continue
try:
orig = self._dict[key]
except KeyError:
@@ -1783,8 +1902,8 @@ class Base(SubstitutionEnvironment):
self.scanner_map_delete(kw)
- def PrependENVPath(self, name, newpath, envname='ENV',
- sep=os.pathsep, delete_existing=True):
+ def PrependENVPath(self, name, newpath, envname: str='ENV',
+ sep=os.pathsep, delete_existing: bool=True) -> None:
"""Prepend path elements to the path *name* in the *envname*
dictionary for this environment. Will only add any particular
path once, and will normpath and normcase all paths to help
@@ -1807,7 +1926,7 @@ class Base(SubstitutionEnvironment):
self._dict[envname][name] = nv
- def PrependUnique(self, delete_existing=False, **kw):
+ def PrependUnique(self, delete_existing: bool=False, **kw) -> None:
"""Prepend values to existing construction variables
in an Environment, if they're not already there.
If delete_existing is True, removes existing values first, so
@@ -1815,6 +1934,9 @@ class Base(SubstitutionEnvironment):
"""
kw = copy_non_reserved_keywords(kw)
for key, val in kw.items():
+ if key == 'CPPDEFINES':
+ _add_cppdefines(self._dict, val, unique=True, prepend=True, delete_existing=delete_existing)
+ continue
if is_List(val):
val = _delete_duplicates(val, not delete_existing)
if key not in self._dict or self._dict[key] in ('', None):
@@ -1847,7 +1969,7 @@ class Base(SubstitutionEnvironment):
self._dict[key] = val + dk
self.scanner_map_delete(kw)
- def Replace(self, **kw):
+ def Replace(self, **kw) -> None:
"""Replace existing construction variables in an Environment
with new construction variables and/or values.
"""
@@ -1887,7 +2009,7 @@ class Base(SubstitutionEnvironment):
name = name[:-len(old_suffix)]
return os.path.join(dir, new_prefix+name+new_suffix)
- def SetDefault(self, **kw):
+ def SetDefault(self, **kw) -> None:
for k in list(kw.keys()):
if k in self._dict:
del kw[k]
@@ -2037,7 +2159,7 @@ class Base(SubstitutionEnvironment):
nkw = self.subst_kw(kw)
return SCons.Builder.Builder(**nkw)
- def CacheDir(self, path, custom_class=None):
+ def CacheDir(self, path, custom_class=None) -> None:
if path is not None:
path = self.subst(path)
self._CacheDir_path = path
@@ -2052,7 +2174,7 @@ class Base(SubstitutionEnvironment):
# multiple threads, but initializing it before the task walk starts
self.get_CacheDir()
- def Clean(self, targets, files):
+ def Clean(self, targets, files) -> None:
global CleanTargets
tlist = self.arg2nodes(targets, self.fs.Entry)
flist = self.arg2nodes(files, self.fs.Entry)
@@ -2219,7 +2341,7 @@ class Base(SubstitutionEnvironment):
else:
return result[0]
- def Glob(self, pattern, ondisk=True, source=False, strings=False, exclude=None):
+ def Glob(self, pattern, ondisk: bool=True, source: bool=False, strings: bool=False, exclude=None):
return self.fs.Glob(self.subst(pattern), ondisk, source, strings, exclude)
def Ignore(self, target, dependency):
@@ -2261,7 +2383,7 @@ class Base(SubstitutionEnvironment):
t.set_pseudo()
return tlist
- def Repository(self, *dirs, **kw):
+ def Repository(self, *dirs, **kw) -> None:
dirs = self.arg2nodes(list(dirs), self.fs.Dir)
self.fs.Repository(*dirs, **kw)
@@ -2284,7 +2406,7 @@ class Base(SubstitutionEnvironment):
nkw = self.subst_kw(kw)
return SCons.Scanner.ScannerBase(*nargs, **nkw)
- def SConsignFile(self, name=SCons.SConsign.current_sconsign_filename(), dbm_module=None):
+ def SConsignFile(self, name=SCons.SConsign.current_sconsign_filename(), dbm_module=None) -> None:
if name is not None:
name = self.subst(name)
if not os.path.isabs(name):
@@ -2347,17 +2469,17 @@ class Base(SubstitutionEnvironment):
"""
return SCons.Node.Python.ValueWithMemo(value, built_value, name)
- def VariantDir(self, variant_dir, src_dir, duplicate=1):
+ def VariantDir(self, variant_dir, src_dir, duplicate: int=1) -> None:
variant_dir = self.arg2nodes(variant_dir, self.fs.Dir)[0]
src_dir = self.arg2nodes(src_dir, self.fs.Dir)[0]
self.fs.VariantDir(variant_dir, src_dir, duplicate)
- def FindSourceFiles(self, node='.') -> list:
+ def FindSourceFiles(self, node: str='.') -> list:
"""Return a list of all source files."""
node = self.arg2nodes(node, self.fs.Entry)[0]
sources = []
- def build_source(ss):
+ def build_source(ss) -> None:
for s in ss:
if isinstance(s, SCons.Node.FS.Dir):
build_source(s.all_children())
@@ -2405,7 +2527,7 @@ class OverrideEnvironment(Base):
values from the overrides dictionary.
"""
- def __init__(self, subject, overrides=None):
+ def __init__(self, subject, overrides=None) -> None:
if SCons.Debug.track_instances: logInstanceCreation(self, 'Environment.OverrideEnvironment')
self.__dict__['__subject'] = subject
if overrides is None:
@@ -2429,7 +2551,7 @@ class OverrideEnvironment(Base):
else:
return attr
- def __setattr__(self, name, value):
+ def __setattr__(self, name, value) -> None:
setattr(self.__dict__['__subject'], name, value)
# Methods that make this class act like a dictionary.
@@ -2466,7 +2588,7 @@ class OverrideEnvironment(Base):
except KeyError:
return self.__dict__['__subject'].get(key, default)
- def __contains__(self, key):
+ def __contains__(self, key) -> bool:
if key in self.__dict__['overrides']:
return True
return key in self.__dict__['__subject']
@@ -2502,10 +2624,10 @@ class OverrideEnvironment(Base):
return default
# Overridden private construction environment methods.
- def _update(self, other):
+ def _update(self, other) -> None:
self.__dict__['overrides'].update(other)
- def _update_onlynew(self, other):
+ def _update_onlynew(self, other) -> None:
"""Update a dict with new keys.
Unlike the .update method, if the key is already present,
@@ -2524,7 +2646,7 @@ class OverrideEnvironment(Base):
return lvars
# Overridden public construction environment methods.
- def Replace(self, **kw):
+ def Replace(self, **kw) -> None:
kw = copy_non_reserved_keywords(kw)
self.__dict__['overrides'].update(semi_deepcopy(kw))
@@ -2553,7 +2675,7 @@ def NoSubstitutionProxy(subject):
might have assigned to SCons.Environment.Environment.
"""
class _NoSubstitutionProxy(Environment):
- def __init__(self, subject):
+ def __init__(self, subject) -> None:
self.__dict__['__subject'] = subject
def __getattr__(self, name):
@@ -2562,14 +2684,14 @@ def NoSubstitutionProxy(subject):
def __setattr__(self, name, value):
return setattr(self.__dict__['__subject'], name, value)
- def executor_to_lvars(self, kwdict):
+ def executor_to_lvars(self, kwdict) -> None:
if 'executor' in kwdict:
kwdict['lvars'] = kwdict['executor'].get_lvars()
del kwdict['executor']
else:
kwdict['lvars'] = {}
- def raw_to_mode(self, mapping):
+ def raw_to_mode(self, mapping) -> None:
try:
raw = mapping['raw']
except KeyError: