summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMats Wichmann <mats@linux.com>2023-02-09 12:30:42 -0700
committerMats Wichmann <mats@linux.com>2023-02-09 12:41:07 -0700
commitb3e6192cfe79c3e4e162ed64a15ba200883f616f (patch)
tree9c98ac80d76a198b367bcbc75685b7b8f6a20dca
parent12d4966b67182a282e3911ad9b0e1dbe8f6a52d7 (diff)
downloadscons-git-b3e6192cfe79c3e4e162ed64a15ba200883f616f.tar.gz
Adjusted CPPDEFINES behavior for list and tuple
After the previous proposals, addition of a bare tuple is restored to the valued-macro behavior (this previously did not work consistently). Strings are now consistently split if they contain spaces, except if entered as a list member, in which case (as documented) they are left alone. tuples with nore than two members are now flagged as a UserError; previously the first two members were taken as name=value and any further members were silently ignored. More tests added. Signed-off-by: Mats Wichmann <mats@linux.com>
-rw-r--r--CHANGES.txt20
-rw-r--r--RELEASE.txt23
-rw-r--r--SCons/Defaults.py47
-rw-r--r--SCons/DefaultsTests.py7
-rw-r--r--SCons/Environment.py94
-rw-r--r--SCons/Environment.xml69
-rw-r--r--SCons/Util/types.py11
-rw-r--r--test/CPPDEFINES/append.py200
-rw-r--r--test/CPPDEFINES/fixture/SConstruct-Append23
-rw-r--r--test/CPPDEFINES/fixture/SConstruct-Prepend21
-rw-r--r--test/CPPDEFINES/prepend.py200
11 files changed, 404 insertions, 311 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 41a966b5c..e10feab6f 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -134,16 +134,18 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
or not if it is already in the $LIBS construction var in the
configure context. (issue #2768).
- Special-case handling for CPPDEFINES in the Append/Prepend routines
- split out into its own function to simplify the remaining code and
+ is split out into its own function to simplify the remaining code and
fix problems. The e2e test test/CPPDEFINES/append.py is expanded
- to cover missed cases, and AppendUnique no longer mismatches with
- what Append does (#3876). Inconsistent handling of tuples to specify
- macro=value outputs is also cleaned up (#4254). The special handling
- now also works for Prepend/PrependUnique, and a corresponding test
- test/CPPDEFINES/prepend.py was added to verify the behavior.
- SCons used to sort keys set or appended via a dict type, in order to
- assure order of commandline flags did not change across runs. This
- behavior has been dropped since Python now assures consistent dict order.
+ to cover missed cases, and AppendUnique no longer mismatches
+ with what Append does (#3876). Inconsistent handling of tuples
+ to specify macro=value outputs is also cleaned up (#4254). The
+ special handling now also works for Prepend/PrependUnique, and a
+ corresponding e2e test test/CPPDEFINES/prepend.py was added to verify
+ the behavior. A unit test for SCons.Util.processDefines, used to
+ convert CPPDEFINES into a list of strings, is added. SCons used
+ to sort keys set or appended via a dict type, in order to assure
+ order of commandline flags did not change across runs. This behavior
+ has been dropped since Python now assures consistent dict order.
RELEASE 4.4.0 - Sat, 30 Jul 2022 14:08:29 -0700
diff --git a/RELEASE.txt b/RELEASE.txt
index f06945d6d..7a431c221 100644
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -17,8 +17,10 @@ NOTE: If you build with Python 3.10.0 and then rebuild with 3.10.1 (or higher),
see unexpected rebuilds. This is due to Python internals changing which changed
the signature of a Python Action Function.
-NOTE: If you use dictionaries to specify your CPPDEFINES, most likely the order of the CPPDEFINES
- on the generated command line will change causing a rebuild.
+NOTE: If you use a dictionary to specify your CPPDEFINES, the order of
+ dictionary keys is now preserved when generating the command line.
+ Previously these were sorted alphabecially: this may cause a change
+ which leads to a rebuild.
NEW FUNCTIONALITY
@@ -98,15 +100,14 @@ FIXES
actual build would not see the file as modified. Leading to incorrect incremental builds.
Now configure checks now clear node info for non conftest nodes, so they will be re-evaluated for
the real taskmaster run when the build commences.
-- Inconsistent behavior of adding CPPDEFINES values via tuple arguments
- has been cleaned up (problems described in issue #4254). In order to
- achieve consistency, a rule for for adding macros-with-values via a
- tuple (or list) is now enforced: they need to be entered as members
- of a containing sequence. ["NAME", "VALUE"] and ("NAME", "VALUE")
- are now treated the same (two individual macro names), rather than
- the latter sometimes, but not always, being handled as a single
- NAME=VALUE macro. Use a construct like [("NAME", "VALUE")] to get the
- macro-with-value behavior.
+- Inconsistent behavior of adding values to the CPPDEFINES construction
+ variable has been cleaned up (described in issue #4254). Now a tuple,
+ whether provided by itself or as a member of a list, is consistently
+ interpreted as a macro with replacement value. When adding a list,
+ individual members are added in sequence without interpretation.
+ A string value containing spaces is split if it is the initial value or
+ added, but not if it is given as a member of an added list. Detection
+ of duplicate macros now works for both valued and unvalued forms.
- Handling of CPPDEFINES macros via Prepend and PrependUnique now works
(previously this was special-cased only for Append and AppendUnique).
diff --git a/SCons/Defaults.py b/SCons/Defaults.py
index 250ccf617..ea7e9308f 100644
--- a/SCons/Defaults.py
+++ b/SCons/Defaults.py
@@ -36,6 +36,7 @@ import shutil
import stat
import sys
import time
+from typing import List
import SCons.Action
import SCons.Builder
@@ -46,7 +47,7 @@ import SCons.PathList
import SCons.Scanner.Dir
import SCons.Subst
import SCons.Tool
-from SCons.Util import is_List, is_String, is_Sequence, is_Dict, flatten
+from SCons.Util import is_List, is_String, is_Sequence, is_Tuple, is_Dict, flatten
# A placeholder for a default Environment (for fetching source files
# from source code management systems and the like). This must be
@@ -510,42 +511,67 @@ def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
return c(prefix, stripped, suffix, env)
-def processDefines(defs):
+def processDefines(defs) -> List[str]:
"""Return list of strings for preprocessor defines from *defs*.
- Resolves all the different forms CPPDEFINES can be assembled in.
+ Resolves the different forms ``CPPDEFINES`` can be assembled in:
+ if the Append/Prepend routines are used beyond a initial setting it
+ will be a deque, but if written to only once (Environment initializer,
+ or direct write) it can be a multitude of types.
+
Any prefix/suffix is handled elsewhere (usually :func:`_concat_ixes`).
"""
dlist = []
- if is_Sequence(defs):
+ if is_List(defs):
for define in defs:
if define is None:
continue
elif is_Sequence(define):
- if len(define) >= 2 and define[1] is not None:
- # TODO: do we need to quote define[1] if it contains space?
- dlist.append(str(define[0]) + '=' + str(define[1]))
+ if len(define) > 2:
+ raise SCons.Errors.UserError(
+ f"Invalid tuple in CPPDEFINES: {define!r}, "
+ "must be a two-tuple"
+ )
+ name, *value = define
+ if value and value[0] is not None:
+ # TODO: do we need to quote value if it contains space?
+ dlist.append(f"{name}={value[0]}")
else:
dlist.append(str(define[0]))
elif is_Dict(define):
for macro, value in define.items():
if value is not None:
# TODO: do we need to quote value if it contains space?
- dlist.append(str(macro) + '=' + str(value))
+ dlist.append(f"{macro}={value}")
else:
dlist.append(str(macro))
elif is_String(define):
dlist.append(str(define))
else:
raise SCons.Errors.UserError(
- f"DEFINE {define!r} is not a list, dict, string or None."
+ f"CPPDEFINES entry {define!r} is not a tuple, list, "
+ "dict, string or None."
)
+ elif is_Tuple(defs):
+ if len(defs) > 2:
+ raise SCons.Errors.UserError(
+ f"Invalid tuple in CPPDEFINES: {defs!r}, "
+ "must be a two-tuple"
+ )
+ name, *value = defs
+ if value and value[0] is not None:
+ # TODO: do we need to quote value if it contains space?
+ dlist.append(f"{name}={value[0]}")
+ else:
+ dlist.append(str(define[0]))
elif is_Dict(defs):
for macro, value in defs.items():
if value is None:
dlist.append(str(macro))
else:
- dlist.append(str(macro) + '=' + str(value))
+ dlist.append(f"{macro}={value}")
+ elif is_String(defs):
+ return defs.split()
else:
dlist.append(str(defs))
@@ -556,7 +582,6 @@ def _defines(prefix, defs, suffix, env, target=None, source=None, c=_concat_ixes
"""A wrapper around :func:`_concat_ixes` that turns a list or string
into a list of C preprocessor command-line definitions.
"""
-
return c(prefix, env.subst_list(processDefines(defs), target=target, source=source), suffix, env)
diff --git a/SCons/DefaultsTests.py b/SCons/DefaultsTests.py
index b876552ca..c9a666311 100644
--- a/SCons/DefaultsTests.py
+++ b/SCons/DefaultsTests.py
@@ -120,6 +120,11 @@ class DefaultsTestCase(unittest.TestCase):
self.assertEqual(rv, ['name=val'])
with self.subTest():
+ # space-separated macros
+ rv = processDefines('name1 name2=val2')
+ self.assertEqual(rv, ['name1', 'name2=val2'])
+
+ with self.subTest():
# single list
rv = processDefines(['name', 'val'])
self.assertEqual(rv, ['name', 'val'])
@@ -127,7 +132,7 @@ class DefaultsTestCase(unittest.TestCase):
with self.subTest():
# single tuple
rv = processDefines(('name', 'val'))
- self.assertEqual(rv, ['name', 'val'])
+ self.assertEqual(rv, ['name=val'])
with self.subTest():
# single dict
diff --git a/SCons/Environment.py b/SCons/Environment.py
index 26f7036fb..3bd1a6204 100644
--- a/SCons/Environment.py
+++ b/SCons/Environment.py
@@ -65,6 +65,7 @@ from SCons.Util import (
flatten,
is_Dict,
is_List,
+ is_Scalar,
is_Sequence,
is_String,
is_Tuple,
@@ -202,16 +203,18 @@ def _add_cppdefines(
) -> None:
"""Adds to CPPDEFINES, using the rules for C preprocessor macros.
- Split out from regular construction variable handling because these
- entries can express either a macro with a replacement list or one
- without. A macro with replacement list can be supplied three ways:
- as a combined string ``name=value``; as a tuple contained in
- a sequence type ``[("name", value)]``; or as a dictionary entry
- ``{"name": value}``. Appending/prepending can be unconditional
- (duplicates allowed) or uniquing (no dupes).
+ 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.
- Note if a replacement list is supplied, "unique" requires a full
- match - both the name and the replacement must be equal.
+ 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.
@@ -239,12 +242,13 @@ def _add_cppdefines(
["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 do much type checking.
+ *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
@@ -256,7 +260,10 @@ def _add_cppdefines(
if is_Tuple(v):
return list(v)
elif is_String(v):
- return v.split("=")
+ rv = v.split("=")
+ if len(rv) == 1:
+ return [v, None]
+ return rv
return v
if item in defines: # cheap check first
@@ -274,22 +281,32 @@ def _add_cppdefines(
defines = env_dict[key]
except KeyError:
# This is a new entry, just save it as is. Defer conversion to
- # deque until someone tries to amend the value, processDefines
- # can handle all of these fine.
+ # 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 to simplify processing of addition -
- # inserting at either end is cheap.
+ # 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):
- # filter deques out to avoid catching in is_List check below
+ # 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) or is_List(defines):
+ elif is_Tuple(defines):
+ if len(defines) > 2:
+ raise SCons.Errors.UserError(
+ f"Invalid tuple in CPPDEFINES: {define!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()
@@ -303,8 +320,9 @@ def _add_cppdefines(
env_dict[key] = deque(defines.items())
else:
env_dict[key] = deque(defines)
- defines = env_dict[key] # in case we reassigned it after the try block.
+ 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():
@@ -319,6 +337,31 @@ def _add_cppdefines(
_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:
@@ -329,20 +372,7 @@ def _add_cppdefines(
else:
_add_define(val, defines, prepend)
- # A tuple appended to anything should yield -Dkey=value
- elif is_Tuple(val):
- item = (val[0], val[1])
- 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_Sequence(val):
+ elif is_List(val):
tmp = []
for item in val:
if unique:
diff --git a/SCons/Environment.xml b/SCons/Environment.xml
index f7e2da979..f87e88393 100644
--- a/SCons/Environment.xml
+++ b/SCons/Environment.xml
@@ -512,7 +512,7 @@ but adding a string to a list or a list to a string requires
different syntax - things &f-Append; takes care of.
Some pre-defined &consvars; do have type expectations
based on how &SCons; will use them:
-for example &cv-link-CPPDEFINES; is normally a string or a list of strings,
+for example &cv-link-CPPDEFINES; is often a string or a list of strings,
but can also be a list of tuples or a dictionary;
while &cv-link-LIBEMITTER;
is expected to be a callable or list of callables,
@@ -577,20 +577,41 @@ scons: `.' is up to date.
<para>
Because &cv-link-CPPDEFINES; is intended for command-line
specification of C/C++ preprocessor macros,
-it accepts additional syntax.
-A command-line preprocessor macro can predefine a name by itself
-(<computeroutput>-DFOO</computeroutput>),
-which gives it an implicit value,
-or be given with a replacement value
-(<computeroutput>-DBAR=1</computeroutput>).
-&SCons; allows you to specify a macro with replacement
-three different ways:
-using a string, like
-<quote><literal>macro=replacement</literal></quote>;
-as a (non-string) sequence inside a (non-string) sequence,
-like <literal>[(macro, replacement)]</literal>
-or as a key/value pair in a dictionary
-<literal>{macro: replacement}</literal>. Examples:
+additional syntax is accepted when adding to it.
+The preprocessor accepts arguments to predefine a macro name by itself
+(<computeroutput>-DFOO</computeroutput> for most compilers,
+<computeroutput>/DFOO</computeroutput> for Microsoft C++),
+which gives it an implicit value of <constant>1</constant>,
+or can be given with a replacement value
+(<computeroutput>-DBAR=TEXT</computeroutput>).
+&SCons; follows these rules when adding to &cv-CPPDEFINES;:
+</para>
+<itemizedlist>
+<listitem>
+<para>A string is split on spaces,
+giving an easy way to enter multiple macros in one addition.
+Use an <literal>=</literal> to specify a valued macro.</para>
+</listitem>
+<listitem>
+<para>A tuple is treated as a valued macro.
+Use the value <constant>None</constant> if the macro should not have a value.
+It is an error to supply more than two elements in such a tuple.</para>
+</listitem>
+<listitem>
+<para>A list is processed in order,
+adding each item without further interpretation.
+In this case, space-separated strings are not split.</para>
+</listitem>
+<listitem>
+<para>A dictionary is processed in order,
+adding each key:value pair as a valued macro.
+Use the value <constant>None</constant> if the macro should not have a value.
+</para>
+</listitem>
+</itemizedlist>
+
+<para>
+Examples:
</para>
<example_commands>
@@ -616,15 +637,7 @@ scons: `.' is up to date.
</screen>
<para>
-Multiple &cv-CPPDEFINES; macros can be added in a single call
-using a (non-string) sequence,
-or using the dictionary form.
-If a given macro name should not have a replacement value,
-supply that macro as a string,
-or either omit the replacement value or give it as
-<constant>None</constant>;
-if using the dictionary form,
-specify the value as <constant>None</constant>. Examples:
+Examples of adding multiple macros:
</para>
<example_commands>
@@ -646,12 +659,8 @@ scons: `.' is up to date.
<para>
<emphasis>Changed in version 4.5</emphasis>:
-clarified that to receive the special handling,
-the tuple form must be supplied <emphasis>inside</emphasis>
-a sequence (e.g. a list); a single tuple will be interpreted
-just like a single list.
-Previously this form was inconsistently interpreted by
-various &SCons; methods.
+clarifined the use of tuples vs. other types,
+handling is now consistent across the four functions.
</para>
<example_commands>
diff --git a/SCons/Util/types.py b/SCons/Util/types.py
index 1602055d6..2071217e9 100644
--- a/SCons/Util/types.py
+++ b/SCons/Util/types.py
@@ -13,7 +13,7 @@ import re
from typing import Optional
from collections import UserDict, UserList, UserString, deque
-from collections.abc import MappingView
+from collections.abc import MappingView, Iterable
# Functions for deciding if things are like various types, mainly to
# handle UserDict, UserList and UserString like their underlying types.
@@ -86,16 +86,19 @@ def is_String( # pylint: disable=redefined-outer-name,redefined-builtin
def is_Scalar( # pylint: disable=redefined-outer-name,redefined-builtin
- obj, isinstance=isinstance, StringTypes=StringTypes, SequenceTypes=SequenceTypes
+ obj, isinstance=isinstance, StringTypes=StringTypes, Iterable=Iterable,
) -> bool:
- """Check if object is a scalar."""
+ """Check if object is a scalar: not a container or iterable."""
# Profiling shows that there is an impressive speed-up of 2x
# when explicitly checking for strings instead of just not
# sequence when the argument (i.e. obj) is already a string.
# But, if obj is a not string then it is twice as fast to
# check only for 'not sequence'. The following code therefore
# assumes that the obj argument is a string most of the time.
- return isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes)
+ # Update: now using collections.abc.Iterable for the 2nd check.
+ # Note: None is considered a "scalar" for this check, which is correct
+ # for the usage in SCons.Environment._add_cppdefines.
+ return isinstance(obj, StringTypes) or not isinstance(obj, Iterable)
# From Dinu C. Gherman,
diff --git a/test/CPPDEFINES/append.py b/test/CPPDEFINES/append.py
index 2a3102196..32917abcb 100644
--- a/test/CPPDEFINES/append.py
+++ b/test/CPPDEFINES/append.py
@@ -44,7 +44,9 @@ expect_print_output="""\
-Dfoo -Dbar -Dbaz
-Dfoo bar -Dbaz
-Dfoo -Dbar baz
--DMacro2=Value2 -DMacro3=Value3 -DMacro1=Value1
+-Dfoo -Dbar -Dbaz
+-DMacro2=Value2 -DMacro4 -DMacro3=Value3 -DMacro1=Value1
+-DMacro1=Value1
-DMacro1 -DValue1
==== Testing CPPDEFINES, appending a string to a string
orig = 'FOO', append = 'FOO'
@@ -63,21 +65,21 @@ AppendUnique:
result=['FOO', 'NAME1=VAL1']
final=-DFOO -DNAME1=VAL1
==== Testing CPPDEFINES, appending a list to a string
- orig = 'FOO', append = ['NAME1', 'NAME2']
+ orig = 'FOO', append = ['NAME1', 'NAME2', 'NAME3']
Append:
- result=['FOO', 'NAME1', 'NAME2']
- final=-DFOO -DNAME1 -DNAME2
+ result=['FOO', 'NAME1', 'NAME2', 'NAME3']
+ final=-DFOO -DNAME1 -DNAME2 -DNAME3
AppendUnique:
- result=['FOO', 'NAME1', 'NAME2']
- final=-DFOO -DNAME1 -DNAME2
+ result=['FOO', 'NAME1', 'NAME2', 'NAME3']
+ final=-DFOO -DNAME1 -DNAME2 -DNAME3
==== Testing CPPDEFINES, appending a tuple to a string
- orig = 'FOO', append = ('NAME1', 'NAME2')
+ orig = 'FOO', append = ('NAME1', 'VAL1')
Append:
- result=['FOO', 'NAME1', 'NAME2']
- final=-DFOO -DNAME1 -DNAME2
+ result=['FOO', ('NAME1', 'VAL1')]
+ final=-DFOO -DNAME1=VAL1
AppendUnique:
- result=['FOO', 'NAME1', 'NAME2']
- final=-DFOO -DNAME1 -DNAME2
+ result=['FOO', ('NAME1', 'VAL1')]
+ final=-DFOO -DNAME1=VAL1
==== Testing CPPDEFINES, appending a list-of-2lists to a string
orig = 'FOO', append = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
Append:
@@ -111,21 +113,21 @@ AppendUnique:
result=['NAME1=VAL1']
final=-DNAME1=VAL1
==== Testing CPPDEFINES, appending a list to a valuestring
- orig = 'NAME1=VAL1', append = ['NAME1', 'NAME2']
+ orig = 'NAME1=VAL1', append = ['NAME1', 'NAME2', 'NAME3']
Append:
- result=['NAME1=VAL1', 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME1 -DNAME2
+ result=['NAME1=VAL1', 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1=VAL1 -DNAME1 -DNAME2 -DNAME3
AppendUnique:
- result=['NAME1=VAL1', 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME1 -DNAME2
+ result=['NAME1=VAL1', 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1=VAL1 -DNAME1 -DNAME2 -DNAME3
==== Testing CPPDEFINES, appending a tuple to a valuestring
- orig = 'NAME1=VAL1', append = ('NAME1', 'NAME2')
+ orig = 'NAME1=VAL1', append = ('NAME1', 'VAL1')
Append:
- result=['NAME1=VAL1', 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME1 -DNAME2
+ result=['NAME1=VAL1', ('NAME1', 'VAL1')]
+ final=-DNAME1=VAL1 -DNAME1=VAL1
AppendUnique:
- result=['NAME1=VAL1', 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME1 -DNAME2
+ result=['NAME1=VAL1']
+ final=-DNAME1=VAL1
==== Testing CPPDEFINES, appending a list-of-2lists to a valuestring
orig = 'NAME1=VAL1', append = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
Append:
@@ -143,101 +145,101 @@ AppendUnique:
result=['NAME1=VAL1', ('NAME2', 'VAL2'), ('NAME3', None)]
final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME3
==== Testing CPPDEFINES, appending a string to a list
- orig = ['NAME1', 'NAME2'], append = 'FOO'
+ orig = ['NAME1', 'NAME2', 'NAME3'], append = 'FOO'
Append:
- result=['NAME1', 'NAME2', 'FOO']
- final=-DNAME1 -DNAME2 -DFOO
+ result=['NAME1', 'NAME2', 'NAME3', 'FOO']
+ final=-DNAME1 -DNAME2 -DNAME3 -DFOO
AppendUnique:
- result=['NAME1', 'NAME2', 'FOO']
- final=-DNAME1 -DNAME2 -DFOO
+ result=['NAME1', 'NAME2', 'NAME3', 'FOO']
+ final=-DNAME1 -DNAME2 -DNAME3 -DFOO
==== Testing CPPDEFINES, appending a valuestring to a list
- orig = ['NAME1', 'NAME2'], append = 'NAME1=VAL1'
+ orig = ['NAME1', 'NAME2', 'NAME3'], append = 'NAME1=VAL1'
Append:
- result=['NAME1', 'NAME2', 'NAME1=VAL1']
- final=-DNAME1 -DNAME2 -DNAME1=VAL1
+ result=['NAME1', 'NAME2', 'NAME3', 'NAME1=VAL1']
+ final=-DNAME1 -DNAME2 -DNAME3 -DNAME1=VAL1
AppendUnique:
- result=['NAME1', 'NAME2', 'NAME1=VAL1']
- final=-DNAME1 -DNAME2 -DNAME1=VAL1
+ result=['NAME1', 'NAME2', 'NAME3', 'NAME1=VAL1']
+ final=-DNAME1 -DNAME2 -DNAME3 -DNAME1=VAL1
==== Testing CPPDEFINES, appending a list to a list
- orig = ['NAME1', 'NAME2'], append = ['NAME1', 'NAME2']
+ orig = ['NAME1', 'NAME2', 'NAME3'], append = ['NAME1', 'NAME2', 'NAME3']
Append:
- result=['NAME1', 'NAME2', 'NAME1', 'NAME2']
- final=-DNAME1 -DNAME2 -DNAME1 -DNAME2
+ result=['NAME1', 'NAME2', 'NAME3', 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1 -DNAME2 -DNAME3 -DNAME1 -DNAME2 -DNAME3
AppendUnique:
- result=['NAME1', 'NAME2']
- final=-DNAME1 -DNAME2
+ result=['NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1 -DNAME2 -DNAME3
==== Testing CPPDEFINES, appending a tuple to a list
- orig = ['NAME1', 'NAME2'], append = ('NAME1', 'NAME2')
+ orig = ['NAME1', 'NAME2', 'NAME3'], append = ('NAME1', 'VAL1')
Append:
- result=['NAME1', 'NAME2', 'NAME1', 'NAME2']
- final=-DNAME1 -DNAME2 -DNAME1 -DNAME2
+ result=['NAME1', 'NAME2', 'NAME3', ('NAME1', 'VAL1')]
+ final=-DNAME1 -DNAME2 -DNAME3 -DNAME1=VAL1
AppendUnique:
- result=['NAME1', 'NAME2']
- final=-DNAME1 -DNAME2
+ result=['NAME1', 'NAME2', 'NAME3', ('NAME1', 'VAL1')]
+ final=-DNAME1 -DNAME2 -DNAME3 -DNAME1=VAL1
==== Testing CPPDEFINES, appending a list-of-2lists to a list
- orig = ['NAME1', 'NAME2'], append = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ orig = ['NAME1', 'NAME2', 'NAME3'], append = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
Append:
- result=['NAME1', 'NAME2', ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
- final=-DNAME1 -DNAME2 -DNAME1=VAL1 -DNAME2=VAL2
+ result=['NAME1', 'NAME2', 'NAME3', ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ final=-DNAME1 -DNAME2 -DNAME3 -DNAME1=VAL1 -DNAME2=VAL2
AppendUnique:
- result=['NAME1', 'NAME2', ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
- final=-DNAME1 -DNAME2 -DNAME1=VAL1 -DNAME2=VAL2
+ result=['NAME1', 'NAME2', 'NAME3', ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ final=-DNAME1 -DNAME2 -DNAME3 -DNAME1=VAL1 -DNAME2=VAL2
==== Testing CPPDEFINES, appending a dict to a list
- orig = ['NAME1', 'NAME2'], append = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
+ orig = ['NAME1', 'NAME2', 'NAME3'], append = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
Append:
- result=['NAME1', 'NAME2', ('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
- final=-DNAME1 -DNAME2 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
+ result=['NAME1', 'NAME2', 'NAME3', ('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
+ final=-DNAME1 -DNAME2 -DNAME3 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
AppendUnique:
- result=['NAME1', 'NAME2', ('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
- final=-DNAME1 -DNAME2 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
+ result=['NAME1', 'NAME2', 'NAME3', ('NAME2', 'VAL2'), ('NAME1', 'VAL1')]
+ final=-DNAME1 -DNAME2 -DNAME3 -DNAME2=VAL2 -DNAME1=VAL1
==== Testing CPPDEFINES, appending a string to a tuple
- orig = ('NAME1', 'NAME2'), append = 'FOO'
+ orig = ('NAME1', 'VAL1'), append = 'FOO'
Append:
- result=['NAME1', 'NAME2', 'FOO']
- final=-DNAME1 -DNAME2 -DFOO
+ result=[('NAME1', 'VAL1'), 'FOO']
+ final=-DNAME1=VAL1 -DFOO
AppendUnique:
- result=['NAME1', 'NAME2', 'FOO']
- final=-DNAME1 -DNAME2 -DFOO
+ result=[('NAME1', 'VAL1'), 'FOO']
+ final=-DNAME1=VAL1 -DFOO
==== Testing CPPDEFINES, appending a valuestring to a tuple
- orig = ('NAME1', 'NAME2'), append = 'NAME1=VAL1'
+ orig = ('NAME1', 'VAL1'), append = 'NAME1=VAL1'
Append:
- result=['NAME1', 'NAME2', 'NAME1=VAL1']
- final=-DNAME1 -DNAME2 -DNAME1=VAL1
+ result=[('NAME1', 'VAL1'), 'NAME1=VAL1']
+ final=-DNAME1=VAL1 -DNAME1=VAL1
AppendUnique:
- result=['NAME1', 'NAME2', 'NAME1=VAL1']
- final=-DNAME1 -DNAME2 -DNAME1=VAL1
+ result=[('NAME1', 'VAL1')]
+ final=-DNAME1=VAL1
==== Testing CPPDEFINES, appending a list to a tuple
- orig = ('NAME1', 'NAME2'), append = ['NAME1', 'NAME2']
+ orig = ('NAME1', 'VAL1'), append = ['NAME1', 'NAME2', 'NAME3']
Append:
- result=['NAME1', 'NAME2', 'NAME1', 'NAME2']
- final=-DNAME1 -DNAME2 -DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1'), 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1=VAL1 -DNAME1 -DNAME2 -DNAME3
AppendUnique:
- result=['NAME1', 'NAME2']
- final=-DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1'), 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1=VAL1 -DNAME1 -DNAME2 -DNAME3
==== Testing CPPDEFINES, appending a tuple to a tuple
- orig = ('NAME1', 'NAME2'), append = ('NAME1', 'NAME2')
+ orig = ('NAME1', 'VAL1'), append = ('NAME1', 'VAL1')
Append:
- result=['NAME1', 'NAME2', 'NAME1', 'NAME2']
- final=-DNAME1 -DNAME2 -DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1'), ('NAME1', 'VAL1')]
+ final=-DNAME1=VAL1 -DNAME1=VAL1
AppendUnique:
- result=['NAME1', 'NAME2']
- final=-DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1')]
+ final=-DNAME1=VAL1
==== Testing CPPDEFINES, appending a list-of-2lists to a tuple
- orig = ('NAME1', 'NAME2'), append = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ orig = ('NAME1', 'VAL1'), append = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
Append:
- result=['NAME1', 'NAME2', ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
- final=-DNAME1 -DNAME2 -DNAME1=VAL1 -DNAME2=VAL2
+ result=[('NAME1', 'VAL1'), ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ final=-DNAME1=VAL1 -DNAME1=VAL1 -DNAME2=VAL2
AppendUnique:
- result=['NAME1', 'NAME2', ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
- final=-DNAME1 -DNAME2 -DNAME1=VAL1 -DNAME2=VAL2
+ result=[('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ final=-DNAME1=VAL1 -DNAME2=VAL2
==== Testing CPPDEFINES, appending a dict to a tuple
- orig = ('NAME1', 'NAME2'), append = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
+ orig = ('NAME1', 'VAL1'), append = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
Append:
- result=['NAME1', 'NAME2', ('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
- final=-DNAME1 -DNAME2 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
+ result=[('NAME1', 'VAL1'), ('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
+ final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
AppendUnique:
- result=['NAME1', 'NAME2', ('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
- final=-DNAME1 -DNAME2 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
+ result=[('NAME1', 'VAL1'), ('NAME2', 'VAL2'), ('NAME3', None)]
+ final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME3
==== Testing CPPDEFINES, appending a string to a list-of-2lists
orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], append = 'FOO'
Append:
@@ -255,21 +257,21 @@ AppendUnique:
result=[('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
final=-DNAME1=VAL1 -DNAME2=VAL2
==== Testing CPPDEFINES, appending a list to a list-of-2lists
- orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], append = ['NAME1', 'NAME2']
+ orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], append = ['NAME1', 'NAME2', 'NAME3']
Append:
- result=[('NAME1', 'VAL1'), ['NAME2', 'VAL2'], 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1'), ['NAME2', 'VAL2'], 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME1 -DNAME2 -DNAME3
AppendUnique:
- result=[('NAME1', 'VAL1'), ['NAME2', 'VAL2'], 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1'), ['NAME2', 'VAL2'], 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME1 -DNAME2 -DNAME3
==== Testing CPPDEFINES, appending a tuple to a list-of-2lists
- orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], append = ('NAME1', 'NAME2')
+ orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], append = ('NAME1', 'VAL1')
Append:
- result=[('NAME1', 'VAL1'), ['NAME2', 'VAL2'], 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1'), ['NAME2', 'VAL2'], ('NAME1', 'VAL1')]
+ final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME1=VAL1
AppendUnique:
- result=[('NAME1', 'VAL1'), ['NAME2', 'VAL2'], 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ final=-DNAME1=VAL1 -DNAME2=VAL2
==== Testing CPPDEFINES, appending a list-of-2lists to a list-of-2lists
orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], append = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
Append:
@@ -303,21 +305,21 @@ AppendUnique:
result=[('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
==== Testing CPPDEFINES, appending a list to a dict
- orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, append = ['NAME1', 'NAME2']
+ orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, append = ['NAME1', 'NAME2', 'NAME3']
Append:
- result=[('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1'), 'NAME1', 'NAME2']
- final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1 -DNAME1 -DNAME2
+ result=[('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1'), 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1 -DNAME1 -DNAME2 -DNAME3
AppendUnique:
result=[('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1'), 'NAME1', 'NAME2']
final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1 -DNAME1 -DNAME2
==== Testing CPPDEFINES, appending a tuple to a dict
- orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, append = ('NAME1', 'NAME2')
+ orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, append = ('NAME1', 'VAL1')
Append:
- result=[('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1'), 'NAME1', 'NAME2']
- final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1 -DNAME1 -DNAME2
+ result=[('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1'), ('NAME1', 'VAL1')]
+ final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1 -DNAME1=VAL1
AppendUnique:
- result=[('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1'), 'NAME1', 'NAME2']
- final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1 -DNAME1 -DNAME2
+ result=[('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
+ final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
==== Testing CPPDEFINES, appending a list-of-2lists to a dict
orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, append = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
Append:
diff --git a/test/CPPDEFINES/fixture/SConstruct-Append b/test/CPPDEFINES/fixture/SConstruct-Append
index 76b86ad0c..df47f681e 100644
--- a/test/CPPDEFINES/fixture/SConstruct-Append
+++ b/test/CPPDEFINES/fixture/SConstruct-Append
@@ -15,7 +15,7 @@ env_2300_2 = Environment(CPPDEFINES=['foo'], CPPDEFPREFIX='-D') # note the list
env_2300_2.Append(CPPDEFINES='bar')
print(env_2300_2.subst('$_CPPDEFFLAGS'))
-# an initial space-separated string will be split, but not a string in a list
+# An initial space-separated string will be split, but not a string in a list.
env_multi = Environment(CPPDEFPREFIX='-D')
env_multi['CPPDEFINES'] = "foo bar"
env_multi.Append(CPPDEFINES="baz")
@@ -28,20 +28,27 @@ env_multi = Environment(CPPDEFPREFIX='-D')
env_multi['CPPDEFINES'] = "foo"
env_multi.Append(CPPDEFINES=["bar baz"])
print(env_multi.subst('$_CPPDEFFLAGS'))
+env_multi = Environment(CPPDEFPREFIX='-D')
+env_multi['CPPDEFINES'] = "foo"
+env_multi.Append(CPPDEFINES="bar baz")
+print(env_multi.subst('$_CPPDEFFLAGS'))
-# check that AppendUnique(..., delete_existing=True) works as expected
-# each addition is in different but matching form, and different order
+# Check that AppendUnique(..., delete_existing=True) works as expected.
+# Each addition is in different but matching form, and different order
# so we expect a reordered list, but with the same macro defines.
env_multi = Environment(CPPDEFPREFIX='-D')
-env_multi.Append(CPPDEFINES=["Macro1=Value1", ("Macro2", "Value2"), {"Macro3": "Value3"}])
+env_multi.Append(CPPDEFINES=["Macro1=Value1", ("Macro2", "Value2"), {"Macro3": "Value3"}, "Macro4"])
env_multi.AppendUnique(CPPDEFINES="Macro2=Value2", delete_existing=True)
+env_multi.AppendUnique(CPPDEFINES=[("Macro4", None)], delete_existing=True)
env_multi.AppendUnique(CPPDEFINES=[("Macro3", "Value3")], delete_existing=True)
env_multi.AppendUnique(CPPDEFINES={"Macro1": "Value1"}, delete_existing=True)
print(env_multi.subst('$_CPPDEFFLAGS'))
-# a lone tuple
+# A lone tuple handled differently than a lone list.
env_multi = Environment(CPPDEFPREFIX='-D', CPPDEFINES=("Macro1", "Value1"))
print(env_multi.subst('$_CPPDEFFLAGS'))
+env_multi = Environment(CPPDEFPREFIX='-D', CPPDEFINES=["Macro1", "Value1"])
+print(env_multi.subst('$_CPPDEFFLAGS'))
# https://github.com/SCons/scons/issues/1152
# https://github.com/SCons/scons/issues/2900
@@ -66,11 +73,11 @@ class OrderedPrintingDict(OrderedDict):
cases = [
('string', 'FOO'),
('valuestring', 'NAME1=VAL1'),
- ('list', ['NAME1', 'NAME2']),
- ('tuple', ('NAME1', 'NAME2')),
+ ('list', ['NAME1', 'NAME2', 'NAME3']),
+ ('tuple', ('NAME1', 'VAL1')),
('list-of-2lists', [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]),
(
- 'dict',
+ 'dict', # intentionally not sorted by key
OrderedPrintingDict([('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]),
),
]
diff --git a/test/CPPDEFINES/fixture/SConstruct-Prepend b/test/CPPDEFINES/fixture/SConstruct-Prepend
index 4628ea46a..7fd4d8475 100644
--- a/test/CPPDEFINES/fixture/SConstruct-Prepend
+++ b/test/CPPDEFINES/fixture/SConstruct-Prepend
@@ -15,7 +15,7 @@ env_2300_2 = Environment(CPPDEFINES=['foo'], CPPDEFPREFIX='-D') # note the list
env_2300_2.Prepend(CPPDEFINES='bar')
print(env_2300_2.subst('$_CPPDEFFLAGS'))
-# an initial space-separated string will be split, but not a string in a list
+# An initial space-separated string will be split, but not a string in a list.
env_multi = Environment(CPPDEFPREFIX='-D')
env_multi['CPPDEFINES'] = "foo bar"
env_multi.Prepend(CPPDEFINES="baz")
@@ -28,20 +28,27 @@ env_multi = Environment(CPPDEFPREFIX='-D')
env_multi['CPPDEFINES'] = "foo"
env_multi.Prepend(CPPDEFINES=["bar baz"])
print(env_multi.subst('$_CPPDEFFLAGS'))
+env_multi = Environment(CPPDEFPREFIX='-D')
+env_multi['CPPDEFINES'] = "foo"
+env_multi.Prepend(CPPDEFINES="bar baz")
+print(env_multi.subst('$_CPPDEFFLAGS'))
-# check that PrependUnique(..., delete_existing=True) works as expected
-# each addition is in different but matching form, and different order,
+# Check that AppendUnique(..., delete_existing=True) works as expected.
+# Each addition is in different but matching form, and different order
# so we expect a reordered list, but with the same macro defines.
env_multi = Environment(CPPDEFPREFIX='-D')
env_multi.Prepend(CPPDEFINES=["Macro1=Value1", ("Macro2", "Value2"), {"Macro3": "Value3"}])
env_multi.PrependUnique(CPPDEFINES="Macro2=Value2", delete_existing=True)
+env_multi.AppendUnique(CPPDEFINES=[("Macro4", None)], delete_existing=True)
env_multi.PrependUnique(CPPDEFINES=[("Macro3", "Value3")], delete_existing=True)
env_multi.PrependUnique(CPPDEFINES={"Macro1": "Value1"}, delete_existing=True)
print(env_multi.subst('$_CPPDEFFLAGS'))
-# a lone tuple
+# A lone tuple handled differently than a lone list.
env_tuple = Environment(CPPDEFPREFIX='-D', CPPDEFINES=("Macro1", "Value1"))
print(env_tuple.subst('$_CPPDEFFLAGS'))
+env_multi = Environment(CPPDEFPREFIX='-D', CPPDEFINES=["Macro1", "Value1"])
+print(env_multi.subst('$_CPPDEFFLAGS'))
# https://github.com/SCons/scons/issues/1152
# https://github.com/SCons/scons/issues/2900
@@ -67,11 +74,11 @@ class OrderedPrintingDict(OrderedDict):
cases = [
('string', 'FOO'),
('valuestring', 'NAME1=VAL1'),
- ('list', ['NAME1', 'NAME2']),
- ('tuple', ('NAME1', 'NAME2')),
+ ('list', ['NAME1', 'NAME2', 'NAME3']),
+ ('tuple', ('NAME1', 'VAL1')),
('list-of-2lists', [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]),
(
- 'dict',
+ 'dict', # intentionally not sorted by key
OrderedPrintingDict([('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]),
),
]
diff --git a/test/CPPDEFINES/prepend.py b/test/CPPDEFINES/prepend.py
index 5ec2e468e..16bedac05 100644
--- a/test/CPPDEFINES/prepend.py
+++ b/test/CPPDEFINES/prepend.py
@@ -43,7 +43,9 @@ expect_print_output="""\
-Dbaz -Dfoo -Dbar
-Dbaz -Dfoo bar
-Dbar baz -Dfoo
--DMacro1=Value1 -DMacro3=Value3 -DMacro2=Value2
+-Dbaz -Dbar -Dfoo
+-DMacro1=Value1 -DMacro3=Value3 -DMacro2=Value2 -DMacro4
+-DMacro1=Value1
-DMacro1 -DValue1
==== Testing CPPDEFINES, prepending a string to a string
orig = 'FOO', prepend = 'FOO'
@@ -62,21 +64,21 @@ PrependUnique:
result=['NAME1=VAL1', 'FOO']
final=-DNAME1=VAL1 -DFOO
==== Testing CPPDEFINES, prepending a list to a string
- orig = 'FOO', prepend = ['NAME1', 'NAME2']
+ orig = 'FOO', prepend = ['NAME1', 'NAME2', 'NAME3']
Prepend:
- result=['NAME2', 'NAME1', 'FOO']
- final=-DNAME2 -DNAME1 -DFOO
+ result=['NAME3', 'NAME2', 'NAME1', 'FOO']
+ final=-DNAME3 -DNAME2 -DNAME1 -DFOO
PrependUnique:
- result=['NAME2', 'NAME1', 'FOO']
- final=-DNAME2 -DNAME1 -DFOO
+ result=['NAME3', 'NAME2', 'NAME1', 'FOO']
+ final=-DNAME3 -DNAME2 -DNAME1 -DFOO
==== Testing CPPDEFINES, prepending a tuple to a string
- orig = 'FOO', prepend = ('NAME1', 'NAME2')
+ orig = 'FOO', prepend = ('NAME1', 'VAL1')
Prepend:
- result=['NAME2', 'NAME1', 'FOO']
- final=-DNAME2 -DNAME1 -DFOO
+ result=[('NAME1', 'VAL1'), 'FOO']
+ final=-DNAME1=VAL1 -DFOO
PrependUnique:
- result=['NAME2', 'NAME1', 'FOO']
- final=-DNAME2 -DNAME1 -DFOO
+ result=[('NAME1', 'VAL1'), 'FOO']
+ final=-DNAME1=VAL1 -DFOO
==== Testing CPPDEFINES, prepending a list-of-2lists to a string
orig = 'FOO', prepend = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
Prepend:
@@ -110,21 +112,21 @@ PrependUnique:
result=['NAME1=VAL1']
final=-DNAME1=VAL1
==== Testing CPPDEFINES, prepending a list to a valuestring
- orig = 'NAME1=VAL1', prepend = ['NAME1', 'NAME2']
+ orig = 'NAME1=VAL1', prepend = ['NAME1', 'NAME2', 'NAME3']
Prepend:
- result=['NAME2', 'NAME1', 'NAME1=VAL1']
- final=-DNAME2 -DNAME1 -DNAME1=VAL1
+ result=['NAME3', 'NAME2', 'NAME1', 'NAME1=VAL1']
+ final=-DNAME3 -DNAME2 -DNAME1 -DNAME1=VAL1
PrependUnique:
- result=['NAME2', 'NAME1', 'NAME1=VAL1']
- final=-DNAME2 -DNAME1 -DNAME1=VAL1
+ result=['NAME3', 'NAME2', 'NAME1', 'NAME1=VAL1']
+ final=-DNAME3 -DNAME2 -DNAME1 -DNAME1=VAL1
==== Testing CPPDEFINES, prepending a tuple to a valuestring
- orig = 'NAME1=VAL1', prepend = ('NAME1', 'NAME2')
+ orig = 'NAME1=VAL1', prepend = ('NAME1', 'VAL1')
Prepend:
- result=['NAME2', 'NAME1', 'NAME1=VAL1']
- final=-DNAME2 -DNAME1 -DNAME1=VAL1
+ result=[('NAME1', 'VAL1'), 'NAME1=VAL1']
+ final=-DNAME1=VAL1 -DNAME1=VAL1
PrependUnique:
- result=['NAME2', 'NAME1', 'NAME1=VAL1']
- final=-DNAME2 -DNAME1 -DNAME1=VAL1
+ result=['NAME1=VAL1']
+ final=-DNAME1=VAL1
==== Testing CPPDEFINES, prepending a list-of-2lists to a valuestring
orig = 'NAME1=VAL1', prepend = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
Prepend:
@@ -142,101 +144,101 @@ PrependUnique:
result=[('NAME3', None), ('NAME2', 'VAL2'), 'NAME1=VAL1']
final=-DNAME3 -DNAME2=VAL2 -DNAME1=VAL1
==== Testing CPPDEFINES, prepending a string to a list
- orig = ['NAME1', 'NAME2'], prepend = 'FOO'
+ orig = ['NAME1', 'NAME2', 'NAME3'], prepend = 'FOO'
Prepend:
- result=['FOO', 'NAME1', 'NAME2']
- final=-DFOO -DNAME1 -DNAME2
+ result=['FOO', 'NAME1', 'NAME2', 'NAME3']
+ final=-DFOO -DNAME1 -DNAME2 -DNAME3
PrependUnique:
- result=['FOO', 'NAME1', 'NAME2']
- final=-DFOO -DNAME1 -DNAME2
+ result=['FOO', 'NAME1', 'NAME2', 'NAME3']
+ final=-DFOO -DNAME1 -DNAME2 -DNAME3
==== Testing CPPDEFINES, prepending a valuestring to a list
- orig = ['NAME1', 'NAME2'], prepend = 'NAME1=VAL1'
+ orig = ['NAME1', 'NAME2', 'NAME3'], prepend = 'NAME1=VAL1'
Prepend:
- result=['NAME1=VAL1', 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME1 -DNAME2
+ result=['NAME1=VAL1', 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1=VAL1 -DNAME1 -DNAME2 -DNAME3
PrependUnique:
- result=['NAME1=VAL1', 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME1 -DNAME2
+ result=['NAME1=VAL1', 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1=VAL1 -DNAME1 -DNAME2 -DNAME3
==== Testing CPPDEFINES, prepending a list to a list
- orig = ['NAME1', 'NAME2'], prepend = ['NAME1', 'NAME2']
+ orig = ['NAME1', 'NAME2', 'NAME3'], prepend = ['NAME1', 'NAME2', 'NAME3']
Prepend:
- result=['NAME2', 'NAME1', 'NAME1', 'NAME2']
- final=-DNAME2 -DNAME1 -DNAME1 -DNAME2
+ result=['NAME3', 'NAME2', 'NAME1', 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME3 -DNAME2 -DNAME1 -DNAME1 -DNAME2 -DNAME3
PrependUnique:
- result=['NAME1', 'NAME2']
- final=-DNAME1 -DNAME2
+ result=['NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1 -DNAME2 -DNAME3
==== Testing CPPDEFINES, prepending a tuple to a list
- orig = ['NAME1', 'NAME2'], prepend = ('NAME1', 'NAME2')
+ orig = ['NAME1', 'NAME2', 'NAME3'], prepend = ('NAME1', 'VAL1')
Prepend:
- result=['NAME2', 'NAME1', 'NAME1', 'NAME2']
- final=-DNAME2 -DNAME1 -DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1'), 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1=VAL1 -DNAME1 -DNAME2 -DNAME3
PrependUnique:
- result=['NAME1', 'NAME2']
- final=-DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1'), 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1=VAL1 -DNAME1 -DNAME2 -DNAME3
==== Testing CPPDEFINES, prepending a list-of-2lists to a list
- orig = ['NAME1', 'NAME2'], prepend = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ orig = ['NAME1', 'NAME2', 'NAME3'], prepend = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
Prepend:
- result=[['NAME2', 'VAL2'], ('NAME1', 'VAL1'), 'NAME1', 'NAME2']
- final=-DNAME2=VAL2 -DNAME1=VAL1 -DNAME1 -DNAME2
+ result=[['NAME2', 'VAL2'], ('NAME1', 'VAL1'), 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME2=VAL2 -DNAME1=VAL1 -DNAME1 -DNAME2 -DNAME3
PrependUnique:
- result=[['NAME2', 'VAL2'], ('NAME1', 'VAL1'), 'NAME1', 'NAME2']
- final=-DNAME2=VAL2 -DNAME1=VAL1 -DNAME1 -DNAME2
+ result=[['NAME2', 'VAL2'], ('NAME1', 'VAL1'), 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME2=VAL2 -DNAME1=VAL1 -DNAME1 -DNAME2 -DNAME3
==== Testing CPPDEFINES, prepending a dict to a list
- orig = ['NAME1', 'NAME2'], prepend = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
+ orig = ['NAME1', 'NAME2', 'NAME3'], prepend = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
Prepend:
- result=[('NAME1', 'VAL1'), ('NAME3', None), ('NAME2', 'VAL2'), 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME3 -DNAME2=VAL2 -DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1'), ('NAME3', None), ('NAME2', 'VAL2'), 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1=VAL1 -DNAME3 -DNAME2=VAL2 -DNAME1 -DNAME2 -DNAME3
PrependUnique:
- result=[('NAME1', 'VAL1'), ('NAME3', None), ('NAME2', 'VAL2'), 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME3 -DNAME2=VAL2 -DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1'), ('NAME2', 'VAL2'), 'NAME1', 'NAME2', 'NAME3']
+ final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME1 -DNAME2 -DNAME3
==== Testing CPPDEFINES, prepending a string to a tuple
- orig = ('NAME1', 'NAME2'), prepend = 'FOO'
+ orig = ('NAME1', 'VAL1'), prepend = 'FOO'
Prepend:
- result=['FOO', 'NAME1', 'NAME2']
- final=-DFOO -DNAME1 -DNAME2
+ result=['FOO', ('NAME1', 'VAL1')]
+ final=-DFOO -DNAME1=VAL1
PrependUnique:
- result=['FOO', 'NAME1', 'NAME2']
- final=-DFOO -DNAME1 -DNAME2
+ result=['FOO', ('NAME1', 'VAL1')]
+ final=-DFOO -DNAME1=VAL1
==== Testing CPPDEFINES, prepending a valuestring to a tuple
- orig = ('NAME1', 'NAME2'), prepend = 'NAME1=VAL1'
+ orig = ('NAME1', 'VAL1'), prepend = 'NAME1=VAL1'
Prepend:
- result=['NAME1=VAL1', 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME1 -DNAME2
+ result=['NAME1=VAL1', ('NAME1', 'VAL1')]
+ final=-DNAME1=VAL1 -DNAME1=VAL1
PrependUnique:
- result=['NAME1=VAL1', 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1')]
+ final=-DNAME1=VAL1
==== Testing CPPDEFINES, prepending a list to a tuple
- orig = ('NAME1', 'NAME2'), prepend = ['NAME1', 'NAME2']
+ orig = ('NAME1', 'VAL1'), prepend = ['NAME1', 'NAME2', 'NAME3']
Prepend:
- result=['NAME2', 'NAME1', 'NAME1', 'NAME2']
- final=-DNAME2 -DNAME1 -DNAME1 -DNAME2
+ result=['NAME3', 'NAME2', 'NAME1', ('NAME1', 'VAL1')]
+ final=-DNAME3 -DNAME2 -DNAME1 -DNAME1=VAL1
PrependUnique:
- result=['NAME1', 'NAME2']
- final=-DNAME1 -DNAME2
+ result=['NAME3', 'NAME2', 'NAME1', ('NAME1', 'VAL1')]
+ final=-DNAME3 -DNAME2 -DNAME1 -DNAME1=VAL1
==== Testing CPPDEFINES, prepending a tuple to a tuple
- orig = ('NAME1', 'NAME2'), prepend = ('NAME1', 'NAME2')
+ orig = ('NAME1', 'VAL1'), prepend = ('NAME1', 'VAL1')
Prepend:
- result=['NAME2', 'NAME1', 'NAME1', 'NAME2']
- final=-DNAME2 -DNAME1 -DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1'), ('NAME1', 'VAL1')]
+ final=-DNAME1=VAL1 -DNAME1=VAL1
PrependUnique:
- result=['NAME1', 'NAME2']
- final=-DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1')]
+ final=-DNAME1=VAL1
==== Testing CPPDEFINES, prepending a list-of-2lists to a tuple
- orig = ('NAME1', 'NAME2'), prepend = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ orig = ('NAME1', 'VAL1'), prepend = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
Prepend:
- result=[['NAME2', 'VAL2'], ('NAME1', 'VAL1'), 'NAME1', 'NAME2']
- final=-DNAME2=VAL2 -DNAME1=VAL1 -DNAME1 -DNAME2
+ result=[['NAME2', 'VAL2'], ('NAME1', 'VAL1'), ('NAME1', 'VAL1')]
+ final=-DNAME2=VAL2 -DNAME1=VAL1 -DNAME1=VAL1
PrependUnique:
- result=[['NAME2', 'VAL2'], ('NAME1', 'VAL1'), 'NAME1', 'NAME2']
- final=-DNAME2=VAL2 -DNAME1=VAL1 -DNAME1 -DNAME2
+ result=[['NAME2', 'VAL2'], ('NAME1', 'VAL1')]
+ final=-DNAME2=VAL2 -DNAME1=VAL1
==== Testing CPPDEFINES, prepending a dict to a tuple
- orig = ('NAME1', 'NAME2'), prepend = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
+ orig = ('NAME1', 'VAL1'), prepend = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}
Prepend:
- result=[('NAME1', 'VAL1'), ('NAME3', None), ('NAME2', 'VAL2'), 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME3 -DNAME2=VAL2 -DNAME1 -DNAME2
+ result=[('NAME1', 'VAL1'), ('NAME3', None), ('NAME2', 'VAL2'), ('NAME1', 'VAL1')]
+ final=-DNAME1=VAL1 -DNAME3 -DNAME2=VAL2 -DNAME1=VAL1
PrependUnique:
- result=[('NAME1', 'VAL1'), ('NAME3', None), ('NAME2', 'VAL2'), 'NAME1', 'NAME2']
- final=-DNAME1=VAL1 -DNAME3 -DNAME2=VAL2 -DNAME1 -DNAME2
+ result=[('NAME3', None), ('NAME2', 'VAL2'), ('NAME1', 'VAL1')]
+ final=-DNAME3 -DNAME2=VAL2 -DNAME1=VAL1
==== Testing CPPDEFINES, prepending a string to a list-of-2lists
orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], prepend = 'FOO'
Prepend:
@@ -254,21 +256,21 @@ PrependUnique:
result=[('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
final=-DNAME1=VAL1 -DNAME2=VAL2
==== Testing CPPDEFINES, prepending a list to a list-of-2lists
- orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], prepend = ['NAME1', 'NAME2']
+ orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], prepend = ['NAME1', 'NAME2', 'NAME3']
Prepend:
- result=['NAME2', 'NAME1', ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
- final=-DNAME2 -DNAME1 -DNAME1=VAL1 -DNAME2=VAL2
+ result=['NAME3', 'NAME2', 'NAME1', ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ final=-DNAME3 -DNAME2 -DNAME1 -DNAME1=VAL1 -DNAME2=VAL2
PrependUnique:
- result=['NAME2', 'NAME1', ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
- final=-DNAME2 -DNAME1 -DNAME1=VAL1 -DNAME2=VAL2
+ result=['NAME3', 'NAME2', 'NAME1', ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ final=-DNAME3 -DNAME2 -DNAME1 -DNAME1=VAL1 -DNAME2=VAL2
==== Testing CPPDEFINES, prepending a tuple to a list-of-2lists
- orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], prepend = ('NAME1', 'NAME2')
+ orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], prepend = ('NAME1', 'VAL1')
Prepend:
- result=['NAME2', 'NAME1', ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
- final=-DNAME2 -DNAME1 -DNAME1=VAL1 -DNAME2=VAL2
+ result=[('NAME1', 'VAL1'), ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ final=-DNAME1=VAL1 -DNAME1=VAL1 -DNAME2=VAL2
PrependUnique:
- result=['NAME2', 'NAME1', ('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
- final=-DNAME2 -DNAME1 -DNAME1=VAL1 -DNAME2=VAL2
+ result=[('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
+ final=-DNAME1=VAL1 -DNAME2=VAL2
==== Testing CPPDEFINES, prepending a list-of-2lists to a list-of-2lists
orig = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']], prepend = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
Prepend:
@@ -302,21 +304,21 @@ PrependUnique:
result=[('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
==== Testing CPPDEFINES, prepending a list to a dict
- orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, prepend = ['NAME1', 'NAME2']
+ orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, prepend = ['NAME1', 'NAME2', 'NAME3']
Prepend:
- result=['NAME2', 'NAME1', ('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
- final=-DNAME2 -DNAME1 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
+ result=['NAME3', 'NAME2', 'NAME1', ('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
+ final=-DNAME3 -DNAME2 -DNAME1 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
PrependUnique:
result=['NAME2', 'NAME1', ('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
final=-DNAME2 -DNAME1 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
==== Testing CPPDEFINES, prepending a tuple to a dict
- orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, prepend = ('NAME1', 'NAME2')
+ orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, prepend = ('NAME1', 'VAL1')
Prepend:
- result=['NAME2', 'NAME1', ('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
- final=-DNAME2 -DNAME1 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
+ result=[('NAME1', 'VAL1'), ('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
+ final=-DNAME1=VAL1 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
PrependUnique:
- result=['NAME2', 'NAME1', ('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
- final=-DNAME2 -DNAME1 -DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
+ result=[('NAME2', 'VAL2'), ('NAME3', None), ('NAME1', 'VAL1')]
+ final=-DNAME2=VAL2 -DNAME3 -DNAME1=VAL1
==== Testing CPPDEFINES, prepending a list-of-2lists to a dict
orig = {'NAME2': 'VAL2', 'NAME3': None, 'NAME1': 'VAL1'}, prepend = [('NAME1', 'VAL1'), ['NAME2', 'VAL2']]
Prepend: