Add support for a platform-independent CPPDEFINES variable.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sat, 2 Aug 2003 04:21:04 +0000 (04:21 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sat, 2 Aug 2003 04:21:04 +0000 (04:21 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@757 fdb21ef1-2011-0410-befe-b5e4ea1792b1

14 files changed:
doc/man/scons.1
src/CHANGES.txt
src/engine/SCons/Defaults.py
src/engine/SCons/Tool/386asm.py
src/engine/SCons/Tool/as.py
src/engine/SCons/Tool/cc.py
src/engine/SCons/Tool/f77.py
src/engine/SCons/Tool/g++.py
src/engine/SCons/Tool/icc.py
src/engine/SCons/Tool/ifl.py
src/engine/SCons/Tool/masm.py
src/engine/SCons/Tool/msvc.py
src/engine/SCons/Tool/nasm.py
test/CPPDEFINES.py [new file with mode: 0644]

index a0a08d1bbeda7d5900c37b7799087a916241ec49..3f5e4d5b870c5733bc2197c2451b4269bfc593e3 100644 (file)
@@ -2304,12 +2304,98 @@ called to transform the list before concatenation.
 env['_CPPINCFLAGS'] = '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs)} $)',
 .EE
 
+.IP CPPDEFINES
+A platform independent specification of C preprocessor definitions.
+The definitions will be added to command lines
+through the automatically-generated
+$_CPPDEFFLAGS construction variable (see below),
+which is constructed according to
+the type of value of $CPPDEFINES:
+
+.IP
+If $CPPDEFINES is a string,
+the values of the
+$CPPDEFPREFIX and $CPPDEFSUFFIX
+construction variables
+will be added to the beginning and end.
+
+.ES
+# Will add -Dxyz to POSIX compiler command lines,
+# and /Dxyz to Microsoft Visual C++ command lines.
+env = Environment(CPPDEFINES='xyz')
+.EE
+
+.IP
+If $CPPDEFINES is a list,
+the values of the
+$CPPDEFPREFIX and $CPPDEFSUFFIX
+construction variables
+will be appended to the beginning and end
+of each element in the list.
+If any element is a list or tuple,
+then the first item is the name being
+defined and the second item is its value:
+
+.ES
+# Will add -DB=2 -DA to POSIX compiler command lines,
+# and /DB=2 /DA to Microsoft Visual C++ command lines.
+env = Environment(CPPDEFINES=[('B', 2), 'A'])
+.EE
+
+.IP
+If $CPPDEFINES is a dictionary,
+the values of the
+$CPPDEFPREFIX and $CPPDEFSUFFIX
+construction variables
+will be appended to the beginning and end
+of each item from the dictionary.
+The key of each dictionary item
+is a name being defined
+to the dictionary item's corresponding value;
+if the value is
+.BR None ,
+then the name is defined without an explicit value.
+Note that the resulting flags are sorted by keyword
+to ensure that the order of the options on the
+command line is consistent each time
+.B scons
+ is run.
+
+.ES
+# Will add -DA -DB=2 to POSIX compiler command lines,
+# and /DA /DB=2 to Microsoft Visual C++ command lines.
+env = Environment(CPPDEFINES={'B':2, 'A':None})
+.EE
+
+.IP _CPPDEFFLAGS
+An automatically-generated construction variable
+containing the C preprocessor command-line options
+to define values.
+The value of $_CPPDEFFLAGS is created
+by appending $CPPDEFPREFIX and $CPPDEFSUFFIX
+to the beginning and end
+of each directory in $CPPDEFINES.
+
+.IP CPPDEFPREFIX
+The prefix used to specify preprocessor definitions
+on the C compiler command line.
+This will be appended to the beginning of each definition
+in the $CPPDEFINES construction variable
+when the $_CPPDEFFLAGS variable is automatically generated.
+
+.IP CPPDEFSUFFIX
+The suffix used to specify preprocessor definitions
+on the C compiler command line.
+This will be appended to the end of each definition
+in the $CPPDEFINES construction variable
+when the $_CPPDEFFLAGS variable is automatically generated.
+
 .IP CPPFLAGS
 User-specified C preprocessor options.
 These will be included in any command that uses the C preprocessor,
 including not just compilation of C and C++ source files
 via the $CCCOM, $SHCCCOM, $CXXCOM and $SHCXXCOM command lines,
-but also the $F77PPCOM command line
+but also the $F77PPCOM and $SHF77PPCOM command lines
 used to compile a Fortran source file,
 and the $ASPPCOM command line
 used to assemble an assembly language source file,
index babc0f34a7c79bb6327e88ec3bff11f4d83dfd28..acf7e8880816e66bb32bbc28383964dc9b636de6 100644 (file)
@@ -97,6 +97,10 @@ RELEASE 0.XX - XXX
   - When the -debug=pdb option is specified, use pdb.Pdb().runcall() to
     call pdb directly, don't call Python recursively.
 
+  From Ben Scott:
+
+  - Add support for a platform-independent CPPDEFINES variable.
+
   From Christoph Wiedemann:
 
   - Have the g++ Tool actually use g++ in preference to c++.
index 4d7933bf8d1c48c029bcb5279918264108dc7d54..87420aa098169bece035e2c21afae3409f748c02 100644 (file)
@@ -41,6 +41,7 @@ import os.path
 import shutil
 import stat
 import string
+import types
 
 import SCons.Action
 import SCons.Builder
@@ -210,6 +211,37 @@ def _stripixes(prefix, list, suffix, stripprefix, stripsuffix, env, c=_concat):
         return ret
     return c(prefix, list, suffix, env, f)
 
+def _defines(prefix, defs, suffix, env, c=_concat):
+    """A wrapper around _concat that turns a list or string
+    into a list of C preprocessor command-line definitions.
+    """
+    if SCons.Util.is_List(defs):
+        l = []
+        for d in defs:
+            if SCons.Util.is_List(d) or type(d) is types.TupleType:
+                l.append(str(d[0]) + '=' + str(d[1]))
+            else:
+                l.append(str(d))
+    elif SCons.Util.is_Dict(defs):
+        # The items in a dictionary are stored in random order, but
+        # if the order of the command-line options changes from
+        # invocation to invocation, then the signature of the command
+        # line will change and we'll get random unnecessary rebuilds.
+        # Consequently, we have to sort the keys to ensure a
+        # consistent order...
+        l = []
+        keys = defs.keys()
+        keys.sort()
+        for k in keys:
+            v = defs[k]
+            if v is None:
+                l.append(str(k))
+            else:
+                l.append(str(k) + '=' + str(v))
+    else:
+        l = [str(defs)]
+    return c(prefix, l, suffix, env)
+    
 class NullCmdGenerator:
     """This is a callable class that can be used in place of other
     command generators if you don't want them to do anything.
@@ -238,10 +270,12 @@ ConstructionEnvironment = {
     'ENV'        : {},
     'INSTALL'    : copyFunc,
     '_concat'     : _concat,
+    '_defines'    : _defines,
     '_stripixes'  : _stripixes,
     '_LIBFLAGS'    : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
     '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs)} $)',
     '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs)} $)',
     '_F77INCFLAGS' : '$( ${_concat(INCPREFIX, F77PATH, INCSUFFIX, __env__, RDirs)} $)',
+    '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
     'TEMPFILE'     : NullCmdGenerator
     }
index 5681534eed15478d54cb58e57215322935865cd2..7a18a406ef61b41cf8f0b1128c6e2705a4552af6 100644 (file)
@@ -44,7 +44,7 @@ def generate(env):
     env['AS']        = '386asm'
     env['ASFLAGS']   = ''
     env['ASCOM']     = '$AS $ASFLAGS $SOURCES -o $TARGET'
-    env['ASPPCOM']   = '$CC $ASFLAGS $CPPFLAGS $SOURCES -o $TARGET'
+    env['ASPPCOM']   = '$CC $ASFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $SOURCES -o $TARGET'
 
     addPharLapPaths(env)
 
index ba33182b15335bc79a34986edb74ce38033ebf31..068648982487a9f0f379b45083d23bd5b45e26db 100644 (file)
@@ -61,7 +61,7 @@ def generate(env):
     env['AS']        = env.Detect(assemblers) or 'as'
     env['ASFLAGS']   = ''
     env['ASCOM']     = '$AS $ASFLAGS -o $TARGET $SOURCES'
-    env['ASPPCOM']   = '$CC $ASFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
+    env['ASPPCOM']   = '$CC $ASFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
 
 def exists(env):
     return env.Detect(assemblers)
index a414590296ce33077fb52d0a56e62976236ec74b..1d37e46e8fc33cc5067d86db8527d242d6966df1 100644 (file)
@@ -61,18 +61,20 @@ def generate(env):
         
     env['CC']        = 'cc'
     env['CCFLAGS']   = ''
-    env['CCCOM']     = '$CC $CCFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
+    env['CCCOM']     = '$CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
     env['SHCC']      = '$CC'
     env['SHCCFLAGS'] = '$CCFLAGS'
-    env['SHCCCOM']   = '$SHCC $SHCCFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
+    env['SHCCCOM']   = '$SHCC $SHCCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
 
     env['CXX']        = 'c++'
     env['CXXFLAGS']   = '$CCFLAGS'
-    env['CXXCOM']     = '$CXX $CXXFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
+    env['CXXCOM']     = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
     env['SHCXX']      = '$CXX'
     env['SHCXXFLAGS'] = '$CXXFLAGS'
-    env['SHCXXCOM']   = '$SHCXX $SHCXXFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
+    env['SHCXXCOM']   = '$SHCXX $SHCXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
 
+    env['CPPDEFPREFIX']  = '-D'
+    env['CPPDEFSUFFIX']  = ''
     env['INCPREFIX']  = '-I'
     env['INCSUFFIX']  = ''
     env['SHOBJSUFFIX'] = '.os'
index 3d4852adb90efb0845c1346ef8ef86a3f86f218e..c99bd219d0b6abe5a344a6873193597a46b0739c 100644 (file)
@@ -63,11 +63,11 @@ def generate(env):
     env['F77']        = env.Detect(compilers) or 'f77'
     env['F77FLAGS']   = ''
     env['F77COM']     = '$F77 $F77FLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES'
-    env['F77PPCOM']   = '$F77 $F77FLAGS $CPPFLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES'
+    env['F77PPCOM']   = '$F77 $F77FLAGS $CPPFLAGS $_CPPDEFFLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES'
     env['SHF77']      = '$F77'
     env['SHF77FLAGS'] = '$F77FLAGS'
     env['SHF77COM']   = '$SHF77 $SHF77FLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES'
-    env['SHF77PPCOM'] = '$SHF77 $SHF77FLAGS $CPPFLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES'
+    env['SHF77PPCOM'] = '$SHF77 $SHF77FLAGS $CPPFLAGS $_CPPDEFFLAGS $_F77INCFLAGS -c -o $TARGET $SOURCES'
 
 def exists(env):
     return env.Detect(compilers)
index 6497fe2b20aefa14e8c343b7610ba73da08db0df..8c7f1b0992f3d259609bf3a6ea3b87f74d080b4b 100644 (file)
@@ -52,13 +52,15 @@ def generate(env):
 
     env['CXX']        = env.Detect(compilers) or 'g++'
     env['CXXFLAGS']   = '$CCFLAGS'
-    env['CXXCOM']     = '$CXX $CXXFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
+    env['CXXCOM']     = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
     env['SHCXX']      = '$CXX'
     if env['PLATFORM'] == 'cygwin':
         env['SHCXXFLAGS'] = '$CXXFLAGS'
     else:
         env['SHCXXFLAGS'] = '$CXXFLAGS -fPIC'
-    env['SHCXXCOM']   = '$SHCXX $SHCXXFLAGS $CPPFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
+    env['SHCXXCOM']   = '$SHCXX $SHCXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
+    env['CPPDEFPREFIX']  = '-D'
+    env['CPPDEFSUFFIX']  = ''
     env['INCPREFIX']  = '-I'
     env['INCSUFFIX']  = ''
 
index 42a179e94aa34c4ac5fe34f009321155ffc6d6bb..20bf17ced9440831e4d7cb8d9f12bdb2dbcce6c9 100644 (file)
@@ -40,9 +40,12 @@ def generate(env):
     cc.generate(env)
 
     env['CC']         = 'icc'
-    env['CCCOM']      = '$CC $CCFLAGS $CPPFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET'
-    env['CXXCOM']     = '$CXX $CXXFLAGS $CPPFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET'
+    env['CCCOM']      = '$CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET'
+    env['CXXCOM']     = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET'
+    env['CPPDEFPREFIX']  = '/D'
+    env['CPPDEFSUFFIX']  = ''
     env['INCPREFIX']  = '/I'
+    env['INCSUFFIX']  = ''
     env['CFILESUFFIX'] = '.c'
     env['CXXFILESUFFIX'] = '.cc'
 
index f8a8be883591825be578ae5bcdaf9a1e1d887f5a..1b0cd33dd0353a10ce219c7624d70d7bc318451a 100644 (file)
@@ -42,11 +42,11 @@ def generate(env):
     env['F77']        = 'ifl'
     env['F77FLAGS']   = ''
     env['F77COM']     = '$F77 $F77FLAGS $_F77INCFLAGS /c $SOURCES /Fo$TARGET'
-    env['F77PPCOM']   = '$F77 $F77FLAGS $CPPFLAGS $_F77INCFLAGS /c $SOURCES /Fo$TARGET'
+    env['F77PPCOM']   = '$F77 $F77FLAGS $CPPFLAGS $_CPPDEFFLAGS $_F77INCFLAGS /c $SOURCES /Fo$TARGET'
     env['SHF77']      = '$F77'
     env['SHF77FLAGS'] = '$F77FLAGS'
     env['SHF77COM']   = '$SHF77 $SHF77FLAGS $_F77INCFLAGS /c $SOURCES /Fo$TARGET'
-    env['SHF77PPCOM'] = '$SHF77 $SHF77FLAGS $CPPFLAGS $_F77INCFLAGS /c $SOURCES /Fo$TARGET'
+    env['SHF77PPCOM'] = '$SHF77 $SHF77FLAGS $CPPFLAGS $_CPPDEFFLAGS $_F77INCFLAGS /c $SOURCES /Fo$TARGET'
 
 def exists(env):
     return env.Detect('ifl')
index 0284c1dda2db5da38e5310bb844e1e202179c819..87570bd4e7044a5300cc6c020202d7f3813c816f 100644 (file)
@@ -60,7 +60,7 @@ def generate(env):
     env['AS']        = 'ml'
     env['ASFLAGS']   = '/nologo'
     env['ASCOM']     = '$AS $ASFLAGS /c /Fo$TARGET $SOURCES'
-    env['ASPPCOM']   = '$CC $ASFLAGS $CPPFLAGS /c /Fo$TARGET $SOURCES'
+    env['ASPPCOM']   = '$CC $ASFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c /Fo$TARGET $SOURCES'
     env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
 
 def exists(env):
index fc86ee121a8cbde54c5ee5104a6e59f6a14c7941..3d6f3ab43a2ec5841395a4895a0b33f0313d1f88 100644 (file)
@@ -374,7 +374,7 @@ def generate(env):
 
     env['CCPDBFLAGS'] = '${(PDB and "/Zi /Fd%s"%File(PDB)) or ""}'
     env['CCPCHFLAGS'] = '${(PCH and "/Yu%s /Fp%s"%(PCHSTOP or "",File(PCH))) or ""}'
-    env['CCCOMFLAGS'] = '$CPPFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET $CCPCHFLAGS $CCPDBFLAGS'
+    env['CCCOMFLAGS'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET $CCPCHFLAGS $CCPDBFLAGS'
     env['CC']         = 'cl'
     env['CCFLAGS']    = '/nologo'
     env['CCCOM']      = '$CC $CCFLAGS $CCCOMFLAGS' 
@@ -387,6 +387,8 @@ def generate(env):
     env['SHCXX']      = '$CXX'
     env['SHCXXFLAGS'] = '$CXXFLAGS'
     env['SHCXXCOM']   = '$SHCXX $SHCXXFLAGS $CCCOMFLAGS'
+    env['CPPDEFPREFIX']  = '/D'
+    env['CPPDEFSUFFIX']  = ''
     env['INCPREFIX']  = '/I'
     env['INCSUFFIX']  = ''
     env['OBJEMITTER'] = object_emitter
@@ -394,7 +396,7 @@ def generate(env):
 
     env['RC'] = 'rc'
     env['RCFLAGS'] = ''
-    env['RCCOM'] = '$RC $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES'
+    env['RCCOM'] = '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES'
     CScan = env.get_scanner('.c')
     if CScan:
         CScan.add_skey('.rc')
@@ -419,7 +421,7 @@ def generate(env):
     env['CFILESUFFIX'] = '.c'
     env['CXXFILESUFFIX'] = '.cc'
 
-    env['PCHCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPINCFLAGS /c $SOURCES /Fo${TARGETS[1]} /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS'
+    env['PCHCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo${TARGETS[1]} /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS'
     env['BUILDERS']['PCH'] = pch_builder
 
 def exists(env):
index 1a9a8d56644f77d072bf3e2935cb6d3ebc15673a..ed2feba9f44838cdaa1787defb56977a6942d60a 100644 (file)
@@ -58,7 +58,7 @@ def generate(env):
     env['AS']        = 'nasm'
     env['ASFLAGS']   = ''
     env['ASCOM']     = '$AS $ASFLAGS -o $TARGET $SOURCES'
-    env['ASPPCOM']   = '$CC $ASFLAGS $CPPFLAGS -c -o $TARGET $SOURCES'
+    env['ASPPCOM']   = '$CC $ASFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
 
 def exists(env):
     return env.Detect('nasm')
diff --git a/test/CPPDEFINES.py b/test/CPPDEFINES.py
new file mode 100644 (file)
index 0000000..b8e08f8
--- /dev/null
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+XXX Put a description of the test here.
+"""
+
+import string
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+# Make sure $_CPPDEFFLAGS doesn't barf when CPPDEFINES isn't defined.
+test.write('SConstruct', """\
+env = Environment()
+print env.subst('$_CPPDEFFLAGS')
+""")
+
+expect = test.wrap_stdout(build_str="scons: `.' is up to date.\n", 
+                          read_str = "\n")
+
+test.run(arguments = '.', stdout=expect)
+
+# Test CPPDEFINES as a string and a list.
+test.write('SConstruct', """\
+test_list = [
+    'xyz',
+    ['x', 'y', 'z'],
+    ['x', ['y', 123], 'z'],
+    { 'c' : 3, 'b': None, 'a' : 1 },
+]
+env = Environment(CPPDEFPREFIX='-D', CPPDEFSUFFIX='')
+for i in test_list:
+    print env.Copy(CPPDEFINES=i).subst('$_CPPDEFFLAGS')
+env = Environment(CPPDEFPREFIX='|', CPPDEFSUFFIX='|')
+for i in test_list:
+    print env.Copy(CPPDEFINES=i).subst('$_CPPDEFFLAGS')
+""")
+
+expect = test.wrap_stdout(build_str="scons: `.' is up to date.\n", 
+                          read_str = """\
+-Dxyz
+-Dx -Dy -Dz
+-Dx -Dy=123 -Dz
+-Da=1 -Db -Dc=3
+|xyz|
+|x| |y| |z|
+|x| |y=123| |z|
+|a=1| |b| |c=3|
+""")
+
+test.run(arguments = '.', stdout=expect)
+
+test.write('SConstruct', """\
+foo = Environment(CPPDEFINES = ['FOO', ('VAL', 7)])
+bar = Environment(CPPDEFINES = {'BAR':None, 'VAL':8})
+f = foo.Object(target = 'foo', source = 'prog.c')
+b = bar.Object(target = 'bar', source = 'prog.c')
+foo.Program(target = 'foo', source = f)
+bar.Program(target = 'bar', source = b)
+""")
+
+test.write('prog.c', r"""
+int
+main(int argc, char *argv[])
+{
+       argv[argc++] = "--";
+#ifdef FOO
+       printf("prog.c:  FOO %d\n", VAL);
+#endif
+#ifdef BAR
+       printf("prog.c:  BAR %d\n", VAL);
+#endif
+       exit (0);
+}
+""")
+
+
+test.run(arguments = '.')
+
+test.run(program = test.workpath('foo'), stdout = "prog.c:  FOO 7\n")
+test.run(program = test.workpath('bar'), stdout = "prog.c:  BAR 8\n")
+
+test.pass_test()