Filed so this slightly confusing situation is recorded somewhere.
Handling of CPPDEFINES gets some special-casing. In Append and AppendUnique (but not, currently, in the Prepend cousins - see #3876) they get some special handling, and then, along with normal substitution and further processing (*ixes), they get processed by SCons.Defaults.processDefines(). The processDefines call is currently unique to the processing of _CPPDEFFLAGS.
One of the ways you can declare a C preprocessor macro of the form macro=value through CPPDEFINES is to use a tuple of length at least two; the first and second values are then combined by processDefines into that NAME=Value form. Unfortunately, it is not clearly specified whether a single tuple argument should have this effect, or only a tuple that is an element of an iterable, and so it's kind of hard to determine what is expected behavior.
- If
CPPDEFINES contains a single tuple (for example, by doing an Append to an uninitialized CPPDEFINES, although direct assignment, or initializing in the Environment call would have exactly the same effect), processDefines falls through to its "default" case, which is just to stringify the contents (l = [str(defs)]). Since we now have a single string, the eventual output of having a tuple like ("FOO", 2) is -D('FOO', 2), which is syntactically incorrect for both gcc-style compilers and msvc. We might expect either treating it as a macro=value tuple: -DFOO=2, or as simply an iterable of values just as if it were a list: -DFOO -D2.
- If you
Append a list value to CPPDEFINES containing a single tuple, the Append routine does some try/except magic and ends up inserting the tuple into the front of the list. Thus, we could have CPPDEFINES = [('FOO', 2), 'BAR', 'BAZ']. processDefines turns this into ['FOO=2', 'BAR', 'BAZ'], and the final expansion is -DFOO=2 -DBAR -DBAZ.
- On the other hand, if you try to
Append a single string value to CPPDEFINES containing a single tuple, it fails with AttributeError: 'str' object has no attribute 'insert' which is probably a surprise - you asked to "append" and you get a failure on "insert".
- If you
Append a tuple to any existing value, the macro=value form is assumed. Say we started with CPPDEFINES set to the string value "BAR". After the addition, we have CPPDEFINES = ['BAR', ('FOO', 2)]. processDefines turns this into ['BAR', 'FOO=2'], and as output we get -DBAR -DFOO=2.
- Meanwhile, if you
AppendUnique to a single tuple CPPDEFINES similar to 2) or 3) it fails with a TypeError. For example, if trying to add a list: TypeError: can only concatenate list (not "tuple") to list.
It's possible that the most "consistent" approach would be to treat a lone tuple as "just an iterable" and not as a special case, and activate the special macro=value handling only if the tuple is seen as an element of an iterable (usually a list). Such a change probably also has the highest chance of affecting existing build systems.
Filed so this slightly confusing situation is recorded somewhere.
Handling of
CPPDEFINESgets some special-casing. InAppendandAppendUnique(but not, currently, in thePrependcousins - see #3876) they get some special handling, and then, along with normal substitution and further processing (*ixes), they get processed bySCons.Defaults.processDefines(). TheprocessDefinescall is currently unique to the processing of_CPPDEFFLAGS.One of the ways you can declare a C preprocessor macro of the form macro=value through
CPPDEFINESis to use a tuple of length at least two; the first and second values are then combined byprocessDefinesinto thatNAME=Valueform. Unfortunately, it is not clearly specified whether a single tuple argument should have this effect, or only a tuple that is an element of an iterable, and so it's kind of hard to determine what is expected behavior.CPPDEFINEScontains a single tuple (for example, by doing anAppendto an uninitializedCPPDEFINES, although direct assignment, or initializing in theEnvironmentcall would have exactly the same effect),processDefinesfalls through to its "default" case, which is just to stringify the contents (l = [str(defs)]). Since we now have a single string, the eventual output of having a tuple like("FOO", 2)is-D('FOO', 2), which is syntactically incorrect for both gcc-style compilers and msvc. We might expect either treating it as a macro=value tuple:-DFOO=2, or as simply an iterable of values just as if it were a list:-DFOO -D2.Appenda list value toCPPDEFINEScontaining a single tuple, theAppendroutine does some try/except magic and ends up inserting the tuple into the front of the list. Thus, we could haveCPPDEFINES = [('FOO', 2), 'BAR', 'BAZ'].processDefinesturns this into['FOO=2', 'BAR', 'BAZ'], and the final expansion is-DFOO=2 -DBAR -DBAZ.Appenda single string value toCPPDEFINEScontaining a single tuple, it fails withAttributeError: 'str' object has no attribute 'insert'which is probably a surprise - you asked to "append" and you get a failure on "insert".Appenda tuple to any existing value, the macro=value form is assumed. Say we started withCPPDEFINESset to the string value"BAR". After the addition, we haveCPPDEFINES = ['BAR', ('FOO', 2)].processDefinesturns this into['BAR', 'FOO=2'], and as output we get-DBAR -DFOO=2.AppendUniqueto a single tupleCPPDEFINESsimilar to 2) or 3) it fails with aTypeError. For example, if trying to add a list:TypeError: can only concatenate list (not "tuple") to list.It's possible that the most "consistent" approach would be to treat a lone tuple as "just an iterable" and not as a special case, and activate the special macro=value handling only if the tuple is seen as an element of an iterable (usually a list). Such a change probably also has the highest chance of affecting existing build systems.