Bring CVS back in sync.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 17 Nov 2005 14:23:07 +0000 (14:23 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 17 Nov 2005 14:23:07 +0000 (14:23 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@1390 fdb21ef1-2011-0410-befe-b5e4ea1792b1

97 files changed:
SConstruct
bin/SConsDoc.py
bin/scons-proc.py
doc/SConscript
doc/man/scons.1
src/engine/SCons/Action.xml
src/engine/SCons/Builder.py
src/engine/SCons/BuilderTests.py
src/engine/SCons/Defaults.xml
src/engine/SCons/Environment.xml
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/FSTests.py
src/engine/SCons/Node/NodeTests.py
src/engine/SCons/Node/__init__.py
src/engine/SCons/Platform/__init__.xml
src/engine/SCons/Platform/posix.xml
src/engine/SCons/Platform/win32.xml
src/engine/SCons/Tool/386asm.xml
src/engine/SCons/Tool/BitKeeper.xml
src/engine/SCons/Tool/CVS.xml
src/engine/SCons/Tool/Perforce.xml
src/engine/SCons/Tool/RCS.xml
src/engine/SCons/Tool/SCCS.xml
src/engine/SCons/Tool/Subversion.xml
src/engine/SCons/Tool/__init__.xml
src/engine/SCons/Tool/aixc++.xml
src/engine/SCons/Tool/aixcc.xml
src/engine/SCons/Tool/aixf77.xml
src/engine/SCons/Tool/aixlink.xml
src/engine/SCons/Tool/applelink.xml
src/engine/SCons/Tool/ar.xml
src/engine/SCons/Tool/as.xml
src/engine/SCons/Tool/bcc32.xml
src/engine/SCons/Tool/c++.xml
src/engine/SCons/Tool/cc.xml
src/engine/SCons/Tool/cvf.xml
src/engine/SCons/Tool/default.xml
src/engine/SCons/Tool/dmd.xml
src/engine/SCons/Tool/dvipdf.xml
src/engine/SCons/Tool/dvips.xml
src/engine/SCons/Tool/f77.xml
src/engine/SCons/Tool/f90.xml
src/engine/SCons/Tool/f95.xml
src/engine/SCons/Tool/fortran.xml
src/engine/SCons/Tool/g++.xml
src/engine/SCons/Tool/g77.xml
src/engine/SCons/Tool/gas.xml
src/engine/SCons/Tool/gcc.xml
src/engine/SCons/Tool/gnulink.xml
src/engine/SCons/Tool/gs.xml
src/engine/SCons/Tool/hpc++.xml
src/engine/SCons/Tool/hpcc.xml
src/engine/SCons/Tool/hplink.xml
src/engine/SCons/Tool/icc.xml
src/engine/SCons/Tool/icl.xml
src/engine/SCons/Tool/ifl.xml
src/engine/SCons/Tool/ifort.xml
src/engine/SCons/Tool/ilink.xml
src/engine/SCons/Tool/ilink32.xml
src/engine/SCons/Tool/intelc.xml
src/engine/SCons/Tool/jar.xml
src/engine/SCons/Tool/javac.xml
src/engine/SCons/Tool/javah.xml
src/engine/SCons/Tool/latex.xml
src/engine/SCons/Tool/lex.xml
src/engine/SCons/Tool/link.xml
src/engine/SCons/Tool/linkloc.xml
src/engine/SCons/Tool/m4.xml
src/engine/SCons/Tool/masm.xml
src/engine/SCons/Tool/midl.xml
src/engine/SCons/Tool/mingw.xml
src/engine/SCons/Tool/mslib.xml
src/engine/SCons/Tool/mslink.xml
src/engine/SCons/Tool/msvc.xml
src/engine/SCons/Tool/msvs.xml
src/engine/SCons/Tool/mwcc.xml
src/engine/SCons/Tool/mwld.xml
src/engine/SCons/Tool/nasm.xml
src/engine/SCons/Tool/pdflatex.xml
src/engine/SCons/Tool/pdftex.xml
src/engine/SCons/Tool/qt.xml
src/engine/SCons/Tool/rmic.xml
src/engine/SCons/Tool/rpcgen.xml
src/engine/SCons/Tool/sgiar.xml
src/engine/SCons/Tool/sgic++.xml
src/engine/SCons/Tool/sgicc.xml
src/engine/SCons/Tool/sgilink.xml
src/engine/SCons/Tool/sunar.xml
src/engine/SCons/Tool/sunc++.xml
src/engine/SCons/Tool/suncc.xml
src/engine/SCons/Tool/sunlink.xml
src/engine/SCons/Tool/swig.xml
src/engine/SCons/Tool/tar.xml
src/engine/SCons/Tool/tex.xml
src/engine/SCons/Tool/tlib.xml
src/engine/SCons/Tool/yacc.xml
src/engine/SCons/Tool/zip.xml

index 9effc18adc57968bbb982f7a37a68785f5c1b7a0..7dfc9354dcbe97ae4a0ee0fc8913015c289441c8 100644 (file)
@@ -32,6 +32,7 @@ copyright_years = '2001, 2002, 2003, 2004'
 import distutils.util
 import os
 import os.path
+import re
 import socket
 import stat
 import string
@@ -247,6 +248,38 @@ def SCons_revision(target, source, env):
 revbuilder = Builder(action = Action(SCons_revision,
                                      varlist=['COPYRIGHT', 'VERSION']))
 
+def soelim(target, source, env):
+    """
+    Interpolate files included in [gnt]roff source files using the
+    .so directive.
+
+    This behaves somewhat like the soelim(1) wrapper around groff, but
+    makes us independent of whether the actual underlying implementation
+    includes an soelim() command or the corresponding command-line option
+    to groff(1).  The key behavioral difference is that this doesn't
+    recursively include .so files from the include file.  Not yet, anyway.
+    """
+    t = str(target[0])
+    s = str(source[0])
+    dir, f = os.path.split(s)
+    tfp = open(t, 'w')
+    sfp = open(s, 'r')
+    for line in sfp.readlines():
+        if line[:4] in ['.so ', "'so "]:
+            sofile = os.path.join(dir, line[4:-1])
+            tfp.write(open(sofile, 'r').read())
+        else:
+            tfp.write(line)
+    sfp.close()
+    tfp.close()
+
+def soscan(node, env, path):
+    c = node.get_contents()
+    return re.compile(r"^[\.']so\s+(\S+)", re.M).findall(c)
+
+soelimbuilder = Builder(action = Action(soelim),
+                        source_scanner = Scanner(soscan))
+
 # When copying local files from a Repository (Aegis),
 # just make copies, don't symlink them.
 SetOption('duplicate', 'copy')
@@ -285,7 +318,8 @@ env = Environment(
                    UNPACK_TAR_GZ_DIR   = unpack_tar_gz_dir,
                    UNPACK_ZIP_DIR      = unpack_zip_dir,
 
-                   BUILDERS            = { 'SCons_revision' : revbuilder },
+                   BUILDERS            = { 'SCons_revision' : revbuilder,
+                                           'SOElim' : soelimbuilder },
 
                    PYTHON              = sys.executable,
                    PYTHONFLAGS         = '-tt',
@@ -336,6 +370,8 @@ python_scons = {
                             'LICENSE.txt' : '../LICENSE.txt'
                           },
 
+        'buildermap'    : {},
+
         'explicit_deps' : {
                             'SCons/__init__.py' : Version_values,
                           },
@@ -374,6 +410,7 @@ python_scons = {
 #        'filemap'      : {
 #                            'LICENSE.txt' : '../LICENSE.txt',
 #                          },
+#        'buildermap'    : {},
 #}
 #
 
@@ -407,6 +444,8 @@ scons_script = {
                             'sconsign'          : 'sconsign.py',
                            },
 
+        'buildermap'    : {},
+
         'extra_rpm_files' : [
                             'scons-' + version,
                             'sconsign-' + version,
@@ -446,8 +485,13 @@ scons = {
                           ],
 
         'filemap'       : {
-                            'scons.1' : '../doc/man/scons.1',
-                            'sconsign.1' : '../doc/man/sconsign.1',
+                            'scons.1' : '../build/doc/man/scons.1',
+                            'sconsign.1' : '../build/doc/man/sconsign.1',
+                          },
+
+        'buildermap'    : {
+                            'scons.1' : env.SOElim,
+                            'sconsign.1' : env.SOElim,
                           },
 
         'subpkgs'       : [ python_scons, scons_script ],
@@ -562,7 +606,9 @@ for p in [ scons ]:
     #
     for b in src_files:
         s = p['filemap'].get(b, b)
-        env.SCons_revision(os.path.join(build, b), os.path.join(src, s))
+        builder = p['buildermap'].get(b, env.SCons_revision)
+        x = builder(os.path.join(build, b), os.path.join(src, s))
+        Local(x)
 
     #
     # NOW, finally, we can create the MANIFEST, which we do
index df28b76dbac8354edbdba6aa85e9446742de4ebc..57bf1d4d343b2f7aaefa5792de535b6b65471340 100644 (file)
@@ -2,6 +2,86 @@
 #
 # Module for handling SCons documentation processing.
 #
+
+__doc__ = """
+This module parses home-brew XML files that document various things
+in SCons.  Right now, it handles Builders, construction variables,
+and Tools, but we expect it to get extended in the future.
+
+In general, you can use any DocBook tag in the input, and this module
+just adds processing various home-brew tags to try to make life a
+little easier.
+
+Builder example:
+
+    <builder name="VARIABLE">
+    <summary>
+    This is the summary description of an SCons Tool.
+    It will get placed in the man page,
+    and in the appropriate User's Guide appendix.
+    The name of any builder may be interpolated
+    anywhere in the document by specifying the
+    &b-VARIABLE;
+    element.  It need not be on a line by itself.
+
+    Unlike normal XML, blank lines are significant in these
+    descriptions and serve to separate paragraphs.
+    They'll get replaced in DocBook output with appropriate tags
+    to indicate a new paragraph.
+
+    <example>
+    print "this is example code, it will be offset and indented"
+    </example>
+    </summary>
+    </builder>
+
+Construction variable example:
+
+    <cvar name="VARIABLE">
+    <summary>
+    This is the summary description of a construction variable.
+    It will get placed in the man page,
+    and in the appropriate User's Guide appendix.
+    The name of any construction variable may be interpolated
+    anywhere in the document by specifying the
+    &t-VARIABLE;
+    element.  It need not be on a line by itself.
+
+    Unlike normal XML, blank lines are significant in these
+    descriptions and serve to separate paragraphs.
+    They'll get replaced in DocBook output with appropriate tags
+    to indicate a new paragraph.
+
+    <example>
+    print "this is example code, it will be offset and indented"
+    </example>
+    </summary>
+    </cvar>
+
+Tool example:
+
+    <tool name="VARIABLE">
+    <summary>
+    This is the summary description of an SCons Tool.
+    It will get placed in the man page,
+    and in the appropriate User's Guide appendix.
+    The name of any tool may be interpolated
+    anywhere in the document by specifying the
+    &t-VARIABLE;
+    element.  It need not be on a line by itself.
+
+    Unlike normal XML, blank lines are significant in these
+    descriptions and serve to separate paragraphs.
+    They'll get replaced in DocBook output with appropriate tags
+    to indicate a new paragraph.
+
+    <example>
+    print "this is example code, it will be offset and indented"
+    </example>
+    </summary>
+    </tool>
+"""
+
 import os.path
 import imp
 import sys
index 809c3d04e1001a3934f7bc4285a4d5757b563f63..bf345a7c97ed2e3906897579e3ebfd416aa0f389 100644 (file)
@@ -2,10 +2,13 @@
 #
 # Process a list of Python and/or XML files containing SCons documentation.
 #
-# Depending on the options, this script creates DocBook-formatted lists
-# of the Builders, Tools or construction variables in generated SGML
-# files containing the summary text and/or .mod files contining the
-# ENTITY definitions for each item.
+# This script creates formatted lists of the Builders, Tools or
+# construction variables documented in the specified XML files.
+#
+# Dependening on the options, the lists are output in either
+# DocBook-formatted generated SGML files containing the summary text
+# and/or .mod files contining the ENTITY definitions for each item,
+# or in man-page-formatted output.
 #
 import getopt
 import os.path
@@ -20,25 +23,35 @@ import SConsDoc
 base_sys_path = [os.getcwd() + '/build/test-tar-gz/lib/scons'] + sys.path
 
 helpstr = """\
-Usage: scons-varlist.py [-b .gen,.mod] [-t .gen,.mod] [-v .gen,.mod] [infile]
+Usage: scons-varlist.py [--man|--sgml] \
+                        [-b file(s)] [-t file(s)] [-v file(s)] [infile ...]
 Options:
-  -m, --modfile               .mod file to hold Builder entities
+  -b file(s)        dump builder information to the specified file(s)
+  -t file(s)        dump tool information to the specified file(s)
+  -v file(s)        dump variable information to the specified file(s)
+  --man             print info in man page format, each -[btv] argument
+                    is a single file name
+  --sgml            (default) print info in SGML format, each -[btv] argument
+                    is a pair of comma-separated .gen,.mod file names
 """
 
 opts, args = getopt.getopt(sys.argv[1:],
                            "b:t:v:",
-                           ['builders=', 'tools=', 'variables='])
+                           ['builders=', 'man', 'sgml', 'tools=', 'variables='])
 
 buildersfiles = None
+output_type = '--sgml'
 toolsfiles = None
 variablesfiles = None
 
 for o, a in opts:
-    if o == '-b' or o == '--builders':
+    if o in ['-b', '--builders']:
         buildersfiles = a
-    elif o == '-t' or o == '--tools':
+    elif o in ['--man', '--sgml']:
+        output_type = o
+    elif o in ['-t', '--tools']:
         toolsfiles = a
-    elif o == '-v' or o == '--variables':
+    elif o in ['-v', '--variables']:
         variablesfiles = a
 
 h = SConsDoc.SConsDocHandler()
@@ -46,12 +59,12 @@ saxparser = xml.sax.make_parser()
 saxparser.setContentHandler(h)
 saxparser.setErrorHandler(h)
 
-preamble = """\
+xml_preamble = """\
 <?xml version="1.0"?>
 <scons_doc>
 """
 
-postamble = """\
+xml_postamble = """\
 </scons_doc>
 """
 
@@ -62,7 +75,7 @@ for f in args:
         if dir:
             sys.path = [dir] + base_sys_path
         module = SConsDoc.importfile(f)
-        h.set_file_info(f, len(preamble.split('\n')))
+        h.set_file_info(f, len(xml_preamble.split('\n')))
         try:
             content = module.__scons_doc__
         except AttributeError:
@@ -70,11 +83,11 @@ for f in args:
         else:
             del module.__scons_doc__
     else:
-        h.set_file_info(f, len(preamble.split('\n')))
+        h.set_file_info(f, len(xml_preamble.split('\n')))
         content = open(f).read()
     if content:
         content = content.replace('&', '&amp;')
-        input = preamble + content + postamble
+        input = xml_preamble + content + xml_postamble
         try:
             saxparser.parse(StringIO.StringIO(input))
         except:
@@ -103,17 +116,27 @@ Link_Entities_Header = """\
 -->
 """
 
-class XXX:
+class SCons_XML:
     def __init__(self, entries, **kw):
         values = entries.values()
         values.sort()
         self.values = values
         for k, v in kw.items():
             setattr(self, k, v)
+    def fopen(self, name):
+        if name == '-':
+            return sys.stdout
+        return open(name, 'w')
+
+class SCons_XML_to_SGML(SCons_XML):
+    def write(self, files):
+        gen, mod = string.split(files, ',')
+        g.write_gen(gen)
+        g.write_mod(mod)
     def write_gen(self, filename):
         if not filename:
             return
-        f = open(filename, 'w')
+        f = self.fopen(filename)
         for v in self.values:
             f.write('\n<varlistentry id="%s%s">\n' %
                         (self.prefix, self.idfunc(v.name)))
@@ -133,7 +156,7 @@ class XXX:
     def write_mod(self, filename):
         if not filename:
             return
-        f = open(filename, 'w')
+        f = self.fopen(filename)
         f.write(Warning)
         f.write('\n')
         f.write(Regular_Entities_Header % self.description)
@@ -155,8 +178,59 @@ class XXX:
         f.write('\n')
         f.write(Warning)
 
+class SCons_XML_to_man(SCons_XML):
+    def mansep(self):
+        return ['\n']
+    def initial_chunks(self, name):
+        return [name]
+    def write(self, filename):
+        if not filename:
+            return
+        f = self.fopen(filename)
+        chunks = []
+        for v in self.values:
+            chunks.extend(self.mansep())
+            for n in self.initial_chunks(v.name):
+                chunks.append('.IP %s\n' % n)
+            chunks.extend(map(str, v.summary.body))
+
+        body = ''.join(chunks)
+        body = string.replace(body, '<programlisting>', '.ES')
+        body = string.replace(body, '</programlisting>', '.EE')
+        body = string.replace(body, '\n</para>\n<para>\n', '\n\n')
+        body = string.replace(body, '<para>\n', '')
+        body = string.replace(body, '<para>', '\n')
+        body = string.replace(body, '</para>\n', '')
+        body = re.sub('\.EE\n\n+(?!\.IP)', '.EE\n.IP\n', body)
+        body = re.sub('&(scons|SConstruct|SConscript|jar);', r'\\fB\1\\fP', body)
+        body = string.replace(body, '&Dir;', r'\fBDir\fP')
+        body = re.sub('&b(-link)?-([^;]*);', r'\\fB\2\\fP()', body)
+        body = re.sub('&cv(-link)?-([^;]*);', r'$\2', body)
+        body = re.sub(r'<(command|envar|filename|literal|option)>([^<]*)</\1>',
+                      r'\\fB\2\\fP', body)
+        body = re.sub(r'<(classname|emphasis|varname)>([^<]*)</\1>',
+                      r'\\fI\2\\fP', body)
+        body = re.compile(r'^\\f([BI])(.*)\\fP\s*$', re.M).sub(r'.\1 \2', body)
+        body = re.compile(r'^\\f([BI])(.*)\\fP(\S+)', re.M).sub(r'.\1R \2 \3', body)
+        body = string.replace(body, '&lt;', '<')
+        body = string.replace(body, '&gt;', '>')
+        body = re.sub(r'\\([^f])', r'\\\\\1', body)
+        body = re.compile("^'\\\\\\\\", re.M).sub("'\\\\", body)
+        body = re.compile(r'^\.([BI]R?) -', re.M).sub(r'.\1 \-', body)
+        body = re.compile(r'^\.([BI]R?) (\S+)\\\\(\S+)', re.M).sub(r'.\1 "\2\\\\\\\\\2"', body)
+        body = re.compile(r'\\f([BI])-', re.M).sub(r'\\f\1\-', body)
+        f.write(body)
+
+if output_type == '--man':
+    processor_class = SCons_XML_to_man
+elif output_type == '--sgml':
+    processor_class = SCons_XML_to_SGML
+else:
+    sys.stderr.write("Unknown output type '%s'\n" % output_type)
+    sys.exit(1)
+
 if buildersfiles:
-    g = XXX(h.builders,
+    g = processor_class(h.builders,
             description = 'builder',
             prefix = 'b-',
             tag = 'function',
@@ -164,12 +238,13 @@ if buildersfiles:
             termfunc = lambda x: [x+'()', 'env.'+x+'()'],
             entityfunc = lambda x: x)
 
-    gen, mod = string.split(buildersfiles, ',')
-    g.write_gen(gen)
-    g.write_mod(mod)
+    g.mansep = lambda: ['\n', "'\\" + '"'*69 + '\n']
+    g.initial_chunks = lambda n: [n+'()', 'env.'+n+'()']
+
+    g.write(buildersfiles)
 
 if toolsfiles:
-    g = XXX(h.tools,
+    g = processor_class(h.tools,
             description = 'tool',
             prefix = 't-',
             tag = 'literal',
@@ -177,12 +252,10 @@ if toolsfiles:
             termfunc = lambda x: [x],
             entityfunc = lambda x: x)
 
-    gen, mod = string.split(toolsfiles, ',')
-    g.write_gen(gen)
-    g.write_mod(mod)
+    g.write(toolsfiles)
 
 if variablesfiles:
-    g = XXX(h.cvars,
+    g = processor_class(h.cvars,
             description = 'construction variable',
             prefix = 'cv-',
             tag = 'envar',
@@ -190,6 +263,4 @@ if variablesfiles:
             termfunc = lambda x: [x],
             entityfunc = lambda x: '$'+x)
 
-    gen, mod = string.split(variablesfiles, ',')
-    g.write_gen(gen)
-    g.write_mod(mod)
+    g.write(variablesfiles)
index a51dd796f2dbfa68e4b1cfc4af6654be43aa0fbb..3fc327fa13bb2b5d53df8067ea9b39bed524394d 100644 (file)
@@ -164,11 +164,12 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE.  DO NOT EDIT.
     # to rebuild documentation just because it's found in one location
     # vs. the other.  The *.gen and *.mod targets will still be dependent
     # on the list of the files themselves.
-    b = env.Command([builders_gen, builders_mod,
-                     tools_gen, tools_mod,
-                     variables_gen, variables_mod],
+    doc_output_files = [builders_gen, builders_mod,
+                        tools_gen, tools_mod,
+                        variables_gen, variables_mod]
+    b = env.Command(doc_output_files,
                     scons_doc_files,
-                    "python $SCONS_PROC_PY -b ${TARGETS[0]},${TARGETS[1]} -t ${TARGETS[2]},${TARGETS[3]} -v ${TARGETS[4]},${TARGETS[5]} $( $SOURCES $)")
+                    "python $SCONS_PROC_PY --sgml -b ${TARGETS[0]},${TARGETS[1]} -t ${TARGETS[2]},${TARGETS[3]} -v ${TARGETS[4]},${TARGETS[5]} $( $SOURCES $)")
     env.Depends(b, "$SCONS_PROC_PY")
 
     env.Local(b)
@@ -375,20 +376,39 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE.  DO NOT EDIT.
 #
 # Man page(s), in good ol' troff format.
 #
-man_page_list = ['scons', 'sconsign']
+man_page_list = ['scons.1', 'sconsign.1']
 
-for man in man_page_list:
-    man_1 = os.path.join('man', '%s.1' % man)
+for m in man_page_list:
+    orig_env.SCons_revision(os.path.join(build, 'man', m),
+                            os.path.join('man', m))
+
+man_intermediate_files = ['builders.man', 'tools.man', 'variables.man']
+
+man_intermediate_files = map(lambda x: os.path.join(build, 'man', x),
+                             man_intermediate_files)
+
+cmd = "python $SCONS_PROC_PY --man -b ${TARGETS[0]} -t ${TARGETS[1]} -v ${TARGETS[2]} $( $SOURCES $)"
+man_intermediate_files = env.Command(man_intermediate_files,
+                                     scons_doc_files,
+                                     cmd)
+env.Depends(man_intermediate_files, "$SCONS_PROC_PY")
+
+for man_1 in man_page_list:
+    man, _1 = os.path.splitext(man_1)
+
+    man_1 = os.path.join(build, 'man', man_1)
 
     if groff:
         ps = os.path.join(build, 'PS', '%s-man.ps' % man)
         text = os.path.join(build, 'TEXT', '%s-man.txt' % man)
 
-        env.Command(ps, man_1, "groff -man -Tps $SOURCES > $TARGET")
+        b = env.Command(ps, man_1, "( cd ${SOURCES.dir} && groff -man -Tps ${SOURCES.file} ) > $TARGET")
         Local(ps)
+        env.Depends(b, man_intermediate_files)
 
-        env.Command(text, man_1, "groff -man -Tascii $SOURCES > $TARGET")
+        b = env.Command(text, man_1, "( cd ${SOURCES.dir} && groff -man -Tascii ${SOURCES.file} ) > $TARGET")
         Local(text)
+        env.Depends(b, man_intermediate_files)
 
         tar_deps.extend([ps, text])
         tar_list.extend([ps, text])
@@ -396,11 +416,12 @@ for man in man_page_list:
     if man2html:
         html = os.path.join(build, 'HTML' , '%s-man.html' % man)
 
-        cmds = [ "man2html $SOURCES > $TARGET" ]
+        cmds = [ "( cd ${SOURCES.dir} && man2html ${SOURCES.dir} ) > $TARGET" ]
         if tidy:
             cmds.append("tidy -m -q $TARGET || true")
-        env.Command(html, man_1, cmds)
+        b = env.Command(html, man_1, cmds)
         Local(html)
+        env.Depends(b, man_intermediate_files)
 
         tar_deps.append(html)
         tar_list.append(html)
index b94d680e508fd09e99e3d3c77e09cf334293b889..b5199be79bcfdca437504afa95e7081effedc9c5 100644 (file)
@@ -31,7 +31,7 @@
 .fi
 .RE
 ..
-.TH SCONS 1 "October 2004"
+.TH SCONS 1 "October 2005"
 .SH NAME
 scons \- a software construction tool
 .SH SYNOPSIS
@@ -149,6 +149,28 @@ import os
 env = Environment(ENV = {'PATH' : os.environ['PATH']})
 .EE
 
+Similarly, if the commands use external environment variables
+like $PATH, $HOME, $JAVA_HOME, $LANG, $SHELL, $TERM, etc.,
+these variables can also be explicitly propagated:
+
+.ES
+import os
+env = Environment(ENV = {'PATH' : os.environ['PATH'],
+                         'HOME' : os.environ['HOME']})
+.EE
+
+Or you may explicitly propagate the invoking user's
+complete external environment:
+
+.ES
+import os
+env = Environment(ENV = os.environ['PATH'])
+.EE
+
+This comes at the expense of making your build
+dependent on the user's environment being set correctly,
+but it may be more convenient for many configurations.
+
 .B scons
 can scan known input files automatically for dependency
 information (for example, #include statements
@@ -510,8 +532,10 @@ specifies what type of debugging:
 
 .TP
 --debug=count
-Print a count of how many objects are created
-of the various classes used internally by SCons.
+Print how many objects are created
+of the various classes used internally by SCons
+before and after reading the SConscript files
+and before and after building targets.
 This only works when run under Python 2.1 or later.
 
 .TP
@@ -519,6 +543,16 @@ This only works when run under Python 2.1 or later.
 Print the dependency tree
 after each top-level target is built. This prints out only derived files.
 
+.TP
+--debug=explain
+Print an explanation of precisely why
+.B scons
+is deciding to (re-)build any targets.
+(Note:  this does not print anything
+for targets that are
+.I not
+rebuilt.)
+
 .TP
 --debug=findlibs
 Instruct the scanner that searches for libraries
@@ -536,11 +570,34 @@ of a given derived file:
 $ scons --debug=includes foo.o
 .EE
 
+.TP
+--debug=memoizer
+Prints a summary of hits and misses in the Memoizer,
+the internal SCons subsystem for caching
+various values in memory instead of
+recomputing them each time they're needed.
+
 .TP
 --debug=memory
 Prints how much memory SCons uses
 before and after reading the SConscript files
-and before and after building.
+and before and after building targets.
+
+.TP
+--debug=nomemoizer
+Disables use of the Memoizer,
+the internal SCons subsystem for caching
+various values in memory instead of
+recomputing them each time they're needed.
+This provides more accurate counts of the
+underlying function calls in the 
+Python profiler output when using the
+.RI --profile=
+option.
+(When the Memoizer is used,
+the profiler counts all
+memoized functions as being executed
+by the Memoizer's wrapper calls.)
 
 .TP
 --debug=objects
@@ -553,7 +610,6 @@ This only works when run under Python 2.1 or later.
 Re-run SCons under the control of the
 .RI pdb
 Python debugger.
-.EE
 
 .TP
 --debug=presub
@@ -573,6 +629,12 @@ Building myprog.o with action(s):
 Prints an internal Python stack trace
 when encountering an otherwise unexplained error.
 
+.TP
+--debug=stree
+Print the dependency tree along with status information.  This is the
+same as the debug=tree option, but additional status information is
+provided for each node in the tree.
+
 .TP
 --debug=time
 Prints various time profiling information: the time spent
@@ -587,6 +649,47 @@ after each top-level target is built. This prints out the complete
 dependency tree including implicit dependencies and ignored
 dependencies.
 
+.TP
+.RI --diskcheck= types
+Enable specific checks for
+whether or not there is a file on disk
+where the SCons configuration expects a directory
+(or vice versa),
+and whether or not RCS or SCCS sources exist
+when searching for source and include files.
+The
+.I types
+argument can be set to:
+.BR all ,
+to enable all checks explicitly
+(the default behavior);
+.BR none ,
+to disable all such checks;
+.BR match ,
+to check that files and directories on disk
+match SCons' expected configuration;
+.BR rcs ,
+to check for the existence of an RCS source
+for any missing source or include files;
+.BR sccs ,
+to check for the existence of an SCCS source
+for any missing source or include files.
+Multiple checks can be specified separated by commas;
+for example,
+.B --diskcheck=sccs,rcs
+would still check for SCCS and RCS sources,
+but disable the check for on-disk matches of files and directories.
+Disabling some or all of these checks
+can provide a performance boost for large configurations,
+or when the configuration will check for files and/or directories
+across networked or shared file systems,
+at the slight increased risk of an incorrect build
+or of not handling errors gracefully
+(if include files really should be
+found in SCCS or RCS, for example,
+or if a file really does exist
+where the SCons configuration expects a directory).
+
 .\" .TP
 .\" -e, --environment-overrides
 .\" Variables from the execution environment override construction
@@ -724,12 +827,18 @@ Ignored for compatibility with non-GNU versions of
 .RI --max-drift= SECONDS
 Set the maximum expected drift in the modification time of files to 
 .IR SECONDS .
-This value determines how old a file must be before its content signature
-is cached. The default value is 2 days, which means a file must have a
-modification time of at least two days ago in order to have its content
-signature cached. A negative value means to never cache the content
+This value determines how long a file must be unmodified
+before its cached content signature
+will be used instead of
+calculating a new content signature (MD5 checksum)
+of the file's contents.
+The default value is 2 days, which means a file must have a
+modification time of at least two days ago in order to have its
+cached content signature used.
+A negative value means to never cache the content
 signature and to ignore the cached value if there already is one. A value
-of 0 means to always cache the signature, no matter how old the file is.
+of 0 means to always use the cached signature,
+no matter how old the file is.
 
 .TP
 -n, --just-print, --dry-run, --recon
@@ -951,8 +1060,10 @@ and suffixes appropriate for the platform.
 Note that the
 .B win32
 platform adds the
+.B SYSTEMDRIVE
+and
 .B SYSTEMROOT
-variable from the user's external environment
+variables from the user's external environment
 to the construction environment's
 .B ENV
 dictionary.
@@ -995,7 +1106,7 @@ have two functions: generate(env, **kw) and exists(env).
 The
 .B generate()
 function
-modifies the passed in environment
+modifies the passed-in environment
 to set up variables so that the tool
 can be executed;
 it may use any keyword arguments
@@ -1008,6 +1119,19 @@ value if the tool is available.
 Tools in the toolpath are used before
 any of the built-in ones.  For example, adding gcc.py to the toolpath
 would override the built-in gcc tool.
+Also note that the toolpath is
+stored in the environment for use
+by later calls to
+.BR Copy ()
+and
+.BR Tool ()
+methods:
+
+.ES
+base = Environment(toolpath=['custom_path'])
+derived = base.Copy(tools=['custom_tool'])
+derived.CustomBuilder()
+.EE
 
 The elements of the tools list may also
 be functions or callable objects,
@@ -1097,6 +1221,7 @@ ifl
 ifort
 ilink
 ilink32
+intelc
 jar
 javac
 javah
@@ -1112,6 +1237,8 @@ mslib
 mslink
 msvc
 msvs
+mwcc
+mwld
 nasm
 pdflatex
 pdftex
@@ -1248,6 +1375,15 @@ environment that consists of the tools and values that
 .B scons
 has determined are appropriate for the local system.
 
+Builder methods that can be called without an explicit
+environment may be called from custom Python modules that you
+import into an SConscript file by adding the following
+to the Python module:
+
+.ES
+from SCons.Script import *
+.EE
+
 All builder methods return a list of Nodes
 that represent the target or targets that will be built.
 A
@@ -1266,7 +1402,7 @@ to add a specific
 flag when compiling one specific object file:
 
 .ES
-bar_obj_list = env.StaticObject('bar.c', CCFLAGS='-DBAR')
+bar_obj_list = env.StaticObject('bar.c', CPPDEFINES='-DBAR')
 env.Program(source = ['foo.c', bar_obj_list, 'main.c'])
 .EE
 
@@ -1313,7 +1449,7 @@ by passing the Node to the Python-builtin
 function:
 
 .ES
-bar_obj_list = env.StaticObject('bar.c', CCFLAGS='-DBAR')
+bar_obj_list = env.StaticObject('bar.c', CPPDEFINES='-DBAR')
 print "The path to bar_obj is:", str(bar_obj_list[0])
 .EE
 
@@ -1385,756 +1521,50 @@ targets and source.
 provides the following builder methods:
 
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP CFile()
-.IP env.CFile()
-Builds a C source file given a lex (.l) or yacc (.y) input file.
-The suffix specified by the $CFILESUFFIX construction variable
-(.c by default)
-is automatically added to the target
-if it is not already present. Example:
-
-.ES
-# builds foo.c
-env.CFile(target = 'foo.c', source = 'foo.l')
-# builds bar.c
-env.CFile(target = 'bar', source = 'bar.y')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP CXXFile()
-.IP env.CXXFile()
-Builds a C++ source file given a lex (.ll) or yacc (.yy)
-input file.
-The suffix specified by the $CXXFILESUFFIX construction variable
-(.cc by default)
-is automatically added to the target
-if it is not already present. Example:
-
-.ES
-# builds foo.cc
-env.CXXFile(target = 'foo.cc', source = 'foo.ll')
-# builds bar.cc
-env.CXXFile(target = 'bar', source = 'bar.yy')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP DVI()
-.IP env.DVI()
-Builds a .dvi file from a .tex, .ltx or .latex input file.
-If the source file suffix is .tex,
-.B scons
-will examine the contents of the file;
-if the string
-.B \\documentclass
-or
-.B \\documentstyle
-is found, the file is assumed to be a LaTeX file and
-the target is built by invoking the $LATEXCOM command line;
-otherwise, the $TEXCOM command line is used.
-If the file is a LaTeX file,
-the
-.B DVI
-builder method will also examine the contents
-of the
-.B .aux file
-and invoke the $BIBTEX command line
-if the string
-.B bibdata
-is found,
-and will examine the contents
-.B .log
-file and re-run the $LATEXCOM command
-if the log file says it is necessary.
-
-The suffix .dvi
-(hard-coded within TeX itself)
-is automatically added to the target
-if it is not already present. Examples:
-
-.ES
-# builds from aaa.tex
-env.DVI(target = 'aaa.dvi', source = 'aaa.tex')
-# builds bbb.dvi
-env.DVI(target = 'bbb', source = 'bbb.ltx')
-# builds from ccc.latex
-env.DVI(target = 'ccc.dvi', source = 'ccc.latex')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP Jar()
-.IP env.Jar()
-Builds a Java archive (.jar) file
-from a source tree of .class files.
-If the $JARCHDIR value is set, the
-.B jar
-command will change to the specified directory using the
-.B \-C
-option.
-If the contents any of the source files begin with the string
-.BR Manifest-Version ,
-the file is assumed to be a manifest
-and is passed to the
-.B jar
-command with the
-.B m
-option set.
-
-.ES
-env.Jar(target = 'foo.jar', source = 'classes')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP Java()
-.IP env.Java()
-Builds one or more Java class files
-from one or more source trees of .java files.
-The class files will be placed underneath
-the specified target directory.
-SCons will parse each source .java file
-to find the classes
-(including inner classes)
-defined within that file,
-and from that figure out the
-target .class files that will be created.
-SCons will also search each Java file
-for the Java package name,
-which it assumes can be found on a line
-beginning with the string
-.B package
-in the first column;
-the resulting .class files
-will be placed in a directory reflecting
-the specified package name.
-For example,
-the file
-.I Foo.java
-defining a single public
-.I Foo
-class and
-containing a package name of
-.I sub.dir
-will generate a corresponding
-.IR sub/dir/Foo.class
-class file.
-
-Example:
-
-.ES
-env.Java(target = 'classes', source = 'src')
-env.Java(target = 'classes', source = ['src1', 'src2'])
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP JavaH()
-.IP env.JavaH()
-Builds C header and source files for
-implementing Java native methods.
-The target can be either a directory
-in which the header files will be written,
-or a header file name which
-will contain all of the definitions.
-The source can be either the names of .class files,
-or the objects returned from the
-.B Java
-builder method.
-
-If the construction variable
-.B JAVACLASSDIR
-is set, either in the environment
-or in the call to the
-.B JavaH
-builder method itself,
-then the value of the variable
-will be stripped from the
-beginning of any .class file names.
-
-Examples:
-
-.ES
-# builds java_native.h
-classes = env.Java(target = 'classdir', source = 'src')
-env.JavaH(target = 'java_native.h', source = classes)
-
-# builds include/package_foo.h and include/package_bar.h
-env.JavaH(target = 'include',
-          source = ['package/foo.class', 'package/bar.class'])
-
-# builds export/foo.h and export/bar.h
-env.JavaH(target = 'export',
-          source = ['classes/foo.class', 'classes/bar.class'],
-          JAVACLASSDIR = 'classes')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP Library()
-.IP env.Library()
-A synonym for the
-.B StaticLibrary
-builder method.
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP M4()
-.IP env.M4()
-Builds an output file from an M4 input file.
-This uses a default $M4FLAGS value of
-.BR -E ,
-which considers all warnings to be fatal
-and stops on the first warning
-when using the GNU version of m4.
-Example:
-
-.ES
-env.M4(target = 'foo.c', source = 'foo.c.m4')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP Moc()
-.IP env.Moc()
-Builds an output file from a moc input file. Moc input files are either 
-header files or cxx files. This builder is only available after using the 
-tool 'qt'. See the QTDIR variable for more information.
-Example:
-
-.ES
-env.Moc('foo.h') # generates moc_foo.cc
-env.Moc('foo.cpp') # generates foo.moc
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP MSVSProject()
-.IP env.MSVSProject()
-Builds Microsoft Visual Studio project files.
-This builds a Visual Studio project file, based on the version of
-Visual Studio that is configured (either the latest installed version,
-or the version set by 
-.B MSVS_VERSION
-in the Environment constructor).
-For VS 6, it will generate 
-.B .dsp
-and
-.B .dsw
-files, for VS 7, it will
-generate
-.B .vcproj
-and
-.B .sln
-files.
-
-It takes several lists of filenames to be placed into the project
-file, currently these are limited to 
-.B srcs, incs, localincs, resources,
-and
-.B misc.
-These are pretty self explanatory, but it
-should be noted that the 'srcs' list is NOT added to the $SOURCES
-environment variable.  This is because it represents a list of files
-to be added to the project file, not the source used to build the
-project file (in this case, the 'source' is the SConscript file used
-to call MSVSProject).
-
-In addition to these values (which are all optional, although not
-specifying any of them results in an empty project file), the
-following values must be specified:
-
-target: The name of the target .dsp or .vcproj file.  The correct
-suffix for the version of Visual Studio must be used, but the value
-
-env['MSVSPROJECTSUFFIX']
-
-will be defined to the correct value (see example below).
-
-variant: The name of this particular variant.  These are typically
-things like "Debug" or "Release", but really can be anything you want.
-Multiple calls to MSVSProject with different variants are allowed: all
-variants will be added to the project file with their appropriate
-build targets and sources.
-
-buildtarget: A list of SCons.Node.FS objects which is returned from
-the command which builds the target.  This is used to tell SCons what
-to build when the 'build' button is pressed inside of the IDE.
-
-Example Usage:
-
-.ES
-        barsrcs = ['bar.cpp'],
-        barincs = ['bar.h'],
-        barlocalincs = ['StdAfx.h']
-        barresources = ['bar.rc','resource.h']
-        barmisc = ['bar_readme.txt']
-
-        dll = local.SharedLibrary(target = 'bar.dll',
-                                  source = barsrcs)
-
-        local.MSVSProject(target = 'Bar' + env['MSVSPROJECTSUFFIX'],
-                          srcs = barsrcs,
-                          incs = barincs,
-                          localincs = barlocalincs,
-                          resources = barresources,
-                          misc = barmisc,
-                          buildtarget = dll,
-                          variant = 'Release')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP Object()
-.IP env.Object()
-A synonym for the
-.B StaticObject
-builder method.
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP PCH()
-.IP env.PCH()
-Builds a Microsoft Visual C++ precompiled header.
-Calling this builder method
-returns a list of two targets: the PCH as the first element, and the object
-file as the second element. Normally the object file is ignored.
-This builder method is only
-provided when Microsoft Visual C++ is being used as the compiler. 
-The PCH builder method is generally used in
-conjuction with the PCH construction variable to force object files to use
-the precompiled header:
-
-.ES
-env['PCH'] = env.PCH('StdAfx.cpp')[0]
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP PDF()
-.IP env.PDF()
-Builds a .pdf file from a .dvi input file
-(or, by extension, a .tex, .ltx, or .latex input file).
-The suffix specified by the $PDFSUFFIX construction variable
-(.pdf by default)
-is added automatically to the target
-if it is not already present.  Example:
-
-.ES
-# builds from aaa.tex
-env.PDF(target = 'aaa.pdf', source = 'aaa.tex')
-# builds bbb.pdf from bbb.dvi
-env.PDF(target = 'bbb', source = 'bbb.dvi')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP PostScript()
-.IP env.PostScript()
-Builds a .ps file from a .dvi input file
-(or, by extension, a .tex, .ltx, or .latex input file).
-The suffix specified by the $PSSUFFIX construction variable
-(.ps by default)
-is added automatically to the target
-if it is not already present.  Example:
-
-.ES
-# builds from aaa.tex
-env.PostScript(target = 'aaa.ps', source = 'aaa.tex')
-# builds bbb.ps from bbb.dvi
-env.PostScript(target = 'bbb', source = 'bbb.dvi')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP Program()
-.IP env.Program()
-Builds an executable given one or more object files
-or C, C++, D, or Fortran source files.
-If any C, C++, D or Fortran source files are specified,
-then they will be automatically
-compiled to object files using the
-.B Object
-builder method;
-see that builder method's description for
-a list of legal source file suffixes
-and how they are interpreted.
-The target executable file prefix
-(specified by the $PROGPREFIX construction variable; nothing by default)
-and suffix
-(specified by the $PROGSUFFIX construction variable;
-by default, .exe on Windows systems, nothing on POSIX systems)
-are automatically added to the target if not already present.
-Example:
-
-.ES
-env.Program(target = 'foo', source = ['foo.o', 'bar.c', 'baz.f'])
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP RES()
-.IP env.RES()
-Builds a Microsoft Visual C++ resource file.
-This builder method is only provided
-when Microsoft Visual C++ or MinGW is being used as the compiler. The
-.I .res
-(or 
-.I .o 
-for MinGW) suffix is added to the target name if no other suffix is given. The source
-file is scanned for implicit dependencies as though it were a C file. Example:
-
-.ES
-env.RES('resource.rc')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP RMIC()
-.IP env.RMIC()
-Builds stub and skeleton class files
-for remote objects
-from Java .class files.
-The target is a directory
-relative to which the stub
-and skeleton class files will be written.
-The source can be the names of .class files,
-or the objects return from the
-.B Java
-builder method.
-
-If the construction variable
-.B JAVACLASSDIR
-is set, either in the environment
-or in the call to the
-.B RMIC
-builder method itself,
-then the value of the variable
-will be stripped from the
-beginning of any .class file names.
-
-.ES
-classes = env.Java(target = 'classdir', source = 'src')
-env.RMIC(target = 'outdir1', source = classes)
-
-env.RMIC(target = 'outdir2',
-         source = ['package/foo.class', 'package/bar.class'])
-
-env.RMIC(target = 'outdir3',
-         source = ['classes/foo.class', 'classes/bar.class'],
-         JAVACLASSDIR = 'classes')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP RPCGenClient()
-.IP env.RPCGenClient()
-Generates an RPC client stub (_clnt.c) file
-from a specified RPC (.x) source file.
-Because rpcgen only builds output files
-in the local directory,
-the command will be executed
-in the source file's directory by default.
-
-.ES
-# Builds src/rpcif_clnt.c
-env.RPCGenClient('src/rpcif.x')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP RPCGenHeader()
-.IP env.RPCGenHeader()
-Generates an RPC header (.h) file
-from a specified RPC (.x) source file.
-Because rpcgen only builds output files
-in the local directory,
-the command will be executed
-in the source file's directory by default.
-
-.ES
-# Builds src/rpcif.h
-env.RPCGenHeader('src/rpcif.x')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP RPCGenService()
-.IP env.RPCGenService()
-Generates an RPC server-skeleton (_svc.c) file
-from a specified RPC (.x) source file.
-Because rpcgen only builds output files
-in the local directory,
-the command will be executed
-in the source file's directory by default.
-
-.ES
-# Builds src/rpcif_svc.c
-env.RPCGenClient('src/rpcif.x')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP RPCGenXDR()
-.IP env.RPCGenXDR()
-Generates an RPC XDR routine (_xdr.c) file
-from a specified RPC (.x) source file.
-Because rpcgen only builds output files
-in the local directory,
-the command will be executed
-in the source file's directory by default.
-
-.ES
-# Builds src/rpcif_xdr.c
-env.RPCGenClient('src/rpcif.x')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP SharedLibrary()
-.IP env.SharedLibrary()
-Builds a shared library
-(.so on a POSIX system, .dll on WIN32)
-given one or more object files
-or C, C++, D or Fortran source files.
-If any source files are given,
-then they will be automatically
-compiled to object files.
-The static library prefix and suffix (if any)
-are automatically added to the target.
-The target library file prefix
-(specified by the $SHLIBPREFIX construction variable;
-by default, lib on POSIX systems, nothing on Windows systems)
-and suffix
-(specified by the $SHLIBSUFFIX construction variable;
-by default, .dll on Windows systems, .so on POSIX systems)
-are automatically added to the target if not already present.
-Example:
-
-.ES
-env.SharedLibrary(target = 'bar', source = ['bar.c', 'foo.o'])
-.EE
-.IP
-On WIN32 systems, the
-.B SharedLibrary
-builder method will always build an import (.lib) library
-in addition to the shared (.dll) library,
-adding a .lib library with the same basename
-if there is not already a .lib file explicitly
-listed in the targets.
-
-Any object files listed in the
-.B source
-must have been built for a shared library
-(that is, using the
-.B SharedObject
-builder method).
-.B scons
-will raise an error if there is any mismatch.
-.IP
-On WIN32 systems, specifying "register=1" will cause the dll to be
-registered after it is built using REGSVR32.  The command that is run
-("regsvr32" by default) is determined by $REGSVR construction
-variable, and the flags passed are determined by $REGSVRFLAGS.  By
-default, $REGSVRFLAGS includes "/s", to prevent dialogs from popping
-up and requiring user attention when it is run.  If you change
-$REGSVRFLAGS, be sure to include "/s".  For example,
-
-.ES
-env.SharedLibrary(target = 'bar',
-                  source = ['bar.cxx', 'foo.obj'],
-                  register=1)
-.EE
-
-.IP
-will register "bar.dll" as a COM object when it is done linking it.
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP SharedObject()
-.IP env.SharedObject()
-Builds an object file for
-inclusion in a shared library.
-Source files must have one of the same set of extensions
-specified above for the
-.B StaticObject
-builder method.
-On some platforms building a shared object requires additional
-compiler options (e.g. -fPIC for gcc) in addition to those needed to build a
-normal (static) object, but on some platforms there is no difference between a
-shared object and a normal (static) one. When there is a difference, SCons
-will only allow shared objects to be linked into a shared library, and will
-use a different suffix for shared objects. On platforms where there is no
-difference, SCons will allow both normal (static)
-and shared objects to be linked into a
-shared library, and will use the same suffix for shared and normal
-(static) objects.
-The target object file prefix
-(specified by the $SHOBJPREFIX construction variable;
-by default, the same as $OBJPREFIX)
-and suffix
-(specified by the $SHOBJSUFFIX construction variable)
-are automatically added to the target if not already present. 
-Examples:
-
-.ES
-env.SharedObject(target = 'ddd', source = 'ddd.c')
-env.SharedObject(target = 'eee.o', source = 'eee.cpp')
-env.SharedObject(target = 'fff.obj', source = 'fff.for')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP StaticLibrary()
-.IP env.StaticLibrary()
-Builds a static library given one or more object files
-or C, C++, D or Fortran source files.
-If any source files are given,
-then they will be automatically
-compiled to object files.
-The static library prefix and suffix (if any)
-are automatically added to the target.
-The target library file prefix
-(specified by the $LIBPREFIX construction variable;
-by default, lib on POSIX systems, nothing on Windows systems)
-and suffix
-(specified by the $LIBSUFFIX construction variable;
-by default, .lib on Windows systems, .a on POSIX systems)
-are automatically added to the target if not already present.
-Example:
-
-.ES
-env.StaticLibrary(target = 'bar', source = ['bar.c', 'foo.o'])
-.EE
-
-.IP
-Any object files listed in the
-.B source
-must have been built for a static library
-(that is, using the
-.B StaticObject
-builder method).
-.B scons
-will raise an error if there is any mismatch.
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP StaticObject()
-.IP env.StaticObject()
-Builds a static object file
-from one or more C, C++, D, or Fortran source files.
-Source files must have one of the following extensions:
-
-.ES
-  .asm    assembly language file
-  .ASM    assembly language file
-  .c      C file
-  .C      WIN32:  C file
-          POSIX:  C++ file
-  .cc     C++ file
-  .cpp    C++ file
-  .cxx    C++ file
-  .cxx    C++ file
-  .c++    C++ file
-  .C++    C++ file
-  .d      D file
-  .f      Fortran file
-  .F      WIN32:  Fortran file
-          POSIX:  Fortran file + C pre-processor
-  .for    Fortran file
-  .FOR    Fortran file
-  .fpp    Fortran file + C pre-processor
-  .FPP    Fortran file + C pre-processor
-  .s      assembly language file
-  .S      WIN32:  assembly language file
-          POSIX:  assembly language file + C pre-processor
-  .spp    assembly language file + C pre-processor
-  .SPP    assembly language file + C pre-processor
-.EE
-.IP
-The target object file prefix
-(specified by the $OBJPREFIX construction variable; nothing by default)
-and suffix
-(specified by the $OBJSUFFIX construction variable;
-\.obj on Windows systems, .o on POSIX systems)
-are automatically added to the target if not already present.
-Examples:
-
-.ES
-env.StaticObject(target = 'aaa', source = 'aaa.c')
-env.StaticObject(target = 'bbb.o', source = 'bbb.c++')
-env.StaticObject(target = 'ccc.obj', source = 'ccc.f')
-.EE
-
-'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP Tar()
-.IP env.Tar()
-Builds a tar archive of the specified files
-and/or directories.
-Unlike most builder methods,
-the
-.B Tar
-builder method may be called multiple times
-for a given target;
-each additional call
-adds to the list of entries
-that will be built into the archive.
-
-.ES
-env.Tar('src.tar', 'src')
-
-# Create the stuff.tar file.
-env.Tar('stuff', ['subdir1', 'subdir2'])
-# Also add "another" to the stuff.tar file.
-env.Tar('stuff', 'another')
-
-# Set TARFLAGS to create a gzip-filtered archive.
-env = Environment(TARFLAGS = '-c -z')
-env.Tar('foo.tar.gz', 'foo')
-
-# Also set the suffix to .tgz.
-env = Environment(TARFLAGS = '-c -z',
-                  TARSUFFIX = '.tgz')
-env.Tar('foo')
-.EE
-
+'\" BEGIN GENERATED BUILDER DESCRIPTIONS
+'\"
+'\" The descriptions below of the various SCons Builders are generated
+'\" from the .xml files that live next to the various Python modules in
+'\" the build enginer library.  If you're reading this [gnt]roff file
+'\" with an eye towards patching this man page, you can still submit
+'\" a diff against this text, but it will have to be translated to a
+'\" diff against the underlying .xml file before the patch is actually
+'\" accepted.  If you do that yourself, it will make it easier to
+'\" integrate the patch.
+'\"
+'\" BEGIN GENERATED BUILDER DESCRIPTIONS
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP TypeLibrary()
-.IP env.TypeLibrary()
-Builds a Windows type library (.tlb) file from and input IDL file
-(.idl).  In addition, it will build the associated inteface stub and
-proxy source files.  It names them according to the base name of the .idl file.
-.IP
-For example,
-
-.ES
-env.TypeLibrary(source="foo.idl")
-.EE
-.IP
-Will create foo.tlb, foo.h, foo_i.c, foo_p.c, and foo_data.c.
-
+.so builders.man
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP Uic()
-.IP env.Uic()
-Builds a header file, an implementation file and a moc file from an ui file.
-and returns the corresponding nodes in the above order.
-This builder is only available after using the tool 'qt'. Note: you can 
-specify .ui files directly as inputs for Program, Library and SharedLibrary
-without using this builder. Using the builder lets you override the standard
-naming conventions (be careful: prefixes are always prepended to names of
-built files; if you don't want prefixes, you may set them to ``).
-See the QTDIR variable for more information.
-Example:
-
-.ES
-env.Uic('foo.ui') # -> ['foo.h', 'uic_foo.cc', 'moc_foo.cc']
-env.Uic(target = Split('include/foo.h gen/uicfoo.cc gen/mocfoo.cc'),
-        source = 'foo.ui') # -> ['include/foo.h', 'gen/uicfoo.cc', 'gen/mocfoo.cc']
-.EE
-
+'\" END GENERATED BUILDER DESCRIPTIONS
+'\"
+'\" The descriptions above of the various SCons Builders are generated
+'\" from the .xml files that live next to the various Python modules in
+'\" the build enginer library.  If you're reading this [gnt]roff file
+'\" with an eye towards patching this man page, you can still submit
+'\" a diff against this text, but it will have to be translated to a
+'\" diff against the underlying .xml file before the patch is actually
+'\" accepted.  If you do that yourself, it will make it easier to
+'\" integrate the patch.
+'\"
+'\" END GENERATED BUILDER DESCRIPTIONS
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-.IP Zip()
-.IP env.Zip()
-Builds a zip archive of the specified files
-and/or directories.
-Unlike most builder methods,
-the
-.B Zip
-builder method may be called multiple times
-for a given target;
-each additional call
-adds to the list of entries
-that will be built into the archive.
-
-.ES
-env.Zip('src.zip', 'src')
 
-# Create the stuff.zip file.
-env.Zip('stuff', ['subdir1', 'subdir2'])
-# Also add "another" to the stuff.tar file.
-env.Zip('stuff', 'another')
-.EE
+All
+targets of builder methods automatically depend on their sources.
+An explicit dependency can
+be specified using the 
+.B Depends 
+method of a construction environment (see below).
 
+In addition,
 .B scons
 automatically scans
-C source files, C++ source files,
+source files for various programming languages,
+so the dependencies do not need to be specified explicitly.
+By default, SCons can
+C source files,
+C++ source files,
 Fortran source files with
 .B .F
 (POSIX systems only),
@@ -2149,14 +1579,26 @@ and assembly language files with
 or
 .B .SPP
 files extensions
-for C preprocessor dependencies,
-so the dependencies do not need to be specified explicitly.
-In addition, all
-targets of builder methods automatically depend on their sources.
-An explicit dependency can
-be specified using the 
-.B Depends 
-method of a construction environment (see below).
+for C preprocessor dependencies.
+SCons also has default support
+for scanning D source files,
+You can also write your own Scanners
+to add support for additional source file types.
+These can be added to the default
+Scanner object used by
+the
+.BR Object ()
+.BR StaticObject ()
+and
+.BR SharedObject ()
+Builders by adding them
+to the
+.B SourceFileScanner
+object as follows:
+
+See the section "Scanner Objects,"
+below, for a more information about
+defining your own Scanner objects.
 
 .SS Methods and Functions to Do Things
 In addition to Builder methods,
@@ -2184,6 +1626,14 @@ environment it looks like:
 If you can call the functionality in both ways,
 then both forms are listed.
 
+Global functions may be called from custom Python modules that you
+import into an SConscript file by adding the following
+to the Python module:
+
+.ES
+from SCons.Script import *
+.EE
+
 Except where otherwise noted,
 the same-named
 construction environment method
@@ -2266,11 +1716,17 @@ can be converted into an Action object
 
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP
-.RI Alias( alias ", [" targets ])
+.RI Alias( alias ", [" targets ", [" action ]])
 .TP
-.RI env.Alias( alias ", [" targets ])
+.RI env.Alias( alias ", [" targets ", [" action ]])
 Creates one or more phony targets that
 expand to one or more other targets.
+An optional
+.I action
+(command)
+or list of actions
+can be specified that will be executed
+whenever the any of the alias targets are out-of-date.
 Returns the Node object representing the alias,
 which exists outside of any file system.
 This Node object, or the alias name,
@@ -2278,7 +1734,8 @@ may be used as a dependency of any other target,
 including another alias.
 .B Alias
 can be called multiple times for the same
-alias to add additional targets to the alias.
+alias to add additional targets to the alias,
+or additional actions to the list for this alias.
 
 .ES
 Alias('install')
@@ -2287,6 +1744,8 @@ Alias(['install', 'install-lib'], '/usr/local/lib')
 
 env.Alias('install', ['/usr/local/bin', '/usr/local/lib'])
 env.Alias('install', ['/usr/local/man'])
+
+env.Alias('update', ['file1', 'file2'], "update_database $SOURCES")
 .EE
 
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
@@ -2354,7 +1813,7 @@ Example:
 .ES
 print 'before:',env['ENV']['INCLUDE']
 include_path = '/foo/bar:/foo'
-env.PrependENVPath('INCLUDE', include_path)
+env.AppendENVPath('INCLUDE', include_path)
 print 'after:',env['ENV']['INCLUDE']
 
 yields:
@@ -2619,22 +2078,47 @@ Clean(['foo', 'bar'], 'something_else_to_clean')
 
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP
-.RI Command( target ", " source ", " commands ", [" key = val ", ...])"
+.RI Command( target ", " source ", " action ", [" key = val ", ...])"
 .TP
-.RI env.Command( target ", " source ", " commands ", [" key = val ", ...])"
+.RI env.Command( target ", " source ", " action ", [" key = val ", ...])"
 Executes a specific action
 (or list of actions)
 to build a target file or files.
 This is more convenient
 than defining a separate Builder object
 for a single special-case build.
-Any keyword arguments specified override any
+
+As a special case, the
+.B source_scanner
+keyword argument can
+be used to specify
+a Scanner object
+that will be used to scan the sources.
+(The global
+.B DirScanner
+object can be used
+if any of the sources will be directories
+that must be scanned on-disk for
+changes to files that aren't
+already specified in other Builder of function calls.)
+
+Any other keyword arguments specified override any
 same-named existing construction variables.
 
-Note that an action can be an external command,
+An action can be an external command,
 specified as a string,
 or a callable Python object;
-see "Action Objects," below.
+see "Action Objects," below,
+for more complete information.
+Also note that a string specifying an external command
+may be preceded by an
+.B @
+(at-sign)
+to suppress printing the command in question,
+or by a
+.B \-
+(hyphen)
+to ignore the exit status of the external command.
 Examples:
 
 .ES
@@ -2890,17 +2374,24 @@ EnsurePythonVersion(2,2)
 
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP
-.RI EnsureSConsVersion( major ", " minor )
+.RI EnsureSConsVersion( major ", " minor ", [" revision ])
 .TP
-.RI env.EnsureSConsVersion( major ", " minor )
+.RI env.EnsureSConsVersion( major ", " minor ", [" revision ])
 Ensure that the SCons version is at least 
-.IR major . minor . 
+.IR major.minor ,
+or
+.IR major.minor.revision . 
+if
+.I revision
+is specified.
 This function will
 print out an error message and exit SCons with a non-zero exit code if the
 actual SCons version is not late enough.
 
 .ES
-EnsureSConsVersion(0,9)
+EnsureSConsVersion(0,14)
+
+EnsureSConsVersion(0,96,90)
 .EE
 
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
@@ -3248,7 +2739,7 @@ Returns a list of the target Node or Nodes.
 
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP
-.RI env.ParseConfig( command ", [" function ])
+.RI env.ParseConfig( command ", [" function ", " unique ])
 Calls the specified
 .I function
 to modify the environment as specified by the output of
@@ -3259,15 +2750,25 @@ expects the output of a typical
 .I *-config command
 (for example,
 .BR gtk-config )
-and parses the returned
+and adds the options
+to the appropriate construction variables.
+By default, 
+duplicate values are not
+added to any construction variables;
+you can specify
+.B unique=0
+to allow duplicate
+values to be added.
+
+By default,
 .BR -L ,
 .BR -l ,
 .BR -Wa ,
 .BR -Wl ,
 .BR -Wp ,
 .B -I
-and other options
-into the
+and other options,
+are add to the
 .BR LIBPATH ,
 .BR LIBS ,
 .BR ASFLAGS ,
@@ -3276,7 +2777,7 @@ into the
 .B CPPPATH
 and
 .B CCFLAGS
-variables,
+construction variables,
 respectively.
 A returned
 .B -pthread
@@ -3300,7 +2801,7 @@ construction variable.
 .TP
 .RI ParseDepends( filename ", [" must_exist ])
 .TP
-.RI env.ParseDepends( filename ", [" must_exist ])
+.RI env.ParseDepends( filename ", [" must_exist " " only_one ])
 Parses the contents of the specified
 .I filename
 as a list of dependencies in the style of
@@ -3308,6 +2809,7 @@ as a list of dependencies in the style of
 or
 .BR mkdep ,
 and explicitly establishes all of the listed dependencies.
+
 By default,
 it is not an error
 if the specified
@@ -3321,13 +2823,34 @@ scons
 throw an exception and
 generate an error if the file does not exist,
 or is otherwise inaccessible.
+
+The optional
+.I only_one
+argument may be set to a non-zero
+value to have
+scons
+thrown an exception and
+generate an error
+if the file contains dependency
+information for more than one target.
+This can provide a small sanity check
+for files intended to be generated
+by, for example, the
+.B gcc -M
+flag,
+which should typically only
+write dependency information for
+one output file into a corresponding
+.B .d
+file.
+
 The
 .I filename
 and all of the files listed therein
 will be interpreted relative to
 the directory of the
 .I SConscript
-file which called the
+file which calls the
 .B ParseDepends
 function.
 
@@ -3388,8 +2911,10 @@ env.Platform('posix')
 Note that the
 .B win32
 platform adds the
+.B SYSTEMDRIVE
+and
 .B SYSTEMROOT
-variable from the user's external environment
+variables from the user's external environment
 to the construction environment's
 .B ENV
 dictionary.
@@ -3467,7 +2992,7 @@ after: /foo/bar:/foo:/biz
 
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP
-.RI env.AppendUnique( key = val ", [...])"
+.RI env.PrependUnique( key = val ", [...])"
 Appends the specified keyword arguments
 to the beginning of construction variables in the environment.
 If the Environment does not have
@@ -3807,13 +3332,17 @@ SConscript('bar/SConscript')    # will chdir to bar
 This tells
 .B scons
 to store all file signatures
-in the specified
+in the specified database
 .IR file .
 If the
 .I file
-is omitted,
-.B .sconsign.dbm
+name is omitted,
+.B .sconsign
 is used by default.
+(The actual file name(s) stored on disk
+may have an appropriated suffix appended
+by the
+.IR  dbm_module .)
 If
 .I file
 is not an absolute path name,
@@ -3821,6 +3350,20 @@ the file is placed in the same directory as the top-level
 .B SConstruct
 file.
 
+If
+.I file
+is
+.BR None ,
+then
+.B scons
+will store file signatures
+in a separate
+.B .sconsign
+file in each directory,
+not in one global database file.
+(This was the default behavior
+prior to SCons 0.96.91 and 0.97.)
+
 The optional
 .I dbm_module
 argument can be used to specify
@@ -3834,8 +3377,9 @@ and which works on all Python versions from 1.5.2 on.
 Examples:
 
 .ES
-# Stores signatures in ".sconsign.dbm"
-# in the top-level SConstruct directory.
+# Explicitly stores signatures in ".sconsign.dblite"
+# in the top-level SConstruct directory (the
+# default behavior).
 SConsignFile()
 
 # Stores signatures in the file "etc/scons-signatures"
@@ -3844,6 +3388,10 @@ SConsignFile("etc/scons-signatures")
 
 # Stores signatures in the specified absolute file name.
 SConsignFile("/home/me/SCons/signatures")
+
+# Stores signatures in a separate .sconsign file
+# in each directory.
+SConsignFile(None)
 .EE
 
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
@@ -3986,7 +3534,92 @@ env.SourceCode(['f1.c', 'f2.c'], env.SCCS())
 env.SourceCode('no_source.c', None)
 .EE
 '\"env.SourceCode('.', env.Subversion('file:///usr/local/Subversion'))
-'\"
+
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.RI env.subst( string ", [" raw ", " target ", " source ", " conv ])
+Performs construction variable interpolation
+on the specified string argument.
+
+By default,
+leading or trailing white space will
+be removed from the result.
+and all sequences of white space
+will be compressed to a single space character.
+Additionally, any
+.B $(
+and
+.B $)
+character sequences will be stripped from the returned string,
+The optional
+.I raw
+argument may be set to
+.B 1
+if you want to preserve white space and
+.BR $( - $)
+sequences.
+The
+.I raw
+argument may be set to
+.B 2
+if you want to strip
+all characters between
+any
+.B $(
+and
+.B $)
+pairs
+(as is done for signature calculation).
+
+The optional
+.I target
+and
+.I source
+keyword arguments
+must be set to lists of
+target and source nodes, respectively,
+if you want the
+.BR $TARGET ,
+.BR $TARGETS ,
+.BR $SOURCE
+and
+.BR $SOURCES
+to be available for expansion.
+This is usually necessary if you are
+calling
+.BR env.subst ()
+from within a Python function used
+as an SCons action.
+
+By default,
+all returned values are converted
+to their string representation.
+The optional
+.I conv
+argument
+may specify a conversion function
+that will be used in place of
+the default.
+For example, if you want Python objects
+(including SCons Nodes)
+to be returned as Python objects,
+you can use the Python
+.B lambda
+idiom to pass in an unnamed function
+that simply returns its unconverted argument.
+
+.ES
+print env.subst("The C compiler is: $CC")
+
+def compile(target, source, env):
+    sourceDir = env.subst("${SOURCE.srcdir}",
+                          target=target,
+                          source=source)
+
+source_nodes = env.subst('$EXPAND_TO_NODELIST',
+                         conv=lambda x: x)
+.EE
+
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 '\".TP
 '\".RI Subversion( repository ", " module )
@@ -4220,6 +3853,13 @@ In addition to the global functions and methods,
 supports a number of Python variables
 that can be used in SConscript files
 to affect how you want the build to be performed.
+These variables may be accessed from custom Python modules that you
+import into an SConscript file by adding the following
+to the Python module:
+
+.ES
+from SCons.Script import *
+.EE
 
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP
@@ -4416,2173 +4056,35 @@ scons for each supported platform, and additional construction variables
 can be defined by the user. The following is a list of the automatically
 defined construction variables:
 
-.IP AR
-The static library archiver.
-
-.IP ARCOM
-The command line used to generate a static library from object files.
-
-.IP ARFLAGS
-General options passed to the static library archiver.
-
-.IP AS
-The assembler.
-
-.IP ASCOM
-The command line used to generate an object file
-from an assembly-language source file.
-
-.IP ASFLAGS
-General options passed to the assembler.
-
-.IP ASPPCOM
-The command line used to assemble an assembly-language
-source file into an object file
-after first running the file through the C preprocessor.
-Any options specified in the $ASFLAGS and $CPPFLAGS construction variables
-are included on this command line.
-
-.IP BIBTEX
-The bibliography generator for the TeX formatter and typesetter and the
-LaTeX structured formatter and typesetter.
-
-.IP BIBTEXCOM
-The command line used to call the bibliography generator for the
-TeX formatter and typesetter and the LaTeX structured formatter and
-typesetter.
-
-.IP BIBTEXFLAGS
-General options passed to the bibliography generator for the TeX formatter
-and typesetter and the LaTeX structured formatter and typesetter.
-
-.IP BITKEEPER
-The BitKeeper executable.
-
-.IP BITKEEPERCOM
-The command line for
-fetching source files using BitKEeper.
-
-.IP BITKEEPERGET
-The command ($BITKEEPER) and subcommand
-for fetching source files using BitKeeper.
-
-.IP BITKEEPERGETFLAGS
-Options that are passed to the BitKeeper
-.B get
-subcommand.
-
-.IP BUILDERS
-A dictionary mapping the names of the builders
-available through this environment
-to underlying Builder objects.
-Builders named
-Alias, CFile, CXXFile, DVI, Library, Object, PDF, PostScript, and Program
-are available by default.
-If you initialize this variable when an
-Environment is created:
-
-.ES
-env = Environment(BUILDERS = {'NewBuilder' : foo})
-.EE
-.IP
-the default Builders will no longer be available.
-To use a new Builder object in addition to the default Builders,
-add your new Builder object like this:
-
-.ES
-env = Environment()
-env.Append(BUILDERS = {'NewBuilder' : foo})
-.EE
-.IP
-or this:
-
-.ES
-env = Environment()
-env['BUILDERS]['NewBuilder'] = foo
-.EE
-
-.IP CC 
-The C compiler.
-
-.IP CCCOM 
-The command line used to compile a C source file to a (static) object file.
-Any options specified in the $CCFLAGS and $CPPFLAGS construction variables
-are included on this command line.
-
-.IP CCFLAGS 
-General options that are passed to the C compiler.
-
-.IP CFILESUFFIX
-The suffix for C source files.
-This is used by the internal CFile builder
-when generating C files from Lex (.l) or YACC (.y) input files.
-The default suffix, of course, is
-.I .c
-(lower case).
-On case-insensitive systems (like Win32),
-SCons also treats
-.I .C
-(upper case) files
-as C files.
-
-.IP CCVERSION
-The version number of the C compiler.
-This may or may not be set,
-depending on the specific C compiler being used.
-
-.IP _concat
-A function used to produce variables like $_CPPINCFLAGS. It takes
-four or five
-arguments: a prefix to concatenate onto each element, a list of
-elements, a suffix to concatenate onto each element, an environment
-for variable interpolation, and an optional function that will be
-called to transform the list before concatenation.
-
-.ES
-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 $FORTRANPPCOM, $SHFORTRANPPCOM,
-$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,
-after first running each file through the C preprocessor.
-Note that this variable does
-.I not
-contain
-.B -I
-(or similar) include search path options
-that scons generates automatically from $CPPPATH.
-See
-.BR _CPPINCFLAGS ,
-below,
-for the variable that expands to those options.
-
-.IP _CPPINCFLAGS
-An automatically-generated construction variable
-containing the C preprocessor command-line options
-for specifying directories to be searched for include files.
-The value of $_CPPINCFLAGS is created
-by appending $INCPREFIX and $INCSUFFIX
-to the beginning and end
-of each directory in $CPPPATH.
-
-.IP CPPPATH
-The list of directories that the C preprocessor will search for include
-directories. The C/C++ implicit dependency scanner will search these
-directories for include files. Don't explicitly put include directory
-arguments in CCFLAGS or CXXFLAGS because the result will be non-portable
-and the directories will not be searched by the dependency scanner. Note:
-directory names in CPPPATH will be looked-up relative to the SConscript
-directory when they are used in a command. To force 
-.B scons
-to look-up a directory relative to the root of the source tree use #:
-
-.ES
-env = Environment(CPPPATH='#/include')
-.EE
-
-.IP
-The directory look-up can also be forced using the 
-.BR Dir ()
-function:
-
-.ES
-include = Dir('include')
-env = Environment(CPPPATH=include)
-.EE
-
-.IP
-The directory list will be added to command lines
-through the automatically-generated
-$_CPPINCFLAGS
-construction variable,
-which is constructed by
-appending the values of the
-$INCPREFIX and $INCSUFFIX
-construction variables
-to the beginning and end
-of each directory in $CPPPATH.
-Any command lines you define that need
-the CPPPATH directory list should
-include $_CPPINCFLAGS:
-
-.ES
-env = Environment(CCCOM="my_compiler $_CPPINCFLAGS -c -o $TARGET $SOURCE")
-.EE
-
-.IP CPPSUFFIXES
-The list of suffixes of files that will be scanned
-for C preprocessor implicit dependencies
-(#include lines).
-The default list is:
-
-.ES
-[".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
- ".h", ".H", ".hxx", ".hpp", ".hh",
- ".F", ".fpp", ".FPP",
- ".S", ".spp", ".SPP"]
-.EE
-
-.IP CVS
-The CVS executable.
-
-.IP CVSCOFLAGS
-Options that are passed to the CVS checkout subcommand.
-
-.IP CVSCOM
-The command line used to
-fetch source files from a CVS repository.
-
-.IP CVSFLAGS
-General options that are passed to CVS.
-By default, this is set to
-"-d $CVSREPOSITORY"
-to specify from where the files must be fetched.
-
-.IP CVSREPOSITORY
-The path to the CVS repository.
-This is referenced in the default
-$CVSFLAGS value.
-
-.IP CXX
-The C++ compiler.
-
-.IP CXXFILESUFFIX
-The suffix for C++ source files.
-This is used by the internal CXXFile builder
-when generating C++ files from Lex (.ll) or YACC (.yy) input files.
-The default suffix is
-.IR .cc .
-SCons also treats files with the suffixes
-.IR .cpp ,
-.IR .cxx ,
-.IR .c++ ,
-and
-.I .C++
-as C++ files.
-On case-sensitive systems (Linux, UNIX, and other POSIX-alikes),
-SCons also treats
-.I .C
-(upper case) files
-as C++ files.
-
-.IP CXXCOM
-The command line used to compile a C++ source file to an object file.
-Any options specified in the $CXXFLAGS and $CPPFLAGS construction variables
-are included on this command line.
-
-.IP CXXFLAGS 
-General options that are passed to the C++ compiler.
-
-.IP CXXVERSION
-The version number of the C++ compiler.
-This may or may not be set,
-depending on the specific C++ compiler being used.
-
-.IP Dir
-A function that converts a file name into a Dir instance relative to the
-target being built. 
-
-.IP DSUFFIXES
-The list of suffixes of files that will be scanned
-for imported D package files.
-The default list is:
-
-.ES
-['.d']
-.EE
-
-.IP DVIPDF
-The TeX DVI file to PDF file converter.
-
-.IP DVIPDFFLAGS
-General options passed to the TeX DVI file to PDF file converter.
-
-.IP DVIPDFCOM
-The command line used to convert TeX DVI files into a PDF file.
-
-.IP DVIPS
-The TeX DVI file to PostScript converter.
-
-.IP DVIPSFLAGS
-General options passed to the TeX DVI file to PostScript converter.
-
-.IP ENV
-A dictionary of environment variables
-to use when invoking commands. When ENV is used in a command all list
-values will be joined using the path separator and any other non-string
-values will simply be coerced to a string.
-Note that, by default,
-.B scons
-does
-.I not
-propagate the environment in force when you
-execute
-.B scons
-to the commands used to build target files.
-This is so that builds will be guaranteed
-repeatable regardless of the environment
-variables set at the time
-.B scons
-is invoked.
-
-If you want to propagate your
-environment variables
-to the commands executed
-to build target files,
-you must do so explicitly:
-
-.ES
-import os
-env = Environment(ENV = os.environ)
-.EE
-
-.RS
-Note that you can choose only to propagate
-certain environment variables.
-A common example is
-the system
-.B PATH
-environment variable,
-so that
-.B scons
-uses the same utilities
-as the invoking shell (or other process):
-.RE
-
-.ES
-import os
-env = Environment(ENV = {'PATH' : os.environ['PATH']})
-.EE
-
-.IP ESCAPE
-A function that will be called to escape shell special characters in
-command lines. The function should take one argument: the command line
-string to escape; and should return the escaped command line.
-
-.IP F77
-The Fortran 77 compiler.
-You should normally set the $FORTRAN variable,
-which specifies the default Fortran compiler
-for all Fortran versions.
-You only need to set $F77 if you need to use a specific compiler
-or compiler version for Fortran 77 files.
-
-.IP F77COM
-The command line used to compile a Fortran 77 source file to an object file.
-You only need to set $F77COM if you need to use a specific
-command line for Fortran 77 files.
-You should normally set the $FORTRANCOM variable,
-which specifies the default command line
-for all Fortran versions.
-
-.IP F77FLAGS
-General user-specified options that are passed to the Fortran 77 compiler.
-Note that this variable does
-.I not
-contain
-.B -I
-(or similar) include search path options
-that scons generates automatically from $F77PATH.
-See
-.BR _F77INCFLAGS ,
-below,
-for the variable that expands to those options.
-You only need to set $F77FLAGS if you need to define specific
-user options for Fortran 77 files.
-You should normally set the $FORTRANFLAGS variable,
-which specifies the user-specified options
-passed to the default Fortran compiler
-for all Fortran versions.
-
-.IP _F77INCFLAGS
-An automatically-generated construction variable
-containing the Fortran 77 compiler command-line options
-for specifying directories to be searched for include files.
-The value of $_F77INCFLAGS is created
-by appending $INCPREFIX and $INCSUFFIX
-to the beginning and end
-of each directory in $F77PATH.
-
-.IP F77PATH
-The list of directories that the Fortran 77 compiler will search for include
-directories. The implicit dependency scanner will search these
-directories for include files. Don't explicitly put include directory
-arguments in $F77FLAGS because the result will be non-portable
-and the directories will not be searched by the dependency scanner. Note:
-directory names in $F77PATH will be looked-up relative to the SConscript
-directory when they are used in a command. To force
-.B scons
-to look-up a directory relative to the root of the source tree use #:
-You only need to set $F77PATH if you need to define a specific
-include path for Fortran 77 files.
-You should normally set the $FORTRANPATH variable,
-which specifies the include path
-for the default Fortran compiler
-for all Fortran versions.
-
-.ES
-env = Environment(F77PATH='#/include')
-.EE
-
-.IP
-The directory look-up can also be forced using the
-.BR Dir ()
-function:
-
-.ES
-include = Dir('include')
-env = Environment(F77PATH=include)
-.EE
-
-.IP
-The directory list will be added to command lines
-through the automatically-generated
-$_F77INCFLAGS
-construction variable,
-which is constructed by
-appending the values of the
-$INCPREFIX and $INCSUFFIX
-construction variables
-to the beginning and end
-of each directory in $F77PATH.
-Any command lines you define that need
-the F77PATH directory list should
-include $_F77INCFLAGS:
-
-.ES
-env = Environment(F77COM="my_compiler $_F77INCFLAGS -c -o $TARGET $SOURCE")
-.EE
-
-.IP F77PPCOM
-The command line used to compile a Fortran 77 source file to an object file
-after first running the file through the C preprocessor.
-Any options specified in the $F77FLAGS and $CPPFLAGS construction variables
-are included on this command line.
-You only need to set $F77PPCOM if you need to use a specific
-C-preprocessor command line for Fortran 77 files.
-You should normally set the $FORTRANPPCOM variable,
-which specifies the default C-preprocessor command line
-for all Fortran versions.
-
-.IP F90
-The Fortran 90 compiler.
-You should normally set the $FORTRAN variable,
-which specifies the default Fortran compiler
-for all Fortran versions.
-You only need to set $F90 if you need to use a specific compiler
-or compiler version for Fortran 90 files.
-
-.IP F90COM
-The command line used to compile a Fortran 90 source file to an object file.
-You only need to set $F90COM if you need to use a specific
-command line for Fortran 90 files.
-You should normally set the $FORTRANCOM variable,
-which specifies the default command line
-for all Fortran versions.
-
-.IP F90FLAGS
-General user-specified options that are passed to the Fortran 90 compiler.
-Note that this variable does
-.I not
-contain
-.B -I
-(or similar) include search path options
-that scons generates automatically from $F90PATH.
-See
-.BR _F90INCFLAGS ,
-below,
-for the variable that expands to those options.
-You only need to set $F90FLAGS if you need to define specific
-user options for Fortran 90 files.
-You should normally set the $FORTRANFLAGS variable,
-which specifies the user-specified options
-passed to the default Fortran compiler
-for all Fortran versions.
-
-.IP _F90INCFLAGS
-An automatically-generated construction variable
-containing the Fortran 90 compiler command-line options
-for specifying directories to be searched for include files.
-The value of $_F90INCFLAGS is created
-by appending $INCPREFIX and $INCSUFFIX
-to the beginning and end
-of each directory in $F90PATH.
-
-.IP F90PATH
-The list of directories that the Fortran 90 compiler will search for include
-directories. The implicit dependency scanner will search these
-directories for include files. Don't explicitly put include directory
-arguments in $F90FLAGS because the result will be non-portable
-and the directories will not be searched by the dependency scanner. Note:
-directory names in $F90PATH will be looked-up relative to the SConscript
-directory when they are used in a command. To force
-.B scons
-to look-up a directory relative to the root of the source tree use #:
-You only need to set $F90PATH if you need to define a specific
-include path for Fortran 90 files.
-You should normally set the $FORTRANPATH variable,
-which specifies the include path
-for the default Fortran compiler
-for all Fortran versions.
-
-.ES
-env = Environment(F90PATH='#/include')
-.EE
-
-.IP
-The directory look-up can also be forced using the
-.BR Dir ()
-function:
-
-.ES
-include = Dir('include')
-env = Environment(F90PATH=include)
-.EE
-
-.IP
-The directory list will be added to command lines
-through the automatically-generated
-$_F90INCFLAGS
-construction variable,
-which is constructed by
-appending the values of the
-$INCPREFIX and $INCSUFFIX
-construction variables
-to the beginning and end
-of each directory in $F90PATH.
-Any command lines you define that need
-the F90PATH directory list should
-include $_F90INCFLAGS:
-
-.ES
-env = Environment(F90COM="my_compiler $_F90INCFLAGS -c -o $TARGET $SOURCE")
-.EE
-
-.IP F90PPCOM
-The command line used to compile a Fortran 90 source file to an object file
-after first running the file through the C preprocessor.
-Any options specified in the $F90FLAGS and $CPPFLAGS construction variables
-are included on this command line.
-You only need to set $F90PPCOM if you need to use a specific
-C-preprocessor command line for Fortran 90 files.
-You should normally set the $FORTRANPPCOM variable,
-which specifies the default C-preprocessor command line
-for all Fortran versions.
-
-.IP F95
-The Fortran 95 compiler.
-You should normally set the $FORTRAN variable,
-which specifies the default Fortran compiler
-for all Fortran versions.
-You only need to set $F95 if you need to use a specific compiler
-or compiler version for Fortran 95 files.
-
-.IP F95COM
-The command line used to compile a Fortran 95 source file to an object file.
-You only need to set $F95COM if you need to use a specific
-command line for Fortran 95 files.
-You should normally set the $FORTRANCOM variable,
-which specifies the default command line
-for all Fortran versions.
-
-.IP F95FLAGS
-General user-specified options that are passed to the Fortran 95 compiler.
-Note that this variable does
-.I not
-contain
-.B -I
-(or similar) include search path options
-that scons generates automatically from $F95PATH.
-See
-.BR _F95INCFLAGS ,
-below,
-for the variable that expands to those options.
-You only need to set $F95FLAGS if you need to define specific
-user options for Fortran 95 files.
-You should normally set the $FORTRANFLAGS variable,
-which specifies the user-specified options
-passed to the default Fortran compiler
-for all Fortran versions.
-
-.IP _F95INCFLAGS
-An automatically-generated construction variable
-containing the Fortran 95 compiler command-line options
-for specifying directories to be searched for include files.
-The value of $_F95INCFLAGS is created
-by appending $INCPREFIX and $INCSUFFIX
-to the beginning and end
-of each directory in $F95PATH.
-
-.IP F95PATH
-The list of directories that the Fortran 95 compiler will search for include
-directories. The implicit dependency scanner will search these
-directories for include files. Don't explicitly put include directory
-arguments in $F95FLAGS because the result will be non-portable
-and the directories will not be searched by the dependency scanner. Note:
-directory names in $F95PATH will be looked-up relative to the SConscript
-directory when they are used in a command. To force
-.B scons
-to look-up a directory relative to the root of the source tree use #:
-You only need to set $F95PATH if you need to define a specific
-include path for Fortran 95 files.
-You should normally set the $FORTRANPATH variable,
-which specifies the include path
-for the default Fortran compiler
-for all Fortran versions.
-
-.ES
-env = Environment(F95PATH='#/include')
-.EE
-
-.IP
-The directory look-up can also be forced using the
-.BR Dir ()
-function:
-
-.ES
-include = Dir('include')
-env = Environment(F95PATH=include)
-.EE
-
-.IP
-The directory list will be added to command lines
-through the automatically-generated
-$_F95INCFLAGS
-construction variable,
-which is constructed by
-appending the values of the
-$INCPREFIX and $INCSUFFIX
-construction variables
-to the beginning and end
-of each directory in $F95PATH.
-Any command lines you define that need
-the F95PATH directory list should
-include $_F95INCFLAGS:
-
-.ES
-env = Environment(F95COM="my_compiler $_F95INCFLAGS -c -o $TARGET $SOURCE")
-.EE
-
-.IP F95PPCOM
-The command line used to compile a Fortran 95 source file to an object file
-after first running the file through the C preprocessor.
-Any options specified in the $F95FLAGS and $CPPFLAGS construction variables
-are included on this command line.
-You only need to set $F95PPCOM if you need to use a specific
-C-preprocessor command line for Fortran 95 files.
-You should normally set the $FORTRANPPCOM variable,
-which specifies the default C-preprocessor command line
-for all Fortran versions.
-
-.IP FORTRAN
-The default Fortran compiler
-for all versions of Fortran.
-
-.IP FORTRANCOM 
-The command line used to compile a Fortran source file to an object file.
-By default, any options specified
-in the $FORTRANFLAGS, $CPPFLAGS, $_CPPDEFFLAGS, 
-$_FORTRANMODFLAG, and $_FORTRANINCFLAGS construction variables
-are included on this command line.
-
-.IP FORTRANFLAGS
-General user-specified options that are passed to the Fortran compiler.
-Note that this variable does
-.I not
-contain
-.B -I
-(or similar) include or module search path options
-that scons generates automatically from $FORTRANPATH.
-See
-.BR _FORTRANINCFLAGS and _FORTRANMODFLAGS,
-below,
-for the variables that expand those options.
-
-.IP _FORTRANINCFLAGS
-An automatically-generated construction variable
-containing the Fortran compiler command-line options
-for specifying directories to be searched for include 
-files and module files.
-The value of $_FORTRANINCFLAGS is created
-by prepending/appending $INCPREFIX and $INCSUFFIX
-to the beginning and end
-of each directory in $FORTRANPATH.
-
-.IP FORTRANMODDIR
-Directory location where the Fortran compiler should place
-any module files it generates.  This variable is empty, by default. Some 
-Fortran compilers will internally append this directory in the search path 
-for module files, as well
-
-.IP FORTRANMODDIRPREFIX
-The prefix used to specify a module directory on the Fortran compiler command
-line.
-This will be appended to the beginning of the directory
-in the $FORTRANMODDIR construction variables
-when the $_FORTRANMODFLAG variables is automatically generated.
-
-.IP FORTRANMODDIRSUFFIX
-The suffix used to specify a module directory on the Fortran compiler command
-line.
-This will be appended to the beginning of the directory
-in the $FORTRANMODDIR construction variables
-when the $_FORTRANMODFLAG variables is automatically generated.
-
-.IP FORTRANMODFLAG
-An automatically-generated construction variable
-containing the Fortran compiler command-line option
-for specifying the directory location where the Fortran
-compiler should place any module files that happen to get 
-generated during compilation.
-The value of $_FORTRANMODFLAG is created
-by prepending/appending $FORTRANMODDIRPREFIX and $FORTRANMODDIRSUFFIX
-to the beginning and end of the directory in $FORTRANMODDIR.
-
-.IP FORTRANMODPREFIX
-The module file prefix used by the Fortran compiler.  SCons assumes that
-the Fortran compiler follows the quasi-standard naming convention for
-module files of
-.I <module_name>.mod.
-As a result, this variable is left empty, by default.  For situations in
-which the compiler does not necessarily follow the normal convention,
-the user may use this variable.  Its value will be appended to every
-module file name as scons attempts to resolve dependencies.
-
-.IP FORTRANMODSUFFIX
-The module file suffix used by the Fortran compiler.  SCons assumes that
-the Fortran compiler follows the quasi-standard naming convention for
-module files of
-.I <module_name>.mod.
-As a result, this variable is set to ".mod", by default.  For situations
-in which the compiler does not necessarily follow the normal convention,
-the user may use this variable.  Its value will be appended to every
-module file name as scons attempts to resolve dependencies.
-
-.IP FORTRANPATH
-The list of directories that the Fortran compiler will search for
-include files and (for some compilers) module files. The Fortran implicit
-dependency scanner will search these directories for include files (but
-not module files since they are autogenerated and, as such, may not
-actually exist at the time the scan takes place). Don't explicitly put
-include directory arguments in FORTRANFLAGS because the result will be
-non-portable and the directories will not be searched by the dependency
-scanner. Note: directory names in FORTRANPATH will be looked-up relative
-to the SConscript directory when they are used in a command. To force
-.B scons
-to look-up a directory relative to the root of the source tree use #:
-
-.ES
-env = Environment(FORTRANPATH='#/include')
-.EE
-
-.IP
-The directory look-up can also be forced using the 
-.BR Dir ()
-function:
-
-.ES
-include = Dir('include')
-env = Environment(FORTRANPATH=include)
-.EE
-
-.IP
-The directory list will be added to command lines
-through the automatically-generated
-$_FORTRANINCFLAGS
-construction variable,
-which is constructed by
-appending the values of the
-$INCPREFIX and $INCSUFFIX
-construction variables
-to the beginning and end
-of each directory in $FORTRANPATH.
-Any command lines you define that need
-the FORTRANPATH directory list should
-include $_FORTRANINCFLAGS:
-
-.ES
-env = Environment(FORTRANCOM="my_compiler $_FORTRANINCFLAGS -c -o $TARGET $SOURCE")
-.EE
-
-.IP FORTRANPPCOM 
-The command line used to compile a Fortran source file to an object file
-after first running the file through the C preprocessor. 
-By default, any options specified in the $FORTRANFLAGS, $CPPFLAGS,
-_CPPDEFFLAGS, $_FORTRANMODFLAG, and $_FORTRANINCFLAGS
-construction variables are included on this command line.
-
-.IP FORTRANSUFFIXES
-The list of suffixes of files that will be scanned
-for Fortran implicit dependencies
-(INCLUDE lines & USE statements).
-The default list is:
-
-.ES
-[".f", ".F", ".for", ".FOR", ".ftn", ".FTN", ".fpp", ".FPP",
-".f77", ".F77", ".f90", ".F90", ".f95", ".F95"]
-.EE
-
-.IP File
-A function that converts a file name into a File instance relative to the
-target being built. 
-
-.IP GS
-The Ghostscript program used to convert PostScript to PDF files.
-
-.IP GSFLAGS
-General options passed to the Ghostscript program
-when converting PostScript to PDF files.
-
-.IP GSCOM
-The Ghostscript command line used to convert PostScript to PDF files.
-
-.IP IDLSUFFIXES
-The list of suffixes of files that will be scanned
-for IDL implicit dependencies
-(#include or import lines).
-The default list is:
-
-.ES
-[".idl", ".IDL"]
-.EE
-
-.IP INCPREFIX
-The prefix used to specify an include directory on the C compiler command
-line.
-This will be appended to the beginning of each directory
-in the $CPPPATH and $FORTRANPATH construction variables
-when the $_CPPINCFLAGS and $_FORTRANINCFLAGS
-variables are automatically generated.
-
-.IP INCSUFFIX
-The suffix used to specify an include directory on the C compiler command
-line.
-This will be appended to the end of each directory
-in the $CPPPATH and $FORTRANPATH construction variables
-when the $_CPPINCFLAGS and $_FORTRANINCFLAGS
-variables are automatically generated.
-
-.IP INSTALL
-A function to be called to install a file into a
-destination file name.
-The default function copies the file into the destination
-(and sets the destination file's mode and permission bits
-to match the source file's).
-The function takes the following arguments:
-
-.ES
-def install(dest, source, env):
-.EE
-.IP
-.I dest
-is the path name of the destination file.
-.I source
-is the path name of the source file.
-.I env
-is the construction environment
-(a dictionary of construction values)
-in force for this file installation.
-
-.IP JAR
-The Java archive tool.
-
-.IP JARCHDIR
-The directory to which the Java archive tool should change
-(using the
-.B \-C
-option).
-
-.IP JARCOM
-The command line used to call the Java archive tool.
-
-.IP JARFLAGS
-General options passed to the Java archive tool.
-By default this is set to
-.B cf
-to create the necessary
-.I jar
-file.
-
-.IP JARSUFFIX
-The suffix for Java archives:
-.B .jar
-by default.
-
-.IP JAVAC
-The Java compiler.
-
-.IP JAVACCOM
-The command line used to compile a directory tree containing
-Java source files to
-corresponding Java class files.
-Any options specified in the $JAVACFLAGS construction variable
-are included on this command line.
-
-.IP JAVACFLAGS
-General options that are passed to the Java compiler.
-
-.IP JAVACLASSDIR
-The directory in which Java class files may be found.
-This is stripped from the beginning of any Java .class
-file names supplied to the
-.B JavaH
-builder.
-
-.IP JAVACLASSSUFFIX
-The suffix for Java class files;
-.B .class
-by default.
-
-.IP JAVAH
-The Java generator for C header and stub files.
-
-.IP JAVAHCOM
-The command line used to generate C header and stub files
-from Java classes.
-Any options specified in the $JAVAHFLAGS construction variable
-are included on this command line.
-
-.IP JAVAHFLAGS
-General options passed to the C header and stub file generator
-for Java classes.
-
-.IP JAVASUFFIX
-The suffix for Java files;
-.B .java
-by default.
-
-.IP LATEX
-The LaTeX structured formatter and typesetter.
-
-.IP LATEXCOM
-The command line used to call the LaTeX structured formatter and typesetter.
-
-.IP LATEXFLAGS
-General options passed to the LaTeX structured formatter and typesetter.
-
-.IP LEX
-The lexical analyzer generator.
-
-.IP LEXFLAGS
-General options passed to the lexical analyzer generator.
-
-.IP LEXCOM
-The command line used to call the lexical analyzer generator
-to generate a source file.
-
-.IP _LIBDIRFLAGS
-An automatically-generated construction variable
-containing the linker command-line options
-for specifying directories to be searched for library.
-The value of $_LIBDIRFLAGS is created
-by appending $LIBDIRPREFIX and $LIBDIRSUFFIX
-to the beginning and end
-of each directory in $LIBPATH.
-
-.IP LIBDIRPREFIX
-The prefix used to specify a library directory on the linker command line.
-This will be appended to the beginning of each directory
-in the $LIBPATH construction variable
-when the $_LIBDIRFLAGS variable is automatically generated.
-
-.IP LIBDIRSUFFIX
-The suffix used to specify a library directory on the linker command line.
-This will be appended to the end of each directory
-in the $LIBPATH construction variable
-when the $_LIBDIRFLAGS variable is automatically generated.
-
-.IP _LIBFLAGS
-An automatically-generated construction variable
-containing the linker command-line options
-for specifying libraries to be linked with the resulting target.
-The value of $_LIBFLAGS is created
-by appending $LIBLINKPREFIX and $LIBLINKSUFFIX
-to the beginning and end
-of each directory in $LIBS.
-
-.IP LIBLINKPREFIX
-The prefix used to specify a library to link on the linker command line.
-This will be appended to the beginning of each library
-in the $LIBS construction variable
-when the $_LIBFLAGS variable is automatically generated.
-
-.IP LIBLINKSUFFIX
-The suffix used to specify a library to link on the linker command line.
-This will be appended to the end of each library
-in the $LIBS construction variable
-when the $_LIBFLAGS variable is automatically generated.
-
-.IP LIBPATH
-The list of directories that will be searched for libraries.
-The implicit dependency scanner will search these
-directories for include files. Don't explicitly put include directory
-arguments in $LINKFLAGS or $SHLINKFLAGS
-because the result will be non-portable
-and the directories will not be searched by the dependency scanner. Note:
-directory names in LIBPATH will be looked-up relative to the SConscript
-directory when they are used in a command. To force 
-.B scons
-to look-up a directory relative to the root of the source tree use #:
-
-.ES
-env = Environment(LIBPATH='#/libs')
-.EE
-
-.IP
-The directory look-up can also be forced using the 
-.BR Dir ()
-function:
-
-.ES
-libs = Dir('libs')
-env = Environment(LIBPATH=libs)
-.EE
-
-.IP
-The directory list will be added to command lines
-through the automatically-generated
-$_LIBDIRFLAGS
-construction variable,
-which is constructed by
-appending the values of the
-$LIBDIRPREFIX and $LIBDIRSUFFIX
-construction variables
-to the beginning and end
-of each directory in $LIBPATH.
-Any command lines you define that need
-the LIBPATH directory list should
-include $_LIBDIRFLAGS:
-
-.ES
-env = Environment(LINKCOM="my_linker $_LIBDIRFLAGS $_LIBFLAGS -o $TARGET $SOURCE")
-.EE
-
-.IP LIBPREFIX
-The prefix used for (static) library file names.
-A default value is set for each platform
-(posix, win32, os2, etc.),
-but the value is overridden by individual tools
-(ar, mslib, sgiar, sunar, tlib, etc.)
-to reflect the names of the libraries they create.
-
-.IP LIBPREFIXES
-An array of legal prefixes for library file names.
-
-.IP LIBS
-A list of one or more libraries
-that will be linked with
-any executable programs
-created by this environment.
-
-.IP
-The library list will be added to command lines
-through the automatically-generated
-$_LIBFLAGS
-construction variable,
-which is constructed by
-appending the values of the
-$LIBLINKPREFIX and $LIBLINKSUFFIX
-construction variables
-to the beginning and end
-of each directory in $LIBS.
-Any command lines you define that need
-the LIBS library list should
-include $_LIBFLAGS:
-
-.ES
-env = Environment(LINKCOM="my_linker $_LIBDIRFLAGS $_LIBFLAGS -o $TARGET $SOURCE")
-.EE
-
-.IP LIBSUFFIX 
-The suffix used for (static) library file names.
-A default value is set for each platform
-(posix, win32, os2, etc.),
-but the value is overridden by individual tools
-(ar, mslib, sgiar, sunar, tlib, etc.)
-to reflect the names of the libraries they create.
-
-.IP LIBSUFFIXES
-An array of legal suffixes for library file names.
-
-.IP LINK
-The linker.
-
-.IP LINKFLAGS
-General user options passed to the linker.
-Note that this variable should
-.I not
-contain
-.B -l
-(or similar) options for linking with the libraries listed in $LIBS,
-nor
-.B -L
-(or similar) library search path options
-that scons generates automatically from $LIBPATH.
-See
-.BR _LIBFLAGS ,
-above,
-for the variable that expands to library-link options,
-and
-.BR _LIBDIRFLAGS ,
-above,
-for the variable that expands to library search path options.
-
-.IP LINKCOM
-The command line used to link object files into an executable.
-
-.IP M4
-The M4 macro preprocessor.
-
-.IP M4FLAGS
-General options passed to the M4 macro preprocessor.
-
-.IP M4COM
-The command line used to pass files through the macro preprocessor.
-
-.IP MAXLINELENGTH
-The maximum number of characters allowed on an external command line.
-On Win32 systems,
-link lines longer than this many characters
-are linke via a temporary file name.
-
-.IP MSVS
-When the Microsoft Visual Studio tools are initialized, they set up
-this dictionary with the following keys:
-
-.B VERSION:
-the version of MSVS being used (can be set via
-MSVS_VERSION)
-
-.B VERSIONS:
-the available versions of MSVS installed
-
-.B VCINSTALLDIR:
-installed directory of Visual C++
-
-.B VSINSTALLDIR:
-installed directory of Visual Studio
-
-.B FRAMEWORKDIR:
-installed directory of the .NET framework
-
-.B FRAMEWORKVERSIONS:
-list of installed versions of the .NET framework, sorted latest to oldest.
-
-.B FRAMEWORKVERSION:
-latest installed version of the .NET framework
-
-.B FRAMEWORKSDKDIR:
-installed location of the .NET SDK.
-
-.B PLATFORMSDKDIR:
-installed location of the Platform SDK.
-
-.B PLATFORMSDK_MODULES:
-dictionary of installed Platform SDK modules,
-where the dictionary keys are keywords for the various modules, and
-the values are 2-tuples where the first is the release date, and the
-second is the version number.
-
-If a value isn't set, it wasn't available in the registry.
-
-.IP MSVS_IGNORE_IDE_PATHS
-Tells the MS Visual Studio tools to use minimal INCLUDE, LIB, and PATH settings,
-instead of the settings from the IDE.
-
-For Visual Studio, SCons will (by default) automatically determine
-where MSVS is installed, and use the LIB, INCLUDE, and PATH variables
-set by the IDE.  You can override this behavior by setting these
-variables after Environment initialization, or by setting
-.B MSVS_IGNORE_IDE_PATHS = 1
-in the Environment initialization.
-Specifying this will not leave these unset, but will set them to a
-minimal set of paths needed to run the tools successfully.
-
-.ES
-For VS6, the mininimal set is:
-   INCLUDE:'<VSDir>\\VC98\\ATL\\include;<VSDir>\\VC98\\MFC\\include;<VSDir>\\VC98\\include'
-   LIB:'<VSDir>\\VC98\\MFC\\lib;<VSDir>\\VC98\\lib'
-   PATH:'<VSDir>\\Common\\MSDev98\\bin;<VSDir>\\VC98\\bin'
-For VS7, it is:
-   INCLUDE:'<VSDir>\\Vc7\\atlmfc\\include;<VSDir>\\Vc7\\include'
-   LIB:'<VSDir>\\Vc7\\atlmfc\\lib;<VSDir>\\Vc7\\lib'
-   PATH:'<VSDir>\\Common7\\Tools\\bin;<VSDir>\\Common7\\Tools;<VSDir>\\Vc7\\bin'
-.EE
-
-.IP
-Where '<VSDir>' is the installed location of Visual Studio.
-
-.IP MSVS_USE_MFC_DIRS
-Tells the MS Visual Studio tool(s) to use
-the MFC directories in its default paths
-for compiling and linking.
-Under MSVS version 6,
-setting
-.B MSVS_USE_MFC_DIRS
-to a non-zero value
-adds the
-.B "ATL\\\\include"
-and
-.B "MFC\\\\include"
-directories to
-the default
-.B INCLUDE
-external environment variable,
-and adds the
-.B "MFC\\\\lib"
-directory to
-the default
-.B LIB
-external environment variable.
-Under MSVS version 7,
-setting
-.B MSVS_USE_MFC_DIRS
-to a non-zero value
-adds the
-.B "atlmfc\\\\include"
-directory to the default
-.B INCLUDE
-external environment variable,
-and adds the
-.B "atlmfc\\\\lib"
-directory to the default
-.B LIB
-external environment variable.
-The current default value is
-.BR 1 ,
-which means these directories
-are added to the paths by default.
-This default value is likely to change
-in a future release,
-so users who want the ATL and MFC
-values included in their paths
-are encouraged to enable the
-.B MSVS_USE_MFC_DIRS
-value explicitly
-to avoid future incompatibility.
-This variable has no effect if the
-.BR INCLUDE
-or
-.BR LIB
-environment variables are set explictly.
-
-.IP MSVS_VERSION
-Sets the preferred version of MSVS to use.
-
-SCons will (by default) select the latest version of MSVS
-installed on your machine.  So, if you have version 6 and version 7
-(MSVS .NET) installed, it will prefer version 7.  You can override this by
-specifying the 
-.B MSVS_VERSION
-variable in the Environment initialization, setting it to the
-appropriate version ('6.0' or '7.0', for example).
-If the given version isn't installed, tool initialization will fail.
-
-.IP MSVSPROJECTCOM
-The action used to generate Microsoft Visual Studio
-project and solution files.
-
-.IP MSVSPROJECTSUFFIX
-The suffix used for Microsoft Visual Studio project (DSP) files.
-The default value is
-.B .vcproj
-when using Visual Studio version 7.x (.NET),
-and
-.B .dsp
-when using earlier versions of Visual Studio.
-
-.IP MSVSSOLUTIONSUFFIX
-The suffix used for Microsoft Visual Studio solution (DSW) files.
-The default value is
-.B .sln
-when using Visual Studio version 7.x (.NET),
-and
-.B .dsw
-when using earlier versions of Visual Studio.
-
-.IP no_import_lib
-When set to non-zero,
-suppresses creation of a corresponding Win32 static import lib by the
-.B SharedLibrary
-builder when used with
-MinGW or Microsoft Visual Studio.
-This also suppresses creation
-of an export (.exp) file
-when using Microsoft Visual Studio.
-
-.IP OBJPREFIX 
-The prefix used for (static) object file names.
-
-.IP OBJSUFFIX 
-The suffix used for (static) object file names.
-
-.IP P4
-The Perforce executable.
-
-.IP P4COM
-The command line used to
-fetch source files from Perforce.
-
-.IP P4FLAGS
-General options that are passed to Perforce.
-
-.IP PCH
-The Microsoft Visual C++ precompiled header that will be used when compiling
-object files. This variable is ignored by tools other than Microsoft Visual C++.
-When this variable is
-defined SCons will add options to the compiler command line to
-cause it to use the precompiled header, and will also set up the
-dependencies for the PCH file. Example: 
-
-.ES
-env['PCH'] = 'StdAfx.pch'
-.EE
-
-.IP PCHSTOP
-This variable specifies how much of a source file is precompiled. This
-variable is ignored by tools other than Microsoft Visual C++, or when
-the PCH variable is not being used. When this variable is define it
-must be a string that is the name of the header that
-is included at the end of the precompiled portion of the source files, or
-the empty string if the "#pragma hrdstop" construct is being used:
-
-.ES
-env['PCHSTOP'] = 'StdAfx.h'
-.EE
-
-.IP PDB
-The Microsoft Visual C++ PDB file that will store debugging information for
-object files, shared libraries, and programs. This variable is ignored by
-tools other than Microsoft Visual C++.
-When this variable is
-defined SCons will add options to the compiler and linker command line to
-cause them to generate external debugging information, and will also set up the
-dependencies for the PDB file. Example:
-
-.ES
-env['PDB'] = 'hello.pdb'
-.EE
-
-.IP PDFCOM
-A deprecated synonym for $DVIPDFCOM.
-
-.IP PDFPREFIX
-The prefix used for PDF file names.
-
-.IP PDFSUFFIX
-The suffix used for PDF file names.
-
-.IP PLATFORM
-The name of the platform used to create the Environment.  If no platform is
-specified when the Environment is created,
-.B SCons
-autodetects the platform.
-
-.ES
-env = Environment(tools = [])
-if env['PLATFORM'] == 'cygwin':
-    Tool('mingw')(env)
-else:
-    Tool('msvc')(env)
-.EE
-
-.IP PRINT_CMD_LINE_FUNC
-A Python function used to print the command lines as they are executed
-(assuming command printing is not disabled by the
-.B -q
-or
-.B -s
-options or their equivalents).
-The function should take four arguments:
-.IR s ,
-the command being executed (a string),
-.IR target ,
-the target being built (file node, list, or string name(s)),
-.IR source ,
-the source(s) used (file node, list, or string name(s)), and
-.IR env ,
-the environment being used.
-
-The function must do the printing itself.  The default implementation,
-used if this variable is not set or is None, is:
-.ES
-def print_cmd_line(s, target, source, env):
-  sys.stdout.write(s + "\n")
-.EE
-
-Here's an example of a more interesting function:
-.ES
-def print_cmd_line(s, target, source, env):
-   sys.stdout.write("Building %s -> %s...\n" %
-    (' and '.join([str(x) for x in source]),
-     ' and '.join([str(x) for x in target])))
-env=Environment(PRINT_CMD_LINE_FUNC=print_cmd_line)
-env.Program('foo', 'foo.c')
-.EE
-
-This just prints "Building <targetname> from <sourcename>..." instead
-of the actual commands.
-Such a function could also log the actual commands to a log file,
-for example.
-
-.IP PROGPREFIX
-The prefix used for executable file names.
-
-.IP PROGSUFFIX
-The suffix used for executable file names.
-
-.IP PSCOM
-The command line used to convert TeX DVI files into a PostScript file.
-
-.IP PSPREFIX
-The prefix used for PostScript file names.
-
-.IP PSSUFFIX
-The prefix used for PostScript file names.
-
-.IP QTDIR
-The qt tool tries to take this from os.environ.
-It also initializes all QT_*
-construction variables listed below.
-(Note that all paths are constructed
-with python's os.path.join() method,
-but are listed here with the '/' separator
-for easier reading.)
-In addition, the construction environment
-variables CPPPATH, LIBPATH and LIBS may be modified
-and the variables
-PROGEMITTER, SHLIBEMITTER and LIBEMITTER
-are modified. Because the build-performance is affected when using this tool,
-you have to explicitly specify it at Environment creation:
-
-.ES
-Environment(tools=['default','qt'])
-.EE
-.IP
-The qt tool supports the following operations:
-
-.B Automatic moc file generation from header files.
-You do not have to specify moc files explicitly, the tool does it for you.
-However, there are a few preconditions to do so: Your header file must have
-the same filebase as your implementation file and must stay in the same
-directory. It must have one of the suffixes .h, .hpp, .H, .hxx, .hh. You 
-can turn off automatic moc file generation by setting QT_AUTOSCAN to 0.
-See also the corresponding builder method
-.B Moc()
-
-.B Automatic moc file generation from cxx files.
-As stated in the qt documentation, include the moc file at the end of 
-the cxx file. Note that you have to include the file, which is generated
-by the transformation ${QT_MOCCXXPREFIX}<basename>${QT_MOCCXXSUFFIX}, by default
-<basename>.moc. A warning is generated after building the moc file, if you 
-do not include the correct file. If you are using BuildDir, you may 
-need to specify duplicate=1. You can turn off automatic moc file generation 
-by setting QT_AUTOSCAN to 0. See also the corresponding builder method
-.B Moc()
-
-.B Automatic handling of .ui files.
-The implementation files generated from .ui files are handled much the same
-as yacc or lex files. Each .ui file given as a source of Program, Library or
-SharedLibrary will generate three files, the declaration file, the 
-implementation file and a moc file. Because there are also generated headers, 
-you may need to specify duplicate=1 in calls to BuildDir. See also the corresponding builder method
-.B Uic()
-
-.IP QT_AUTOSCAN
-Turn off scanning for mocable files. Use the Moc Builder to explicitely 
-specify files to run moc on.
-
-.IP QT_BINPATH
-The path where the qt binaries are installed.
-The default value is '$QTDIR/bin'.
-
-.IP QT_CPPPATH
-The path where the qt header files are installed.
-The default value is '$QTDIR/include'.
-Note: If you set this variable to None, the tool won't change the CPPPATH
-construction variable.
-
-.IP QT_DEBUG 
-Prints lots of debugging information while scanning for moc files.
-
-.IP QT_LIBPATH
-The path where the qt libraries are installed.
-The default value is '$QTDIR/lib'. 
-Note: If you set this variable to None, the tool won't change the LIBPATH
-construction variable.
-
-.IP QT_LIB
-Default value is 'qt'. You may want to set this to 'qt-mt'. Note: If you set
-this variable to None, the tool won't change the LIBS variable.
-
-.IP QT_MOC
-Default value is '$QT_BINPATH/moc'.
-
-.IP QT_MOCCXXPREFIX
-Default value is ''. Prefix for moc output files, when source is a cxx file.
-
-.IP QT_MOCCXXSUFFIX
-Default value is '.moc'. Suffix for moc output files, when source is a cxx 
-file.
-
-.IP QT_MOCFROMCPPFLAGS
-Default value is '-i'. These flags are passed to moc, when moccing a
-cpp file.
-
-.IP QT_MOCFROMCXXCOM
-Command to generate a moc file from a cpp file.
-
-.IP QT_MOCFROMHCOM
-Command to generate a moc file from a header.
-
-.IP QT_MOCFROMHFLAGS
-Default value is ''. These flags are passed to moc, when moccing a header
-file.
-
-.IP QT_MOCHPREFIX
-Default value is 'moc_'. Prefix for moc output files, when source is a header.
-
-.IP QT_MOCHSUFFIX
-Default value is '$CXXFILESUFFIX'. Suffix for moc output files, when source is
-a header.
-
-.IP QT_UIC
-Default value is '$QT_BINPATH/uic'.
-
-.IP QT_UICDECLCOM
-Command to generate header files from .ui files.
-
-.IP QT_UICDECLFLAGS
-Default value is ''. These flags are passed to uic, when creating a a h
-file from a .ui file.
-
-.IP QT_UICDECLPREFIX
-Default value is ''. Prefix for uic generated header files.
-
-.IP QT_UICDECLSUFFIX
-Default value is '.h'. Suffix for uic generated header files.
-
-.IP QT_UICIMPLCOM
-Command to generate cxx files from .ui files.
-
-.IP QT_UICIMPLFLAGS
-Default value is ''. These flags are passed to uic, when creating a cxx
-file from a .ui file.
-
-.IP QT_UICIMPLPREFIX
-Default value is 'uic_'. Prefix for uic generated implementation files.
-
-.IP QT_UICIMPLSUFFIX
-Default value is '$CXXFILESUFFIX'. Suffix for uic generated implementation 
-files.
-
-.IP QT_UISUFFIX
-Default value is '.ui'. Suffix of designer input files.
-
-.IP RANLIB
-The archive indexer.
-
-.IP RANLIBFLAGS
-General options passed to the archive indexer.
-
-.IP RC
-The resource compiler used by the RES builder.
-
-.IP RCCOM
-The command line used by the RES builder.
-
-.IP RCFLAGS
-The flags passed to the resource compiler by the RES builder.
-
-.IP RCS
-The RCS executable.
-Note that this variable is not actually used
-for the command to fetch source files from RCS;
-see the
-.B RCS_CO
-construction variable, below.
-
-.IP RCS_CO 
-The RCS "checkout" executable,
-used to fetch source files from RCS.
-
-.IP RCS_COCOM
-The command line used to
-fetch (checkout) source files from RCS.
-
-.IP RCS_COFLAGS
-Options that are passed to the $RCS_CO command.
-
-.IP RDirs
-A function that converts a file name into a list of Dir instances by
-searching the repositories. 
-
-.IP RMIC
-The Java RMI stub compiler.
-
-.IP RMICCOM
-The command line used to compile stub
-and skeleton class files
-from Java classes that contain RMI implementations.
-Any options specified in the $RMICFLAGS construction variable
-are included on this command line.
-
-.IP RMICFLAGS
-General options passed to the Java RMI stub compiler.
-
-.IP RPCGEN
-The RPC protocol compiler.
-
-.IP RPCGENCLIENTFLAGS
-Options passed to the RPC protocol compiler
-when generating client side stubs.
-These are in addition to any flags specified in the
-.B RPCGENFLAGS
-construction variable.
-
-.IP RPCGENFLAGS
-General options passed to the RPC protocol compiler.
-
-.IP RPCGENHEADERFLAGS
-Options passed to the RPC protocol compiler
-when generating a header file.
-These are in addition to any flags specified in the
-.B RPCGENFLAGS
-construction variable.
-
-.IP RPCGENSERVICEFLAGS
-Options passed to the RPC protocol compiler
-when generating server side stubs.
-These are in addition to any flags specified in the
-.B RPCGENFLAGS
-construction variable.
-
-.IP RPCGENXDRFLAGS
-Options passed to the RPC protocol compiler
-when generating XDR routines.
-These are in addition to any flags specified in the
-.B RPCGENFLAGS
-construction variable.
-
-.IP RPATH
-A list of paths to search for shared libraries when running programs.
-Currently only used in the GNU linker (gnulink) and IRIX linker (sgilink).
-Ignored on platforms and toolchains that don't support it.
-Note that the paths added to RPATH
-are not transformed by
-.B scons
-in any way:  if you want an absolute
-path, you must make it absolute yourself.
-
-.IP SCANNERS
-A list of the available implicit dependency scanners.
-New file scanners may be added by
-appending to this list,
-although the more flexible approach
-is to associate scanners
-with a specific Builder.
-See the sections "Builder Objects"
-and "Scanner Objects,"
-below, for more information.
-
-.IP SCCS
-The SCCS executable.
-
-.IP SCCSCOM
-The command line used to
-fetch source files from SCCS.
-
-.IP SCCSFLAGS
-General options that are passed to SCCS.
-
-.IP SCCSGETFLAGS
-Options that are passed specifically to the SCCS "get" subcommand.
-This can be set, for example, to
-.I -e
-to check out editable files from SCCS.
-
-.IP SHCC
-The C compiler used for generating shared-library objects.
-
-.IP SHCCCOM
-The command line used to compile a C source file
-to a shared-library object file.
-Any options specified in the $SHCCFLAGS and $CPPFLAGS construction variables
-are included on this command line.
-
-.IP SHCCFLAGS
-Options that are passed to the C compiler
-to generate shared-library objects.
-
-.IP SHCXX
-The C++ compiler used for generating shared-library objects.
-
-.IP SHCXXCOM
-The command line used to compile a C++ source file
-to a shared-library object file.
-Any options specified in the $SHCXXFLAGS and $CPPFLAGS construction variables
-are included on this command line.
-
-.IP SHCXXFLAGS
-Options that are passed to the C++ compiler
-to generate shared-library objects.
-
-.IP SHELL
-A string naming the shell program that will be passed to the 
-.I SPAWN 
-function. 
-See the 
-.I SPAWN 
-construction variable for more information.
-
-.IP SHF77
-The Fortran 77 compiler used for generating shared-library objects.
-You should normally set the $SHFORTRANC variable,
-which specifies the default Fortran compiler
-for all Fortran versions.
-You only need to set $SHF77 if you need to use a specific compiler
-or compiler version for Fortran 77 files.
-
-.IP SHF77COM
-The command line used to compile a Fortran 77 source file
-to a shared-library object file.
-You only need to set $SHF77COM if you need to use a specific
-command line for Fortran 77 files.
-You should normally set the $SHFORTRANCOM variable,
-which specifies the default command line
-for all Fortran versions.
-
-.IP SHF77FLAGS
-Options that are passed to the Fortran 77 compiler
-to generated shared-library objects.
-You only need to set $SHF77FLAGS if you need to define specific
-user options for Fortran 77 files.
-You should normally set the $SHFORTRANFLAGS variable,
-which specifies the user-specified options
-passed to the default Fortran compiler
-for all Fortran versions.
-
-.IP SHF77PPCOM
-The command line used to compile a Fortran 77 source file to a
-shared-library object file
-after first running the file through the C preprocessor.
-Any options specified in the $SHF77FLAGS and $CPPFLAGS construction variables
-are included on this command line.
-You only need to set $SHF77PPCOM if you need to use a specific
-C-preprocessor command line for Fortran 77 files.
-You should normally set the $SHFORTRANPPCOM variable,
-which specifies the default C-preprocessor command line
-for all Fortran versions.
-
-.IP SHF90
-The Fortran 90 compiler used for generating shared-library objects.
-You should normally set the $SHFORTRANC variable,
-which specifies the default Fortran compiler
-for all Fortran versions.
-You only need to set $SHF90 if you need to use a specific compiler
-or compiler version for Fortran 90 files.
-
-.IP SHF90COM
-The command line used to compile a Fortran 90 source file
-to a shared-library object file.
-You only need to set $SHF90COM if you need to use a specific
-command line for Fortran 90 files.
-You should normally set the $SHFORTRANCOM variable,
-which specifies the default command line
-for all Fortran versions.
-
-.IP SHF90FLAGS
-Options that are passed to the Fortran 90 compiler
-to generated shared-library objects.
-You only need to set $SHF90FLAGS if you need to define specific
-user options for Fortran 90 files.
-You should normally set the $SHFORTRANFLAGS variable,
-which specifies the user-specified options
-passed to the default Fortran compiler
-for all Fortran versions.
-
-.IP SHF90PPCOM
-The command line used to compile a Fortran 90 source file to a
-shared-library object file
-after first running the file through the C preprocessor.
-Any options specified in the $SHF90FLAGS and $CPPFLAGS construction variables
-are included on this command line.
-You only need to set $SHF90PPCOM if you need to use a specific
-C-preprocessor command line for Fortran 90 files.
-You should normally set the $SHFORTRANPPCOM variable,
-which specifies the default C-preprocessor command line
-for all Fortran versions.
-
-.IP SHF95
-The Fortran 95 compiler used for generating shared-library objects.
-You should normally set the $SHFORTRANC variable,
-which specifies the default Fortran compiler
-for all Fortran versions.
-You only need to set $SHF95 if you need to use a specific compiler
-or compiler version for Fortran 95 files.
-
-.IP SHF95COM
-The command line used to compile a Fortran 95 source file
-to a shared-library object file.
-You only need to set $SHF95COM if you need to use a specific
-command line for Fortran 95 files.
-You should normally set the $SHFORTRANCOM variable,
-which specifies the default command line
-for all Fortran versions.
-
-.IP SHF95FLAGS
-Options that are passed to the Fortran 95 compiler
-to generated shared-library objects.
-You only need to set $SHF95FLAGS if you need to define specific
-user options for Fortran 95 files.
-You should normally set the $SHFORTRANFLAGS variable,
-which specifies the user-specified options
-passed to the default Fortran compiler
-for all Fortran versions.
-
-.IP SHF95PPCOM
-The command line used to compile a Fortran 95 source file to a
-shared-library object file
-after first running the file through the C preprocessor.
-Any options specified in the $SHF95FLAGS and $CPPFLAGS construction variables
-are included on this command line.
-You only need to set $SHF95PPCOM if you need to use a specific
-C-preprocessor command line for Fortran 95 files.
-You should normally set the $SHFORTRANPPCOM variable,
-which specifies the default C-preprocessor command line
-for all Fortran versions.
-
-.IP SHFORTRAN
-The default Fortran compiler used for generating shared-library objects.
-
-.IP SHFORTRANCOM
-The command line used to compile a Fortran source file
-to a shared-library object file.
-
-.IP SHFORTRANFLAGS
-Options that are passed to the Fortran compiler
-to generate shared-library objects.
-
-.IP SHFORTRANPPCOM
-The command line used to compile a Fortran source file to a
-shared-library object file
-after first running the file through the C preprocessor.
-Any options specified
-in the $SHFORTRANFLAGS and $CPPFLAGS construction variables
-are included on this command line.
-
-.IP SHLIBPREFIX
-The prefix used for shared library file names.
-
-.IP SHLIBSUFFIX
-The suffix used for shared library file names.
-
-.IP SHLINK
-The linker for programs that use shared libraries.
-
-.IP SHLINKFLAGS
-General user options passed to the linker for programs using shared libraries.
-Note that this variable should
-.I not
-contain
-.B -l
-(or similar) options for linking with the libraries listed in $LIBS,
-nor
-.B -L
-(or similar) include search path options
-that scons generates automatically from $LIBPATH.
-See
-.BR _LIBFLAGS ,
-above,
-for the variable that expands to library-link options,
-and
-.BR _LIBDIRFLAGS ,
-above,
-for the variable that expands to library search path options.
-
-.IP SHOBJPREFIX 
-The prefix used for shared object file names.
-
-.IP SHOBJSUFFIX 
-The suffix used for shared object file names.
-
-.IP SOURCE
-A reserved variable name
-that may not be set or used in a construction environment.
-(See "Variable Substitution," below.)
-
-.IP SOURCES
-A reserved variable name
-that may not be set or used in a construction environment.
-(See "Variable Substitution," below.)
-
-.IP SPAWN
-A command interpreter function that will be called to execute command line
-strings. The function must expect the following arguments:
-
-.ES
-def spawn(shell, escape, cmd, args, env):
-.EE
-.IP
-.I sh
-is a string naming the shell program to use.
-.I escape
-is a function that can be called to escape shell special characters in
-the command line. 
-.I cmd
-is the path to the command to be executed.
-.I args
-is the arguments to the command.
-.I env
-is a dictionary of the environment variables
-in which the command should be executed.
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+'\" BEGIN GENERATED CONSTRUCTION VARIABLE DESCRIPTIONS
 '\"
-'\".IP SVN
-'\"The Subversion executable (usually named
-'\".BR svn ).
+'\" The descriptions below of the various SCons contruction variables
+'\" are generated from the .xml files that live next to the various
+'\" Python modules in the build enginer library.  If you're reading
+'\" this [gnt]roff file with an eye towards patching this man page,
+'\" you can still submit a diff against this text, but it will have to
+'\" be translated to a diff against the underlying .xml file before the
+'\" patch is actually accepted.  If you do that yourself, it will make
+'\" it easier to integrate the patch.
 '\"
-'\".IP SVNCOM
-'\"The command line used to
-'\"fetch source files from a Subversion repository.
+'\" BEGIN GENERATED CONSTRUCTION VARIABLE DESCRIPTIONS
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.so variables.man
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+'\" END GENERATED CONSTRUCTION VARIABLE DESCRIPTIONS
 '\"
-'\".IP SVNFLAGS
-'\"General options that are passed to Subversion.
-
-.IP SWIG
-The scripting language wrapper and interface generator.
-
-.IP SWIGCFILESUFFIX
-The suffix that will be used for intermediate C
-source files generated by
-the scripting language wrapper and interface generator.
-The default value is
-.BR _wrap$CFILESUFFIX .
-By default, this value is used whenever the
-.B -c++
-option is
-.I not
-specified as part of the
-.B SWIGFLAGS
-construction variable.
-
-.IP SWIGCOM
-The command line used to call
-the scripting language wrapper and interface generator.
-
-.IP SWIGCXXFILESUFFIX
-The suffix that will be used for intermediate C++
-source files generated by
-the scripting language wrapper and interface generator.
-The default value is
-.BR _wrap$CFILESUFFIX .
-By default, this value is used whenever the
-.B -c++
-option is specified as part of the
-.B SWIGFLAGS
-construction variable.
-
-.IP SWIGFLAGS
-General options passed to
-the scripting language wrapper and interface generator.
-This is where you should set
-.BR -python ,
-.BR -perl5 ,
-.BR -tcl ,
-or whatever other options you want to specify to SWIG.
-If you set the
-.B -c++
-option in this variable,
-.B scons
-will, by default,
-generate a C++ intermediate source file
-with the extension that is specified as the
-.B $CXXFILESUFFIX
-variable.
-
-.IP TAR
-The tar archiver.
-
-.IP TARCOM
-The command line used to call the tar archiver.
-
-.IP TARFLAGS
-General options passed to the tar archiver.
-
-.IP TARGET
-A reserved variable name
-that may not be set or used in a construction environment.
-(See "Variable Substitution," below.)
-
-.IP TARGETS
-A reserved variable name
-that may not be set or used in a construction environment.
-(See "Variable Substitution," below.)
-
-.IP TARSUFFIX 
-The suffix used for tar file names.
-
-.IP TEX
-The TeX formatter and typesetter.
-
-.IP TEXCOM
-The command line used to call the TeX formatter and typesetter.
-
-.IP TEXFLAGS
-General options passed to the TeX formatter and typesetter.
-
-.IP TOOLS
-A list of the names of the Tool specifications
-that are part of this construction environment.
-
-.IP WIN32_INSERT_DEF
-When this is set to true,
-a library build of a WIN32 shared library (.dll file)
-will also build a corresponding .def file at the same time,
-if a .def file is not already listed as a build target.
-The default is 0 (do not build a .def file).
-
-.IP WIN32DEFPREFIX
-The prefix used for WIN32 .def file names.
-
-.IP WIN32DEFSUFFIX
-The suffix used for WIN32 .def file names.
-
-.IP YACC
-The parser generator.
-
-.IP YACCCOM
-The command line used to call the parser generator
-to generate a source file.
-
-.IP YACCFLAGS
-General options passed to the parser generator.
-If $YACCFLAGS contains a \-d option,
-SCons assumes that the call will also create a .h file
-(if the yacc source file ends in a .y suffix)
-or a .hpp file
-(if the yacc source file ends in a .yy suffix)
-
-.IP ZIP
-The zip compression and file packaging utility.
-
-.IP ZIPCOM
-The command line used to call the zip utility,
-or the internal Python function used to create a
-zip archive.
-
-.IP ZIPCOMPRESSION
-The
-.I compression
-flag
-from the Python
-.B zipfile
-module used by the internal Python function
-to control whether the zip archive
-is compressed or not.
-The default value is
-.BR zipfile.ZIP_DEFLATED ,
-which creates a compressed zip archive.
-This value has no effect when using Python 1.5.2
-or if the
-.B zipfile
-module is otherwise unavailable.
-
-.IP ZIPFLAGS
-General options passed to the zip utility.
+'\" The descriptions above of the various SCons contruction variables
+'\" are generated from the .xml files that live next to the various
+'\" Python modules in the build enginer library.  If you're reading
+'\" this [gnt]roff file with an eye towards patching this man page,
+'\" you can still submit a diff against this text, but it will have to
+'\" be translated to a diff against the underlying .xml file before the
+'\" patch is actually accepted.  If you do that yourself, it will make
+'\" it easier to integrate the patch.
+'\"
+'\" END GENERATED CONSTRUCTION VARIABLE DESCRIPTIONS
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 
 .LP
 Construction variables can be retrieved and set using the 
@@ -6814,7 +4316,7 @@ and selects the compiler to be used for the check;
 the default is "C".
 
 .TP 
-.RI Configure.CheckLib( self ", [" library ", " symbol ", " header ", " language ", " autoadd ])
+.RI Configure.CheckLib( self ", [" library ", " symbol ", " header ", " language ", " autoadd=1 ])
 Checks if 
 .I library 
 provides 
@@ -7104,7 +4606,13 @@ is the name of the variable.
 .I help 
 is the help text for the variable.
 .I default 
-is the default value of the variable.
+is the default value of the variable;
+if the default value is
+.B None
+and there is no explicit value specified,
+the construction variable will
+.I not
+be added to the construction environment.
 .I validator
 is called to validate the value of the variable, and should take three
 arguments: key, value, and environment
@@ -7149,6 +4657,18 @@ the Environment() function:
 env = Environment(options=opts)
 .EE
 
+.IP
+The text file(s) that were specified
+when the Options object was created
+are executed as Python scripts,
+and the values of (global) Python variables set in the file
+are added to the construction environment.
+Example:
+
+.ES
+CC = 'my_cc'
+.EE
+
 .TP
 .RI Save( filename ", " env )
 This saves the currently set options into a script file named  
@@ -7192,12 +4712,30 @@ Help(opts.GenerateHelpText(env))
 Help(opts.GenerateHelpText(env, sort=cmp))
 .EE
 
-The text based SConscript file is executed as a Python script, and the
-global variables are queried for customizable construction
-variables. Example:
+.TP
+.RI FormatOptionHelpText( env ", " opt ", " help ", " default ", " actual )
+This method returns a formatted string
+containing the printable help text
+for one option.
+It is normally not called directly,
+but is called by the
+.IR GenerateHelpText ()
+method to create the returned help text.
+It may be overridden with your own
+function that takes the arguments specified above
+and returns a string of help text formatted to your liking.
+Note that the
+.IR GenerateHelpText ()
+will not put any blank lines or extra
+characters in between the entries,
+so you must add those characters to the returned
+string if you want the entries separated.
 
 .ES
-CC = 'my_cc'
+def my_format(env, opt, help, default, actual):
+    fmt = "\n%s: default=%s actual=%s (%s)\n"
+    return fmt % (opt, default. actual, help)
+opts.FormatOptionHelpText = my_format
 .EE
 
 To make it more convenient to work with customizable Options,
@@ -7287,7 +4825,7 @@ and all input values will be
 converted to lower case.
 
 .TP
-.RI ListOption( key ", " help ", " default ", " names )
+.RI ListOption( key ", " help ", " default ", " names ", [", map ])
 Return a tuple of arguments
 to set up an option
 whose value may be one or more
@@ -7311,6 +4849,14 @@ with all values separated by commas.
 The default may be a string of
 comma-separated default values,
 or a list of the default values.
+The optional
+.I map
+argument is a dictionary
+that can be used to convert
+input values into specific legal values
+in the
+.I names
+list.
 
 .TP
 .RI PackageOption( key ", " help ", " default )
@@ -7381,7 +4927,7 @@ which verifies that the specified path is an existing directory;
 and
 .BR PathOption.PathIsDirCreate ,
 which verifies that the specified path is a directory,
-and will create the specified directory if the path exist.
+and will create the specified directory if the path does not exist.
 You may supply your own
 .I validator
 function,
@@ -7632,8 +5178,17 @@ specify a scanner to
 find things like
 .B #include
 lines in source files.
+The pre-built
+.B DirScanner
+Scanner object may be used to
+indicate that this Builder
+should scan directory trees
+for on-disk changes to files
+that
+.B scons
+does not know about from other Builder or function calls.
 (See the section "Scanner Objects," below,
-for information about creating Scanner objects.)
+for information about creating your own Scanner objects.)
 
 .IP target_factory
 A factory function that the Builder will use
@@ -7658,6 +5213,15 @@ env.Append(BUILDERS = {'MakeDirectory':MakeDirectoryBuilder})
 env.MakeDirectory('new_directory', [])
 .EE
 
+Note that the call to the MakeDirectory Builder
+needs to specify an empty source list
+to make the string represent the builder's target;
+without that, it would assume the argument is the source,
+and would try to deduce the target name from it,
+which in the absence of an automatically-added prefix or suffix
+would lead to a matching target and source name
+and a circular dependency.
+
 .IP source_factory
 A factory function that the Builder will use
 to turn any sources specified as strings into SCons Nodes.
@@ -7743,12 +5307,6 @@ b = Builder("my_build < $TARGET > $SOURCE",
             emitter = {'.suf1' : e_suf1,
                        '.suf2' : e_suf2})
 .EE
-.IP
-The 
-.I generator
-and
-.I action
-arguments must not both be used for the same Builder.
 
 .IP multi
 Specifies whether this builder is allowed to be called multiple times for
@@ -7798,6 +5356,13 @@ def g(source, target, env, for_signature):
 b = Builder(generator=g)
 .EE
 
+.IP
+The 
+.I generator
+and
+.I action
+arguments must not both be used for the same Builder.
+
 .IP src_builder
 Specifies a builder to use when a source file name suffix does not match
 any of the suffixes of the builder. Using this argument produces a
@@ -7941,9 +5506,27 @@ the object is simply returned.
 .IP String
 If the first argument is a string,
 a command-line Action is returned.
+Note that the command line string
+may be preceded by an
+.B @
+(at-sign)
+to suppress printing of the
+specified command line,
+or by a
+.B \-
+(hyphen)
+to ignore the exit status from
+the specified command.
+Examples:
 
 .ES
 Action('$CC -c -o $TARGET $SOURCES')
+
+# Doesn't print the line being executed.
+Action('@build $TARGET $SOURCES')
+
+# Ignores
+Action('-build $TARGET $SOURCES')
 .EE
 
 .\" XXX From Gary Ruben, 23 April 2002:
@@ -8133,6 +5716,32 @@ a = Action("build < ${SOURCE.file} > ${TARGET.file}",
            chdir=1)
 .EE
 
+The
+.BR Action ()
+global function
+also takes an
+.B exitstatfunc
+keyword argument
+which specifies a function
+that is passed the exit status
+(or return value)
+from the specified action
+and can return an arbitrary
+or modified value.
+This can be used, for example,
+to specify that an Action object's
+return value should be ignored
+and SCons should, therefore,
+consider that the action always suceeds:
+
+.ES
+def always_succeed(s):
+    # Always return 0, which indicates success.
+    return 0
+a = Action("build < ${SOURCE.file} > ${TARGET.file}",
+           exitstatfunc=always_succeed)
+.EE
+
 .SS Miscellaneous Action Functions
 
 .B scons
@@ -8191,7 +5800,7 @@ that
 env = Environment(TMPBUILD = '/tmp/builddir')
 env.Command('foo.out', 'foo.in',
             [Mkdir('$TMPBUILD'),
-             Copy('${SOURCE.dir}', '$TMPBUILD')
+             Copy('$TMPBUILD', '${SOURCE.dir}')
              "cd $TMPBUILD && make",
              Delete('$TMPBUILD')])
 .EE
@@ -8445,7 +6054,7 @@ ${TARGET.filebase}   => file
 ${TARGET.suffix}     => .x
 ${TARGET.abspath}    => /top/dir/sub/dir/file.x
 
-BuildDir('sub/dir','src')
+SConscript('src/SConscript', build_dir='sub/dir')
 $SOURCE              => sub/dir/file.x
 ${SOURCE.srcpath}    => src/file.x
 ${SOURCE.srcdir}     => src
@@ -8697,6 +6306,49 @@ only invoke the scanner on the file being scanned,
 and not (for example) also on the files
 specified by the #include lines
 in the file being scanned.
+.I recursive
+may be a callable function,
+in which case it will be called with a list of
+Nodes found and
+should return a list of Nodes
+that should be scanned recursively;
+this can be used to select a specific subset of
+Nodes for additional scanning.
+
+Note that
+.B scons
+has a global
+.B SourceFileScanner
+object that is used by
+the
+.BR Object (),
+.BR SharedObject (),
+and 
+.BR StaticObject ()
+builders to decide
+which scanner should be used
+for different file extensions.
+You can using the
+.BR SourceFileScanner.add_scanner ()
+method to add your own Scanner object
+to the
+.B scons
+infrastructure
+that builds target programs or
+libraries from a list of
+source files of different types:
+
+.ES
+def xyz_scan(node, env, path):
+    contents = node.get_contents()
+    # Scan the contents and return the included files.
+
+XYZScanner = Scanner(xyz_scan)
+
+SourceFileScanner.add_scanner('.xyx', XYZScanner)
+
+env.Program('my_prog', ['file1.c', 'file2.f', 'file3.xyz'])
+.EE
 
 .SH SYSTEM-SPECIFIC BEHAVIOR
 SCons and its configuration files are very portable,
@@ -8944,6 +6596,8 @@ env['BUILDERS]['PDFBuilder'] = bld
 .ES
 import re
 
+'\" Note:  the \\ in the following are for the benefit of nroff/troff,
+'\" not inappropriate doubled escape characters within the r'' raw string.
 include_re = re.compile(r'^include\\s+(\\S+)$', re.M)
 
 def kfile_scan(node, env, path, arg):
@@ -9016,36 +6670,32 @@ subdirectory/SConscript:
 
 .SS Building Multiple Variants From the Same Source
 
-Use the BuildDir() method to establish
+Use the build_dir keyword argument to
+the SConscript function to establish
 one or more separate build directories for
-a given source directory,
-then use the SConscript() method
-to specify the SConscript files
-in the build directories:
+a given source directory:
 
 .ES
 SConstruct:
 
-    ccflags = '-DFOO'
-    Export("ccflags")
-    BuildDir('foo', 'src')
-    SConscript('foo/SConscript')
+    cppdefines = ['FOO']
+    Export("cppdefines")
+    SConscript('src/SConscript', build_dir='foo')
 
-    ccflags = '-DBAR'
-    Export("ccflags")
-    BuildDir('bar', 'src')
-    SConscript('bar/SConscript')
+    cppdefines = ['BAR']
+    Export("cppdefines")
+    SConscript('src/SConscript', build_dir='bar')
 
 src/SConscript:
 
-    Import("ccflags")
-    env = Environment(CCFLAGS = ccflags)
+    Import("cppdefines")
+    env = Environment(CPPDEFINES = cppdefines)
     env.Program(target = 'src', source = 'src.c')
 .EE
 
 Note the use of the Export() method
-to set the "ccflags" variable to a different
-value for each variant build.
+to set the "cppdefines" variable to a different
+value each time we call the SConscript function.
 
 .SS Hierarchical Build of Two Libraries Linked With a Program
 
index c22531844d1a92c5c890d71caa645137113e0c82..da2f3e3d0802a126e58290a35c204873bcc65fbc 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <cvar name="PRINT_CMD_LINE_FUNC">
 <summary>
 A Python function used to print the command lines as they are executed
@@ -55,7 +60,7 @@ def spawn(shell, escape, cmd, args, env):
 is a string naming the shell program to use.
 <varname>escape</varname>
 is a function that can be called to escape shell special characters in
-the command line. 
+the command line.
 <varname>cmd</varname>
 is the path to the command to be executed.
 <varname>args</varname>
index 6afff589788ce06025681995e2738281779dee3b..90839855448690976d9c0959ff6ae34c71fb4099 100644 (file)
@@ -126,6 +126,7 @@ import SCons.Action
 from SCons.Debug import logInstanceCreation
 from SCons.Errors import InternalError, UserError
 import SCons.Executor
+import SCons.Node
 import SCons.Node.FS
 import SCons.Util
 import SCons.Warnings
@@ -151,6 +152,9 @@ class DictCmdGenerator(SCons.Util.Selector):
         self[suffix] = action
 
     def __call__(self, target, source, env, for_signature):
+        if not source:
+            return []
+
         ext = None
         for src in map(str, source):
             my_ext = SCons.Util.splitext(src)[1]
@@ -221,6 +225,7 @@ class OverrideWarner(UserDict.UserDict):
     """
     def __init__(self, dict):
         UserDict.UserDict.__init__(self, dict)
+        if __debug__: logInstanceCreation(self, 'Builder.OverrideWarner')
         self.already_warned = None
     def warn(self):
         if self.already_warned:
@@ -241,12 +246,15 @@ def Builder(**kw):
     if kw.has_key('generator'):
         if kw.has_key('action'):
             raise UserError, "You must not specify both an action and a generator."
-        kw['action'] = SCons.Action.CommandGenerator(kw['generator'])
+        kw['action'] = SCons.Action.CommandGeneratorAction(kw['generator'])
         del kw['generator']
-    elif kw.has_key('action') and SCons.Util.is_Dict(kw['action']):
-        composite = DictCmdGenerator(kw['action'])
-        kw['action'] = SCons.Action.CommandGenerator(composite)
-        kw['src_suffix'] = composite.src_suffixes()
+    elif kw.has_key('action'):
+        if SCons.Util.is_Dict(kw['action']):
+            composite = DictCmdGenerator(kw['action'])
+            kw['action'] = SCons.Action.CommandGeneratorAction(composite)
+            kw['src_suffix'] = composite.src_suffixes()
+        else:
+            kw['action'] = SCons.Action.Action(kw['action'])
 
     if kw.has_key('emitter'):
         emitter = kw['emitter']
@@ -274,9 +282,10 @@ def Builder(**kw):
 
     return ret
 
-def _init_nodes(builder, env, overrides, executor_kw, tlist, slist):
-    """Initialize lists of target and source nodes with all of
-    the proper Builder information.
+def _node_errors(builder, env, tlist, slist):
+    """Validate that the lists of target and source nodes are
+    legal for this builder and environment.  Raise errors or
+    issue warnings as appropriate.
     """
 
     # First, figure out if there are any errors in the way the targets
@@ -286,22 +295,17 @@ def _init_nodes(builder, env, overrides, executor_kw, tlist, slist):
             raise UserError, "Multiple ways to build the same target were specified for: %s" % str(t)
         if t.has_explicit_builder():
             if not t.env is None and not t.env is env:
-                t_contents = t.builder.action.get_contents(tlist, slist, t.env)
-                contents = t.builder.action.get_contents(tlist, slist, env)
+                action = t.builder.action
+                t_contents = action.get_contents(tlist, slist, t.env)
+                contents = action.get_contents(tlist, slist, env)
 
                 if t_contents == contents:
                     SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning,
-                                        "Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s"%(str(t), t.builder.action.strfunction(tlist, slist, t.env)))
+                                        "Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s"%(str(t), action.genstring(tlist, slist, t.env)))
 
                 else:
                     raise UserError, "Two environments with different actions were specified for the same target: %s"%str(t)
 
-            elif t.overrides != overrides:
-                raise UserError, "Two different sets of overrides were specified for the same target: %s"%str(t)
-
-            elif builder.target_scanner and t.target_scanner and builder.target_scanner != t.target_scanner:
-                raise UserError, "Two different scanners were specified for the same target: %s"%str(t)
-
             if builder.multi:
                 if t.builder != builder:
                     if isinstance(t.builder, ListBuilder) and isinstance(builder, ListBuilder) and t.builder.builder == builder.builder:
@@ -317,52 +321,6 @@ def _init_nodes(builder, env, overrides, executor_kw, tlist, slist):
         if len(slist) > 1:
             raise UserError, "More than one source given for single-source builder: targets=%s sources=%s" % (map(str,tlist), map(str,slist))
 
-    # The targets are fine, so find or make the appropriate Executor to
-    # build this particular list of targets from this particular list of
-    # sources.
-    executor = None
-    if builder.multi:
-        try:
-            executor = tlist[0].get_executor(create = 0)
-        except AttributeError:
-            pass
-        else:
-            executor.add_sources(slist)
-    if executor is None:
-        if not builder.action:
-            raise UserError, "Builder %s must have an action to build %s."%(builder.get_name(env or builder.env), map(str,tlist))
-        executor = SCons.Executor.Executor(builder.action,
-                                           env or builder.env,
-                                           [builder.overrides, overrides],
-                                           tlist,
-                                           slist,
-                                           executor_kw)
-
-    # Now set up the relevant information in the target Nodes themselves.
-    for t in tlist:
-        t.overrides = overrides
-        t.cwd = SCons.Node.FS.default_fs.getcwd()
-        t.builder_set(builder)
-        t.env_set(env)
-        t.add_source(slist)
-        t.set_executor(executor)
-        if builder.target_scanner:
-            t.target_scanner = builder.target_scanner
-        if t.source_scanner is None:
-            t.source_scanner = builder.source_scanner
-
-    # Add backup source scanners from the environment to the source
-    # nodes.  This may not be necessary if the node will have a real
-    # source scanner added later (which is why these are the "backup"
-    # source scanners, not the real ones), but because source nodes may
-    # be used multiple times for different targets, it ends up being
-    # more efficient to do this calculation once here, as opposed to
-    # delaying it until later when we potentially have to calculate it
-    # over and over and over.
-    for s in slist:
-        if s.source_scanner is None and s.backup_source_scanner is None:
-            s.backup_source_scanner = env.get_scanner(s.scanner_key())
-
 class EmitterProxy:
     """This is a callable class that can act as a
     Builder emitter.  It holds on to a string that
@@ -398,12 +356,15 @@ class BuilderBase:
     nodes (files) from input nodes (files).
     """
 
+    if SCons.Memoize.use_memoizer:
+        __metaclass__ = SCons.Memoize.Memoized_Metaclass
+
     def __init__(self,  action = None,
                         prefix = '',
                         suffix = '',
                         src_suffix = '',
-                        target_factory = SCons.Node.FS.default_fs.File,
-                        source_factory = SCons.Node.FS.default_fs.File,
+                        target_factory = None,
+                        source_factory = None,
                         target_scanner = None,
                         source_scanner = None,
                         emitter = None,
@@ -414,15 +375,14 @@ class BuilderBase:
                         chdir = _null,
                         is_explicit = 1,
                         **overrides):
-        if __debug__: logInstanceCreation(self, 'BuilderBase')
-        self.action = SCons.Action.Action(action)
+        if __debug__: logInstanceCreation(self, 'Builder.BuilderBase')
+        self.action = action
         self.multi = multi
         if SCons.Util.is_Dict(prefix):
             prefix = CallableSelector(prefix)
         self.prefix = prefix
         if SCons.Util.is_Dict(suffix):
             suffix = CallableSelector(suffix)
-        self.suffix = suffix
         self.env = env
         self.single_source = single_source
         if overrides.has_key('overrides'):
@@ -438,6 +398,7 @@ class BuilderBase:
             del overrides['scanner']
         self.overrides = overrides
 
+        self.set_suffix(suffix)
         self.set_src_suffix(src_suffix)
 
         self.target_factory = target_factory
@@ -470,7 +431,7 @@ class BuilderBase:
         try:
             index = env['BUILDERS'].values().index(self)
             return env['BUILDERS'].keys()[index]
-        except (AttributeError, KeyError, ValueError):
+        except (AttributeError, KeyError, TypeError, ValueError):
             try:
                 return self.name
             except AttributeError:
@@ -490,7 +451,25 @@ class BuilderBase:
                 return [path[:-len(suf)], path[-len(suf):]]
         return SCons.Util.splitext(path)
 
-    def _create_nodes(self, env, overwarn, target = None, source = None):
+    def get_single_executor(self, env, tlist, slist, executor_kw):
+        if not self.action:
+            raise UserError, "Builder %s must have an action to build %s."%(self.get_name(env or self.env), map(str,tlist))
+        return self.action.get_executor(env or self.env,
+                                        [],  # env already has overrides
+                                        tlist,
+                                        slist,
+                                        executor_kw)
+
+    def get_multi_executor(self, env, tlist, slist, executor_kw):
+        try:
+            executor = tlist[0].get_executor(create = 0)
+        except (AttributeError, IndexError):
+            return self.get_single_executor(env, tlist, slist, executor_kw)
+        else:
+            executor.add_sources(slist)
+            return executor
+
+    def _create_nodes(self, env, target = None, source = None):
         """Create and return lists of target and source nodes.
         """
         def _adjustixes(files, pre, suf):
@@ -506,14 +485,13 @@ class BuilderBase:
                 result.append(f)
             return result
 
-        overwarn.warn()
-
-        env = env.Override(overwarn.data)
-
         src_suf = self.get_src_suffix(env)
 
+        target_factory = env.get_factory(self.target_factory)
+        source_factory = env.get_factory(self.source_factory)
+
         source = _adjustixes(source, None, src_suf)
-        slist = env.arg2nodes(source, self.source_factory)
+        slist = env.arg2nodes(source, source_factory)
 
         pre = self.get_prefix(env, slist)
         suf = self.get_suffix(env, slist)
@@ -523,11 +501,14 @@ class BuilderBase:
                 t_from_s = slist[0].target_from_source
             except AttributeError:
                 raise UserError("Do not know how to create a target from source `%s'" % slist[0])
-            splitext = lambda S,self=self,env=env: self.splitext(S,env)
-            tlist = [ t_from_s(pre, suf, splitext) ]
+            except IndexError:
+                tlist = []
+            else:
+                splitext = lambda S,self=self,env=env: self.splitext(S,env)
+                tlist = [ t_from_s(pre, suf, splitext) ]
         else:
             target = _adjustixes(target, pre, suf)
-            tlist = env.arg2nodes(target, self.target_factory)
+            tlist = env.arg2nodes(target, target_factory)
 
         if self.emitter:
             # The emitter is going to do str(node), but because we're
@@ -538,62 +519,88 @@ class BuilderBase:
             new_targets = []
             for t in tlist:
                 if not t.is_derived():
-                    t.builder = self
+                    t.builder_set(self)
                     new_targets.append(t)
 
             target, source = self.emitter(target=tlist, source=slist, env=env)
 
             # Now delete the temporary builders that we attached to any
-            # new targets, so that _init_nodes() doesn't do weird stuff
+            # new targets, so that _node_errors() doesn't do weird stuff
             # to them because it thinks they already have builders.
             for t in new_targets:
                 if t.builder is self:
                     # Only delete the temporary builder if the emitter
                     # didn't change it on us.
-                    t.builder = None
+                    t.builder_set(None)
 
             # Have to call arg2nodes yet again, since it is legal for
             # emitters to spit out strings as well as Node instances.
-            slist = env.arg2nodes(source, self.source_factory)
-            tlist = env.arg2nodes(target, self.target_factory)
+            slist = env.arg2nodes(source, source_factory)
+            tlist = env.arg2nodes(target, target_factory)
 
         return tlist, slist
 
-    def _execute(self, env, target=None, source=_null, overwarn={}, executor_kw={}):
-        if source is _null:
-            source = target
-            target = None
-
-        if(self.single_source and
-           SCons.Util.is_List(source) and
-           len(source) > 1 and
-           target is None):
+    def _execute(self, env, target, source, overwarn={}, executor_kw={}):
+        # We now assume that target and source are lists or None.
+        if self.single_source and len(source) > 1 and target is None:
             result = []
             if target is None: target = [None]*len(source)
-            for k in range(len(source)):
-                t = self._execute(env, target[k], source[k], overwarn)
-                if SCons.Util.is_List(t):
-                    result.extend(t)
-                else:
-                    result.append(t)
+            for tgt, src in zip(target, source):
+                if not tgt is None: tgt = [tgt]
+                if not src is None: src = [src]
+                result.extend(self._execute(env, tgt, src, overwarn))
             return result
+
+        overwarn.warn()
         
-        tlist, slist = self._create_nodes(env, overwarn, target, source)
+        tlist, slist = self._create_nodes(env, target, source)
 
         if len(tlist) == 1:
             builder = self
         else:
             builder = ListBuilder(self, env, tlist)
-        _init_nodes(builder, env, overwarn.data, executor_kw, tlist, slist)
 
-        return tlist
+        # Check for errors with the specified target/source lists.
+        _node_errors(builder, env, tlist, slist)
 
-    def __call__(self, env, target=None, source=_null, chdir=_null, **kw):
+        # The targets are fine, so find or make the appropriate Executor to
+        # build this particular list of targets from this particular list of
+        # sources.
+        if builder.multi:
+            get_executor = builder.get_multi_executor
+        else:
+            get_executor = builder.get_single_executor
+        executor = get_executor(env, tlist, slist, executor_kw)
+
+        # Now set up the relevant information in the target Nodes themselves.
+        for t in tlist:
+            t.cwd = env.fs.getcwd()
+            t.builder_set(builder)
+            t.env_set(env)
+            t.add_source(slist)
+            t.set_executor(executor)
+            t.set_explicit(builder.is_explicit)
+
+        return SCons.Node.NodeList(tlist)
+
+    def __call__(self, env, target=None, source=None, chdir=_null, **kw):
+        # We now assume that target and source are lists or None.
+        # The caller (typically Environment.BuilderWrapper) is
+        # responsible for converting any scalar values to lists.
         if chdir is _null:
             ekw = self.executor_kw
         else:
             ekw = self.executor_kw.copy()
             ekw['chdir'] = chdir
+        if kw:
+            if self.overrides:
+                env_kw = self.overrides.copy()
+                env_kw.update(kw)
+            else:
+                env_kw = kw
+        else:
+            env_kw = self.overrides
+        env = env.Override(env_kw)
         return self._execute(env, target, source, OverrideWarner(kw), ekw)
 
     def adjust_suffix(self, suff):
@@ -607,24 +614,29 @@ class BuilderBase:
             prefix = prefix(env, sources)
         return env.subst(prefix)
 
+    def set_suffix(self, suffix):
+        if not callable(suffix):
+            suffix = self.adjust_suffix(suffix)
+        self.suffix = suffix
+
     def get_suffix(self, env, sources=[]):
         suffix = self.suffix
         if callable(suffix):
             suffix = suffix(env, sources)
-        else:
-            suffix = self.adjust_suffix(suffix)
         return env.subst(suffix)
 
     def src_suffixes(self, env):
-        return map(lambda x, s=self, e=env: e.subst(s.adjust_suffix(x)),
-                   self.src_suffix)
+        "__cacheable__"
+        return map(lambda x, s=self, e=env: e.subst(x), self.src_suffix)
 
     def set_src_suffix(self, src_suffix):
         if not src_suffix:
             src_suffix = []
         elif not SCons.Util.is_List(src_suffix):
             src_suffix = [ src_suffix ]
-        self.src_suffix = src_suffix
+        adjust = lambda suf, s=self: \
+                        callable(suf) and suf or s.adjust_suffix(suf)
+        self.src_suffix = map(adjust, src_suffix)
 
     def get_src_suffix(self, env):
         """Get the first src_suffix in the list of src_suffixes."""
@@ -650,13 +662,21 @@ class BuilderBase:
         """
         self.emitter[suffix] = emitter
 
+if SCons.Memoize.use_old_memoization():
+    _Base = BuilderBase
+    class BuilderBase(SCons.Memoize.Memoizer, _Base):
+        "Cache-backed version of BuilderBase"
+        def __init__(self, *args, **kw):
+            apply(_Base.__init__, (self,)+args, kw)
+            SCons.Memoize.Memoizer.__init__(self)
+
 class ListBuilder(SCons.Util.Proxy):
     """A Proxy to support building an array of targets (for example,
     foo.o and foo.h from foo.y) from a single Action execution.
     """
 
     def __init__(self, builder, env, tlist):
-        if __debug__: logInstanceCreation(self)
+        if __debug__: logInstanceCreation(self, 'Builder.ListBuilder')
         SCons.Util.Proxy.__init__(self, builder)
         self.builder = builder
         self.target_scanner = builder.target_scanner
@@ -692,13 +712,13 @@ class MultiStepBuilder(BuilderBase):
                         prefix = '',
                         suffix = '',
                         src_suffix = '',
-                        target_factory = SCons.Node.FS.default_fs.File,
-                        source_factory = SCons.Node.FS.default_fs.File,
+                        target_factory = None,
+                        source_factory = None,
                         target_scanner = None,
                         source_scanner = None,
                         emitter=None,
                         single_source=0):
-        if __debug__: logInstanceCreation(self)
+        if __debug__: logInstanceCreation(self, 'Builder.MultiStepBuilder')
         BuilderBase.__init__(self, action, prefix, suffix, src_suffix,
                              target_factory, source_factory,
                              target_scanner, source_scanner, emitter,
@@ -706,50 +726,60 @@ class MultiStepBuilder(BuilderBase):
         if not SCons.Util.is_List(src_builder):
             src_builder = [ src_builder ]
         self.src_builder = src_builder
-        self.sdict = {}
-        self.cached_src_suffixes = {} # source suffixes keyed on id(env)
-
-    def _execute(self, env, target = None, source = _null, overwarn={}, executor_kw={}):
-        if source is _null:
-            source = target
-            target = None
 
-        slist = env.arg2nodes(source, self.source_factory)
+    def _get_sdict(self, env):
+        "__cacheable__"
+        sdict = {}
+        for bld in self.src_builder:
+            if SCons.Util.is_String(bld):
+                try:
+                    bld = env['BUILDERS'][bld]
+                except KeyError:
+                    continue
+            for suf in bld.src_suffixes(env):
+                sdict[suf] = bld
+        return sdict
+        
+    def _execute(self, env, target, source, overwarn={}, executor_kw={}):
+        # We now assume that target and source are lists or None.
+        source_factory = env.get_factory(self.source_factory)
+        slist = env.arg2nodes(source, source_factory)
         final_sources = []
 
-        try:
-            sdict = self.sdict[id(env)]
-        except KeyError:
-            sdict = {}
-            self.sdict[id(env)] = sdict
-            for bld in self.src_builder:
-                if SCons.Util.is_String(bld):
-                    try:
-                        bld = env['BUILDERS'][bld]
-                    except KeyError:
-                        continue
-                for suf in bld.src_suffixes(env):
-                    sdict[suf] = bld
+        sdict = self._get_sdict(env)
 
         src_suffixes = self.src_suffixes(env)
 
+        lengths_dict = {}
+        for l in map(len, src_suffixes):
+            lengths_dict[l] = None
+        lengths = lengths_dict.keys()
+
+        def match_src_suffix(node, src_suffixes=src_suffixes, lengths=lengths):
+            node_suffixes = map(lambda l, n=node: n.name[-l:], lengths)
+            for suf in src_suffixes:
+                if suf in node_suffixes:
+                    return suf
+            return None
+
         for snode in slist:
-            for srcsuf in src_suffixes:
-                if str(snode)[-len(srcsuf):] == srcsuf and sdict.has_key(srcsuf):
-                    tgt = sdict[srcsuf]._execute(env, None, snode, overwarn)
-                    # If the subsidiary Builder returned more than one target,
-                    # then filter out any sources that this Builder isn't
-                    # capable of building.
-                    if len(tgt) > 1:
-                        tgt = filter(lambda x, self=self, suf=src_suffixes, e=env:
-                                     self.splitext(SCons.Util.to_String(x),e)[1] in suf,
-                                     tgt)
-                    final_sources.extend(tgt)
-                    snode = None
-                    break
-            if snode:
+            match_suffix = match_src_suffix(snode)
+            if match_suffix:
+                try:
+                    bld = sdict[match_suffix]
+                except KeyError:
+                    final_sources.append(snode)
+                else:
+                    tlist = bld._execute(env, None, [snode], overwarn)
+                    # If the subsidiary Builder returned more than one
+                    # target, then filter out any sources that this
+                    # Builder isn't capable of building.
+                    if len(tlist) > 1:
+                        tlist = filter(match_src_suffix, tlist)
+                    final_sources.extend(tlist)
+            else:
                 final_sources.append(snode)
-                
+
         return BuilderBase._execute(self, env, target, final_sources, overwarn)
 
     def get_src_builders(self, env):
@@ -772,15 +802,12 @@ class MultiStepBuilder(BuilderBase):
     def src_suffixes(self, env):
         """Return a list of the src_suffix attributes for all
         src_builders of this Builder.
+        __cacheable__
         """
-        try:
-            return self.cached_src_suffixes[id(env)]
-        except KeyError:
-            suffixes = BuilderBase.src_suffixes(self, env)
-            for builder in self.get_src_builders(env):
-                suffixes.extend(builder.src_suffixes(env))
-            self.cached_src_suffixes[id(env)] = suffixes
-            return suffixes
+        suffixes = BuilderBase.src_suffixes(self, env)
+        for builder in self.get_src_builders(env):
+            suffixes.extend(builder.src_suffixes(env))
+        return suffixes
 
 class CompositeBuilder(SCons.Util.Proxy):
     """A Builder Proxy whose main purpose is to always have
@@ -789,7 +816,7 @@ class CompositeBuilder(SCons.Util.Proxy):
     """
 
     def __init__(self, builder, cmdgen):
-        if __debug__: logInstanceCreation(self)
+        if __debug__: logInstanceCreation(self, 'Builder.CompositeBuilder')
         SCons.Util.Proxy.__init__(self, builder)
 
         # cmdgen should always be an instance of DictCmdGenerator.
index 2075bf0e85d8bf51f0e4e480127a5a522714b8d5..233336c731d2215ca2f04ccdcc15b0678d1b0e26 100644 (file)
@@ -34,6 +34,7 @@ import os.path
 import sys
 import types
 import unittest
+import UserList
 
 import TestCmd
 
@@ -54,6 +55,9 @@ test = TestCmd.TestCmd(workdir = '')
 outfile = test.workpath('outfile')
 outfile2 = test.workpath('outfile2')
 
+infile = test.workpath('infile')
+test.write(infile, "infile\n")
+
 show_string = None
 
 scons_env = SCons.Environment.Environment()
@@ -71,6 +75,7 @@ class Environment:
         global env_arg2nodes_called
         env_arg2nodes_called = None
         self.scanner = None
+        self.fs = SCons.Node.FS.FS()
     def subst(self, s):
         if not SCons.Util.is_String(s):
             return s
@@ -82,6 +87,14 @@ class Environment:
         except IndexError:
             pass
         return self.d.get(s, s)
+    def subst_target_source(self, string, raw=0, target=None,
+                            source=None, dict=None, conv=None):
+        return SCons.Util.scons_subst(string, self, raw, target,
+                                      source, dict, conv)
+    def subst_list(self, string, raw=0, target=None,
+                   source=None, dict=None, conv=None):
+        return SCons.Util.scons_subst_list(string, self, raw, target,
+                                           source, dict, conv)
     def arg2nodes(self, args, factory):
         global env_arg2nodes_called
         env_arg2nodes_called = 1
@@ -93,6 +106,8 @@ class Environment:
                 a = factory(a)
             list.append(a)
         return list
+    def get_factory(self, factory):
+        return factory or self.fs.File
     def get_scanner(self, ext):
         return self.scanner
     def Dictionary(self):
@@ -112,6 +127,7 @@ class Environment:
     def Override(self, overrides):
         env = apply(Environment, (), self.d)
         env.d.update(overrides)
+        env.scanner = self.scanner
         return env
     def _update(self, dict):
         self.d.update(dict)
@@ -125,23 +141,32 @@ class Environment:
         d['SOURCES'] = ['__s1__', '__s2__', '__s3__', '__s4__', '__s5__', '__s6__']
         d['SOURCE'] = d['SOURCES'][0]
         return d
+    def __cmp__(self, other):
+        return cmp(self.scanner, other.scanner) or cmp(self.d, other.d)
+
+class MyAction:
+    def __init__(self, action):
+        self.action = action
+    def get_executor(self, env, overrides, tlist, slist, executor_kw):
+        return ['executor'] + [self.action]
 
 class MyNode_without_target_from_source:
     def __init__(self, name):
         self.name = name
         self.sources = []
         self.builder = None
+        self.is_explicit = None
         self.side_effect = 0
-        self.source_scanner = None
-        self.backup_source_scanner = None
     def __str__(self):
         return self.name
     def builder_set(self, builder):
         self.builder = builder
     def has_builder(self):
         return not self.builder is None
+    def set_explicit(self, is_explicit):
+        self.is_explicit = is_explicit
     def has_explicit_builder(self):
-        return not self.builder is None and self.builder.is_explicit
+        return self.is_explicit
     def env_set(self, env, safe=0):
         self.env = env
     def add_source(self, source):
@@ -206,8 +231,11 @@ class BuilderTestCase(unittest.TestCase):
                                         target_factory=MyNode,
                                         source_factory=MyNode)
 
-        n1 = MyNode("n1");
-        n2 = MyNode("n2");
+        tgt = builder(env, source=[])
+        assert tgt == [], tgt
+
+        n1 = MyNode("n1")
+        n2 = MyNode("n2")
         builder(env, target = n1, source = n2)
         assert env_arg2nodes_called
         assert n1.env == env, n1.env
@@ -216,15 +244,48 @@ class BuilderTestCase(unittest.TestCase):
         assert n1.executor, "no executor found"
         assert not hasattr(n2, 'env')
 
-        target = builder(env, target = 'n3', source = 'n4')[0]
+        l = [1]
+        ul = UserList.UserList([2])
+        try:
+            l.extend(ul)
+        except TypeError:
+            def mystr(l):
+                return str(map(str, l))
+        else:
+            mystr = str
+
+        nnn1 = MyNode("nnn1")
+        nnn2 = MyNode("nnn2")
+        tlist = builder(env, target = [nnn1, nnn2], source = [])
+        s = mystr(tlist)
+        assert s == "['nnn1', 'nnn2']", s
+        l = map(str, tlist)
+        assert l == ['nnn1', 'nnn2'], l
+
+        tlist = builder(env, target = 'n3', source = 'n4')
+        s = mystr(tlist)
+        assert s == "['n3']", s
+        target = tlist[0]
+        l = map(str, tlist)
+        assert l == ['n3'], l
         assert target.name == 'n3'
         assert target.sources[0].name == 'n4'
 
-        target = builder(env, target = 'n4 n5', source = ['n6 n7'])[0]
+        tlist = builder(env, target = 'n4 n5', source = ['n6 n7'])
+        s = mystr(tlist)
+        assert s == "['n4 n5']", s
+        l = map(str, tlist)
+        assert l == ['n4 n5'], l
+        target = tlist[0]
         assert target.name == 'n4 n5'
         assert target.sources[0].name == 'n6 n7'
 
-        target = builder(env, target = ['n8 n9'], source = 'n10 n11')[0]
+        tlist = builder(env, target = ['n8 n9'], source = 'n10 n11')
+        s = mystr(tlist)
+        assert s == "['n8 n9']", s
+        l = map(str, tlist)
+        assert l == ['n8 n9'], l
+        target = tlist[0]
         assert target.name == 'n8 n9'
         assert target.sources[0].name == 'n10 n11'
 
@@ -254,7 +315,7 @@ class BuilderTestCase(unittest.TestCase):
         n20 = MyNode_without_target_from_source('n20')
         flag = 0
         try:
-            target = builder(env, source=n20)
+            target = builder(env, None, source=n20)
         except SCons.Errors.UserError, e:
             flag = 1
         assert flag, "UserError should be thrown if a source node can't create a target."
@@ -264,7 +325,7 @@ class BuilderTestCase(unittest.TestCase):
                                         source_factory=MyNode,
                                         prefix='p-',
                                         suffix='.s')
-        target = builder(env, source='n21')[0]
+        target = builder(env, None, source='n21')[0]
         assert target.name == 'p-n21.s', target
 
         builder = SCons.Builder.Builder(misspelled_action="foo",
@@ -331,6 +392,29 @@ class BuilderTestCase(unittest.TestCase):
         builder = SCons.Builder.Builder(generator=generator)
         assert builder.action.generator == generator
 
+    def test_get_name(self):
+        """Test the get_name() method
+        """
+
+    def test_get_single_executor(self):
+        """Test the get_single_executor() method
+        """
+        b = SCons.Builder.Builder(action='foo')
+        x = b.get_single_executor({}, [], [], {})
+        assert not x is None, x
+
+    def test_get_multi_executor(self):
+        """Test the get_multi_executor() method
+        """
+        b = SCons.Builder.Builder(action='foo', multi=1)
+        t1 = MyNode('t1')
+        s1 = MyNode('s1')
+        s2 = MyNode('s2')
+        x1 = b.get_multi_executor({}, [t1], [s1], {})
+        t1.executor = x1
+        x2 = b.get_multi_executor({}, [t1], [s2], {})
+        assert x1 is x2, "%s is not %s" % (repr(x1), repr(x2))
+
     def test_cmp(self):
         """Test simple comparisons of Builder objects
         """
@@ -412,10 +496,10 @@ class BuilderTestCase(unittest.TestCase):
         tgt = builder(env, target = 'tgt2a tgt2b', source = 'src2')[0]
         assert tgt.path == 'libtgt2a tgt2b', \
                 "Target has unexpected name: %s" % tgt.path
-        tgt = builder(env, source = 'src3')[0]
+        tgt = builder(env, target = None, source = 'src3')[0]
         assert tgt.path == 'libsrc3', \
                 "Target has unexpected name: %s" % tgt.path
-        tgt = builder(env, source = 'lib/src4')[0]
+        tgt = builder(env, target = None, source = 'lib/src4')[0]
         assert tgt.path == os.path.join('lib', 'libsrc4'), \
                 "Target has unexpected name: %s" % tgt.path
         tgt = builder(env, target = 'lib/tgt5', source = 'lib/src5')[0]
@@ -439,19 +523,35 @@ class BuilderTestCase(unittest.TestCase):
                                                   '$FOO' : 'foo-',
                                                   '.zzz' : my_emit},
                                         action = '')
-        tgt = builder(my_env, source = 'f1')[0]
+        tgt = builder(my_env, target = None, source = 'f1')[0]
         assert tgt.path == 'default-f1', tgt.path
-        tgt = builder(my_env, source = 'f2.c')[0]
+        tgt = builder(my_env, target = None, source = 'f2.c')[0]
         assert tgt.path == 'default-f2', tgt.path
-        tgt = builder(my_env, source = 'f3.in')[0]
+        tgt = builder(my_env, target = None, source = 'f3.in')[0]
         assert tgt.path == 'out-f3', tgt.path
-        tgt = builder(my_env, source = 'f4.x')[0]
+        tgt = builder(my_env, target = None, source = 'f4.x')[0]
         assert tgt.path == 'y-f4', tgt.path
-        tgt = builder(my_env, source = 'f5.foo')[0]
+        tgt = builder(my_env, target = None, source = 'f5.foo')[0]
         assert tgt.path == 'foo-f5', tgt.path
-        tgt = builder(my_env, source = 'f6.zzz')[0]
+        tgt = builder(my_env, target = None, source = 'f6.zzz')[0]
         assert tgt.path == 'emit-f6', tgt.path
 
+    def test_set_suffix(self):
+        """Test the set_suffix() method"""
+        b = SCons.Builder.Builder(action='')
+        env = Environment(XSUFFIX = '.x')
+
+        s = b.get_suffix(env)
+        assert s == '', s
+
+        b.set_suffix('.foo')
+        s = b.get_suffix(env)
+        assert s == '.foo', s
+
+        b.set_suffix('$XSUFFIX')
+        s = b.get_suffix(env)
+        assert s == '.x', s
+
     def test_src_suffix(self):
         """Test Builder creation with a specified source file suffix
         
@@ -492,7 +592,7 @@ class BuilderTestCase(unittest.TestCase):
         b6 = SCons.Builder.Builder(action = '',
                                    src_suffix='_src.a',
                                    suffix='.b')
-        tgt = b6(env, source='foo_src.a')
+        tgt = b6(env, target=None, source='foo_src.a')
         assert str(tgt[0]) == 'foo.b', str(tgt[0])
 
         b7 = SCons.Builder.Builder(action = '',
@@ -501,16 +601,16 @@ class BuilderTestCase(unittest.TestCase):
         b8 = SCons.Builder.Builder(action = '',
                                    src_builder=b7,
                                    suffix='.c')
-        tgt = b8(env, source='foo_source.a')
+        tgt = b8(env, target=None, source='foo_source.a')
         assert str(tgt[0]) == 'foo_obj.c', str(tgt[0])
-        src = SCons.Node.FS.default_fs.File('foo_source.a')
-        tgt = b8(env, source=src)
+        src = env.fs.File('foo_source.a')
+        tgt = b8(env, target=None, source=src)
         assert str(tgt[0]) == 'foo_obj.c', str(tgt[0])
 
         b9 = SCons.Builder.Builder(action={'_src.a' : 'srcaction'},
                                    suffix='.c')
         b9.add_action('_altsrc.b', 'altaction')
-        tgt = b9(env, source='foo_altsrc.b')
+        tgt = b9(env, target=None, source='foo_altsrc.b')
         assert str(tgt[0]) == 'foo.c', str(tgt[0])
 
     def test_suffix(self):
@@ -530,7 +630,7 @@ class BuilderTestCase(unittest.TestCase):
         tgt = builder(env, target = 'tgt4a tgt4b', source = 'src4')[0]
         assert tgt.path == 'tgt4a tgt4b.o', \
                 "Target has unexpected name: %s" % tgt.path
-        tgt = builder(env, source = 'src5')[0]
+        tgt = builder(env, target = None, source = 'src5')[0]
         assert tgt.path == 'src5.o', \
                 "Target has unexpected name: %s" % tgt.path
 
@@ -551,17 +651,17 @@ class BuilderTestCase(unittest.TestCase):
                                                   '$BAR' : '.new',
                                                   '.zzz' : my_emit},
                                         action='')
-        tgt = builder(my_env, source = 'f1')[0]
+        tgt = builder(my_env, target = None, source = 'f1')[0]
         assert tgt.path == 'f1.default', tgt.path
-        tgt = builder(my_env, source = 'f2.c')[0]
+        tgt = builder(my_env, target = None, source = 'f2.c')[0]
         assert tgt.path == 'f2.default', tgt.path
-        tgt = builder(my_env, source = 'f3.in')[0]
+        tgt = builder(my_env, target = None, source = 'f3.in')[0]
         assert tgt.path == 'f3.out', tgt.path
-        tgt = builder(my_env, source = 'f4.x')[0]
+        tgt = builder(my_env, target = None, source = 'f4.x')[0]
         assert tgt.path == 'f4.y', tgt.path
-        tgt = builder(my_env, source = 'f5.bar')[0]
+        tgt = builder(my_env, target = None, source = 'f5.bar')[0]
         assert tgt.path == 'f5.new', tgt.path
-        tgt = builder(my_env, source = 'f6.zzz')[0]
+        tgt = builder(my_env, target = None, source = 'f6.zzz')[0]
         assert tgt.path == 'f6.emit', tgt.path
 
     def test_single_source(self):
@@ -589,7 +689,7 @@ class BuilderTestCase(unittest.TestCase):
         tgt.prepare()
         tgt.build()
         assert env['CNT'][0] == 2
-        tgts = builder(env, infiles[2:4])
+        tgts = builder(env, None, infiles[2:4])
         for t in tgts: t.prepare()
         tgts[0].build()
         tgts[1].build()
@@ -621,7 +721,11 @@ class BuilderTestCase(unittest.TestCase):
 
         env = Environment()
         builder = SCons.Builder.Builder(action = function2)
-        tgts = builder(env, target = [outfile, outfile2], source = 'foo')
+
+        tgts = builder(env, source=[])
+        assert tgts == [], tgts
+
+        tgts = builder(env, target = [outfile, outfile2], source = infile)
         for t in tgts:
             t.prepare()
         try:
@@ -645,7 +749,7 @@ class BuilderTestCase(unittest.TestCase):
             return 1
 
         builder = SCons.Builder.Builder(action = function3)
-        tgts = builder(env, target = [sub1_out, sub2_out], source = 'foo')
+        tgts = builder(env, target = [sub1_out, sub2_out], source = infile)
         for t in tgts:
             t.prepare()
         try:
@@ -665,23 +769,29 @@ class BuilderTestCase(unittest.TestCase):
         builder1 = SCons.Builder.Builder(action='foo',
                                          src_suffix='.bar',
                                          suffix='.foo')
-        builder2 = SCons.Builder.MultiStepBuilder(action='bar',
+        builder2 = SCons.Builder.MultiStepBuilder(action=MyAction('act'),
                                                   src_builder = builder1,
                                                   src_suffix = '.foo')
 
+        tgt = builder2(env, source=[])
+        assert tgt == [], tgt
+
         tgt = builder2(env, target='baz',
                        source=['test.bar', 'test2.foo', 'test3.txt'])[0]
-        assert str(tgt.sources[0]) == 'test.foo', str(tgt.sources[0])
-        assert str(tgt.sources[0].sources[0]) == 'test.bar', \
-               str(tgt.sources[0].sources[0])
-        assert str(tgt.sources[1]) == 'test2.foo', str(tgt.sources[1])
-        assert str(tgt.sources[2]) == 'test3.txt', str(tgt.sources[2])
-
-        tgt = builder2(env, 'aaa.bar')[0]
-        assert str(tgt) == 'aaa', str(tgt)
-        assert str(tgt.sources[0]) == 'aaa.foo', str(tgt.sources[0])
-        assert str(tgt.sources[0].sources[0]) == 'aaa.bar', \
-               str(tgt.sources[0].sources[0])
+        s = str(tgt)
+        assert s == 'baz', s
+        s = map(str, tgt.sources)
+        assert s == ['test.foo', 'test2.foo', 'test3.txt'], s
+        s = map(str, tgt.sources[0].sources)
+        assert s == ['test.bar'], s
+
+        tgt = builder2(env, None, 'aaa.bar')[0]
+        s = str(tgt)
+        assert s == 'aaa', s
+        s = map(str, tgt.sources)
+        assert s == ['aaa.foo'], s
+        s = map(str, tgt.sources[0].sources)
+        assert s == ['aaa.bar'], s
 
         builder3 = SCons.Builder.MultiStepBuilder(action = 'foo',
                                                   src_builder = 'xyzzy',
@@ -691,21 +801,23 @@ class BuilderTestCase(unittest.TestCase):
         builder4 = SCons.Builder.Builder(action='bld4',
                                          src_suffix='.i',
                                          suffix='_wrap.c')
-        builder5 = SCons.Builder.MultiStepBuilder(action='bld5',
+        builder5 = SCons.Builder.MultiStepBuilder(action=MyAction('act'),
                                                   src_builder=builder4,
                                                   suffix='.obj',
                                                   src_suffix='.c')
-        builder6 = SCons.Builder.MultiStepBuilder(action='bld6',
+        builder6 = SCons.Builder.MultiStepBuilder(action=MyAction('act'),
                                                   src_builder=builder5,
                                                   suffix='.exe',
                                                   src_suffix='.obj')
         tgt = builder6(env, 'test', 'test.i')[0]
-        assert str(tgt) == 'test.exe', str(tgt)
-        assert str(tgt.sources[0]) == 'test_wrap.obj', str(tgt.sources[0])
-        assert str(tgt.sources[0].sources[0]) == 'test_wrap.c', \
-               str(tgt.sources[0].sources[0])
-        assert str(tgt.sources[0].sources[0].sources[0]) == 'test.i', \
-               str(tgt.sources[0].sources[0].sources[0])
+        s = str(tgt)
+        assert s == 'test.exe', s
+        s = map(str, tgt.sources)
+        assert s == ['test_wrap.obj'], s
+        s = map(str, tgt.sources[0].sources)
+        assert s == ['test_wrap.c'], s
+        s = map(str, tgt.sources[0].sources[0].sources)
+        assert s == ['test.i'], s
         
     def test_CompositeBuilder(self):
         """Testing CompositeBuilder class."""
@@ -717,15 +829,21 @@ class BuilderTestCase(unittest.TestCase):
                                                  '.bar' : func_action,
                                                  '$BAR_SUFFIX' : func_action,
                                                  '$FOO_SUFFIX' : func_action })
+
+        tgt = builder(env, source=[])
+        assert tgt == [], tgt
         
         assert isinstance(builder, SCons.Builder.CompositeBuilder)
         assert isinstance(builder.action, SCons.Action.CommandGeneratorAction)
+
         tgt = builder(env, target='test1', source='test1.foo')[0]
         assert isinstance(tgt.builder, SCons.Builder.BuilderBase)
         assert tgt.builder.action is builder.action
+
         tgt = builder(env, target='test2', source='test1.bar')[0]
         assert isinstance(tgt.builder, SCons.Builder.BuilderBase)
         assert tgt.builder.action is builder.action
+
         flag = 0
         tgt = builder(env, target='test3', source=['test2.bar', 'test1.foo'])[0]
         try:
@@ -852,8 +970,8 @@ class BuilderTestCase(unittest.TestCase):
                                         source_scanner=sscan,
                                         action='')
         tgt = builder(env, target='foo2', source='bar')[0]
-        assert tgt.target_scanner == tscan, tgt.target_scanner
-        assert tgt.source_scanner == sscan, tgt.source_scanner
+        assert tgt.builder.target_scanner == tscan, tgt.builder.target_scanner
+        assert tgt.builder.source_scanner == sscan, tgt.builder.source_scanner
 
         builder1 = SCons.Builder.Builder(action='foo',
                                          src_suffix='.bar',
@@ -863,8 +981,8 @@ class BuilderTestCase(unittest.TestCase):
                                          target_scanner = tscan,
                                          source_scanner = tscan)
         tgt = builder2(env, target='baz2', source='test.bar test2.foo test3.txt')[0]
-        assert tgt.target_scanner == tscan, tgt.target_scanner
-        assert tgt.source_scanner == tscan, tgt.source_scanner
+        assert tgt.builder.target_scanner == tscan, tgt.builder.target_scanner
+        assert tgt.builder.source_scanner == tscan, tgt.builder.source_scanner
 
     def test_actual_scanner(self):
         """Test usage of actual Scanner objects."""
@@ -890,28 +1008,84 @@ class BuilderTestCase(unittest.TestCase):
                  return 'TestScannerkey'
             def instance(self, env):
                  return self
+            def select(self, node):
+                 return self
+            name = 'TestScanner'
+            def __str__(self):
+                return self.name
 
         scanner = TestScanner()
         builder = SCons.Builder.Builder(action='action')
 
         # With no scanner specified, source_scanner and
         # backup_source_scanner are None.
+        bar_y = MyNode('bar.y')
         env1 = Environment()
         tgt = builder(env1, target='foo1.x', source='bar.y')[0]
         src = tgt.sources[0]
-        assert tgt.target_scanner != scanner, tgt.target_scanner
-        assert src.source_scanner is None, src.source_scanner
-        assert src.backup_source_scanner is None, src.backup_source_scanner
-
-        # Later use of the same source file with an environment that
-        # has a scanner must still set the scanner.
-        env2 = Environment()
-        env2.scanner = scanner
-        tgt = builder(env2, target='foo2.x', source='bar.y')[0]
+        assert tgt.builder.target_scanner != scanner, tgt.builder.target_scanner
+        assert tgt.builder.source_scanner is None, tgt.builder.source_scanner
+        assert tgt.get_source_scanner(bar_y) is None, tgt.get_source_scanner(bar_y)
+        assert not src.has_builder(), src.has_builder()
+        assert src.get_source_scanner(bar_y) is None, src.get_source_scanner(bar_y)
+
+        # An Environment that has suffix-specified SCANNERS should
+        # provide a source scanner to the target.
+        class EnvTestScanner:
+            def key(self, env):
+                 return '.y'
+            def instance(self, env):
+                 return self
+            name = 'EnvTestScanner'
+            def __str__(self):
+                return self.name
+            def select(self, node):
+                return self
+            def path(self, env, dir=None):
+                return ()
+            def __call__(self, node, env, path):
+                return []
+        env3 = Environment(SCANNERS = [EnvTestScanner()])
+        env3.scanner = EnvTestScanner() # test env's version of SCANNERS
+        tgt = builder(env3, target='foo2.x', source='bar.y')[0]
         src = tgt.sources[0]
-        assert tgt.target_scanner != scanner, tgt.target_scanner
-        assert src.source_scanner is None, src.source_scanner
-        assert src.backup_source_scanner == scanner, src.backup_source_scanner
+        assert tgt.builder.target_scanner != scanner, tgt.builder.target_scanner
+        assert not tgt.builder.source_scanner, tgt.builder.source_scanner
+        assert tgt.get_source_scanner(bar_y), tgt.get_source_scanner(bar_y)
+        assert str(tgt.get_source_scanner(bar_y)) == 'EnvTestScanner', tgt.get_source_scanner(bar_y)
+        assert not src.has_builder(), src.has_builder()
+        assert src.get_source_scanner(bar_y) is None, src.get_source_scanner(bar_y)
+
+        # Can't simply specify the scanner as a builder argument; it's
+        # global to all invocations of this builder.
+        tgt = builder(env3, target='foo3.x', source='bar.y', source_scanner = scanner)[0]
+        src = tgt.sources[0]
+        assert tgt.builder.target_scanner != scanner, tgt.builder.target_scanner
+        assert not tgt.builder.source_scanner, tgt.builder.source_scanner
+        assert tgt.get_source_scanner(bar_y), tgt.get_source_scanner(bar_y)
+        assert str(tgt.get_source_scanner(bar_y)) == 'EnvTestScanner', tgt.get_source_scanner(bar_y)
+        assert not src.has_builder(), src.has_builder()
+        assert src.get_source_scanner(bar_y) is None, src.get_source_scanner(bar_y)
+
+        # Now use a builder that actually has scanners and ensure that
+        # the target is set accordingly (using the specified scanner
+        # instead of the Environment's scanner)
+        builder = SCons.Builder.Builder(action='action',
+                                        source_scanner=scanner,
+                                        target_scanner=scanner)
+        tgt = builder(env3, target='foo4.x', source='bar.y')[0]
+        src = tgt.sources[0]
+        assert tgt.builder.target_scanner == scanner, tgt.builder.target_scanner
+        assert tgt.builder.source_scanner, tgt.builder.source_scanner
+        assert tgt.builder.source_scanner == scanner, tgt.builder.source_scanner
+        assert str(tgt.builder.source_scanner) == 'TestScanner', str(tgt.builder.source_scanner)
+        assert tgt.get_source_scanner(bar_y), tgt.get_source_scanner(bar_y)
+        assert tgt.get_source_scanner(bar_y) == scanner, tgt.get_source_scanner(bar_y)
+        assert str(tgt.get_source_scanner(bar_y)) == 'TestScanner', tgt.get_source_scanner(bar_y)
+        assert not src.has_builder(), src.has_builder()
+        assert src.get_source_scanner(bar_y) is None, src.get_source_scanner(bar_y)
+
+
 
     def test_Builder_API(self):
         """Test Builder interface.
@@ -921,8 +1095,8 @@ class BuilderTestCase(unittest.TestCase):
         forms of component specifications."""
 
         builder = SCons.Builder.Builder()
-
         env = Environment(BUILDERS={'Bld':builder})
+
         r = builder.get_name(env)
         assert r == 'Bld', r
         r = builder.get_prefix(env)
@@ -937,23 +1111,34 @@ class BuilderTestCase(unittest.TestCase):
         assert r == ['foo'], r
 
         # src_suffix can be a single string or a list of strings
+        # src_suffixes() caches its return value, so we use a new
+        # Builder each time we do any of these tests
 
-        builder.set_src_suffix('.foo')
-        r = builder.get_src_suffix(env)
+        bld = SCons.Builder.Builder()
+        env = Environment(BUILDERS={'Bld':bld})
+
+        bld.set_src_suffix('.foo')
+        r = bld.get_src_suffix(env)
         assert r == '.foo', r
-        r = builder.src_suffixes(env)
+        r = bld.src_suffixes(env)
         assert r == ['.foo'], r
 
-        builder.set_src_suffix(['.foo', '.bar'])
-        r = builder.get_src_suffix(env)
+        bld = SCons.Builder.Builder()
+        env = Environment(BUILDERS={'Bld':bld})
+
+        bld.set_src_suffix(['.foo', '.bar'])
+        r = bld.get_src_suffix(env)
         assert r == '.foo', r
-        r = builder.src_suffixes(env)
+        r = bld.src_suffixes(env)
         assert r == ['.foo', '.bar'], r
 
-        builder.set_src_suffix(['.bar', '.foo'])
-        r = builder.get_src_suffix(env)
+        bld = SCons.Builder.Builder()
+        env = Environment(BUILDERS={'Bld':bld})
+
+        bld.set_src_suffix(['.bar', '.foo'])
+        r = bld.get_src_suffix(env)
         assert r == '.bar', r
-        r = builder.src_suffixes(env)
+        r = bld.src_suffixes(env)
         assert r == ['.bar', '.foo'], r
 
         # adjust_suffix normalizes the suffix, adding a `.' if needed
@@ -1026,8 +1211,8 @@ class BuilderTestCase(unittest.TestCase):
         assert r == '.D', r
 
         builder = SCons.Builder.Builder(prefix='A_', suffix={}, action={})
-
         env = Environment(BUILDERS={'Bld':builder})
+
         r = builder.get_name(env)
         assert r == 'Bld', r
         r = builder.get_prefix(env)
@@ -1043,7 +1228,10 @@ class BuilderTestCase(unittest.TestCase):
         # whose keys are the source suffix.  The add_action()
         # specifies a new source suffix/action binding.
 
+        builder = SCons.Builder.Builder(prefix='A_', suffix={}, action={})
+        env = Environment(BUILDERS={'Bld':builder})
         builder.add_action('.src_sfx1', 'FOO')
+
         r = builder.get_name(env)
         assert r == 'Bld', r
         r = builder.get_prefix(env)
@@ -1057,6 +1245,9 @@ class BuilderTestCase(unittest.TestCase):
         r = builder.src_suffixes(env)
         assert r == ['.src_sfx1'], r
 
+        builder = SCons.Builder.Builder(prefix='A_', suffix={}, action={})
+        env = Environment(BUILDERS={'Bld':builder})
+        builder.add_action('.src_sfx1', 'FOO')
         builder.add_action('.src_sfx2', 'BAR')
 
         r = builder.get_name(env)
@@ -1184,11 +1375,11 @@ class BuilderTestCase(unittest.TestCase):
                                                   '.4b':emit4b},
                                          target_factory=MyNode,
                                          source_factory=MyNode)
-        tgt = builder4(env, source='aaa.4a')[0]
+        tgt = builder4(env, None, source='aaa.4a')[0]
         assert str(tgt) == 'emit4a-aaa', str(tgt)
-        tgt = builder4(env, source='bbb.4b')[0]
+        tgt = builder4(env, None, source='bbb.4b')[0]
         assert str(tgt) == 'emit4b-bbb', str(tgt)
-        tgt = builder4(env, source='ccc.4c')[0]
+        tgt = builder4(env, None, source='ccc.4c')[0]
         assert str(tgt) == 'ccc', str(tgt)
 
         def emit4c(target, source, env):
@@ -1196,7 +1387,7 @@ class BuilderTestCase(unittest.TestCase):
             target = map(lambda x: 'emit4c-' + x[:-3], source)
             return (target, source)
         builder4.add_emitter('.4c', emit4c)
-        tgt = builder4(env, source='ccc.4c')[0]
+        tgt = builder4(env, None, source='ccc.4c')[0]
         assert str(tgt) == 'emit4c-ccc', str(tgt)
 
         # Test a list of emitter functions.
@@ -1241,43 +1432,43 @@ class BuilderTestCase(unittest.TestCase):
         env = Environment()
         b = SCons.Builder.Builder(action='foo', suffix='.o')
 
-        tgt = b(env, 'aaa')[0]
+        tgt = b(env, None, 'aaa')[0]
         assert str(tgt) == 'aaa.o', str(tgt)
         assert len(tgt.sources) == 1, map(str, tgt.sources)
         assert str(tgt.sources[0]) == 'aaa', map(str, tgt.sources)
 
-        tgt = b(env, 'bbb.c')[0]
+        tgt = b(env, None, 'bbb.c')[0]
         assert str(tgt) == 'bbb.o', str(tgt)
         assert len(tgt.sources) == 1, map(str, tgt.sources)
         assert str(tgt.sources[0]) == 'bbb.c', map(str, tgt.sources)
 
-        tgt = b(env, 'ccc.x.c')[0]
+        tgt = b(env, None, 'ccc.x.c')[0]
         assert str(tgt) == 'ccc.x.o', str(tgt)
         assert len(tgt.sources) == 1, map(str, tgt.sources)
         assert str(tgt.sources[0]) == 'ccc.x.c', map(str, tgt.sources)
 
-        tgt = b(env, ['d0.c', 'd1.c'])[0]
+        tgt = b(env, None, ['d0.c', 'd1.c'])[0]
         assert str(tgt) == 'd0.o', str(tgt)
         assert len(tgt.sources) == 2,  map(str, tgt.sources)
         assert str(tgt.sources[0]) == 'd0.c', map(str, tgt.sources)
         assert str(tgt.sources[1]) == 'd1.c', map(str, tgt.sources)
 
-        tgt = b(env, source='eee')[0]
+        tgt = b(env, target = None, source='eee')[0]
         assert str(tgt) == 'eee.o', str(tgt)
         assert len(tgt.sources) == 1, map(str, tgt.sources)
         assert str(tgt.sources[0]) == 'eee', map(str, tgt.sources)
 
-        tgt = b(env, source='fff.c')[0]
+        tgt = b(env, target = None, source='fff.c')[0]
         assert str(tgt) == 'fff.o', str(tgt)
         assert len(tgt.sources) == 1, map(str, tgt.sources)
         assert str(tgt.sources[0]) == 'fff.c', map(str, tgt.sources)
 
-        tgt = b(env, source='ggg.x.c')[0]
+        tgt = b(env, target = None, source='ggg.x.c')[0]
         assert str(tgt) == 'ggg.x.o', str(tgt)
         assert len(tgt.sources) == 1, map(str, tgt.sources)
         assert str(tgt.sources[0]) == 'ggg.x.c', map(str, tgt.sources)
 
-        tgt = b(env, source=['h0.c', 'h1.c'])[0]
+        tgt = b(env, target = None, source=['h0.c', 'h1.c'])[0]
         assert str(tgt) == 'h0.o', str(tgt)
         assert len(tgt.sources) == 2,  map(str, tgt.sources)
         assert str(tgt.sources[0]) == 'h0.c', map(str, tgt.sources)
@@ -1285,7 +1476,7 @@ class BuilderTestCase(unittest.TestCase):
 
         w = b(env, target='i0.w', source=['i0.x'])[0]
         y = b(env, target='i1.y', source=['i1.z'])[0]
-        tgt = b(env, source=[w, y])[0]
+        tgt = b(env, None, source=[w, y])[0]
         assert str(tgt) == 'i0.o', str(tgt)
         assert len(tgt.sources) == 2, map(str, tgt.sources)
         assert str(tgt.sources[0]) == 'i0.w', map(str, tgt.sources)
@@ -1316,18 +1507,31 @@ class BuilderTestCase(unittest.TestCase):
                                      'B2': b2,
                                      'B3': b3,
                                      'B4': b4})
+        # With no name, get_name will return the class.  Allow
+        # for caching...
+        b6_names = [
+            'SCons.Builder.BuilderBase',
+            "<class 'SCons.Builder.BuilderBase'>",
+            'SCons.Memoize.BuilderBase',
+            "<class 'SCons.Memoize.BuilderBase'>",
+        ]
+
         assert b1.get_name(env) == 'bldr1', b1.get_name(env)
         assert b2.get_name(env) == 'bldr2', b2.get_name(env)
         assert b3.get_name(env) == 'bldr3', b3.get_name(env)
         assert b4.get_name(env) == 'bldr4', b4.get_name(env)
         assert b5.get_name(env) == 'builder5', b5.get_name(env)
-        assert b6.get_name(env) == 'SCons.Builder.BuilderBase', b6.get_name(env)
+        assert b6.get_name(env) in b6_names, b6.get_name(env)
+
         assert b1.get_name(env2) == 'B1', b1.get_name(env2)
         assert b2.get_name(env2) == 'B2', b2.get_name(env2)
         assert b3.get_name(env2) == 'B3', b3.get_name(env2)
         assert b4.get_name(env2) == 'B4', b4.get_name(env2)
         assert b5.get_name(env2) == 'builder5', b5.get_name(env2)
-        assert b6.get_name(env2) == 'SCons.Builder.BuilderBase', b6.get_name(env2)
+        assert b6.get_name(env2) in b6_names, b6.get_name(env2)
+
+        assert b5.get_name(None) == 'builder5', b5.get_name(None)
+        assert b6.get_name(None) in b6_names, b6.get_name(None)
 
         for B in b3.get_src_builders(env):
             assert B.get_name(env) == 'bldr1'
@@ -1336,7 +1540,8 @@ class BuilderTestCase(unittest.TestCase):
 
         tgts = b1(env, target = [outfile, outfile2], source='moo')
         for t in tgts:
-            assert t.builder.get_name(env) == 'ListBuilder(bldr1)'
+            name = t.builder.get_name(env)
+            assert name == 'ListBuilder(bldr1)', name
             # The following are not symbolically correct, because the
             # ListBuilder was only created on behalf of env, so it
             # would probably be OK if better correctness
index 1720aaa4100e8f4e6fb284389febe5ddbfa154ea..84dfe589bab195465131f8edd763c1f508b12617 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <builder name="DVI">
 <summary>
 Builds a <filename>.dvi</filename> file
@@ -111,12 +116,24 @@ file.
 </summary>
 </cvar>
 
+<cvar name="_CPPDEFFLAGS">
+<summary>
+An automatically-generated construction variable
+containing the C preprocessor command-line options
+to define values.
+The value of &cv-_CPPDEFFLAGS; is created
+by appending &cv-CPPDEFPREFIX; and &cv-CPPDEFSUFFIX;
+to the beginning and end
+of each directory in &cv-CPPDEFINES;.
+</summary>
+</cvar>
+
 <cvar name="CPPDEFINES">
 <summary>
 A platform independent specification of C preprocessor definitions.
 The definitions will be added to command lines
 through the automatically-generated
-&cv-_CPPDEFFLAGS; construction variable (see below),
+&cv-_CPPDEFFLAGS; construction variable (see above),
 which is constructed according to
 the type of value of &cv-CPPDEFINES;:
 
@@ -163,7 +180,8 @@ 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
-&scons; is run.
+&scons;
+is run.
 
 <example>
 # Will add -DA -DB=2 to POSIX compiler command lines,
@@ -173,18 +191,6 @@ env = Environment(CPPDEFINES={'B':2, 'A':None})
 </summary>
 </cvar>
 
-<cvar name="_CPPDEFFLAGS">
-<summary>
-An automatically-generated construction variable
-containing the C preprocessor command-line options
-to define values.
-The value of &cv-_CPPDEFFLAGS; is created
-by appending &cv-CPPDEFPREFIX; and &cv-CPPDEFSUFFIX;
-to the beginning and end
-of each directory in &cv-CPPDEFINES;.
-</summary>
-</cvar>
-
 <cvar name="CPPDEFPREFIX">
 <summary>
 The prefix used to specify preprocessor definitions
@@ -225,7 +231,7 @@ directories for include files. Don't explicitly put include directory
 arguments in CCFLAGS or CXXFLAGS because the result will be non-portable
 and the directories will not be searched by the dependency scanner. Note:
 directory names in CPPPATH will be looked-up relative to the SConscript
-directory when they are used in a command. To force 
+directory when they are used in a command. To force
 &scons;
 to look-up a directory relative to the root of the source tree use #:
 
@@ -233,7 +239,7 @@ to look-up a directory relative to the root of the source tree use #:
 env = Environment(CPPPATH='#/include')
 </example>
 
-The directory look-up can also be forced using the 
+The directory look-up can also be forced using the
 &Dir;()
 function:
 
@@ -265,7 +271,7 @@ env = Environment(CCCOM="my_compiler $_CPPINCFLAGS -c -o $TARGET $SOURCE")
 <cvar name="Dir">
 <summary>
 A function that converts a string
-into a Dir instance relative to the target being built. 
+into a Dir instance relative to the target being built.
 </summary>
 </cvar>
 
@@ -291,7 +297,7 @@ The default list is:
 <cvar name="File">
 <summary>
 A function that converts a string into a File instance relative to the
-target being built. 
+target being built.
 </summary>
 </cvar>
 
@@ -354,6 +360,17 @@ in force for this file installation.
 </summary>
 </cvar>
 
+<cvar name="INSTALLSTR">
+<summary>
+The string displayed when a file is
+installed into a destination file name.
+The default is:
+<example>
+Install file: "$SOURCE" as "$TARGET"
+</example>
+</summary>
+</cvar>
+
 <cvar name="LATEXSUFFIXES">
 <summary>
 The list of suffixes of files that will be scanned
@@ -436,7 +453,7 @@ arguments in &cv-LINKFLAGS; or &cv-SHLINKFLAGS;
 because the result will be non-portable
 and the directories will not be searched by the dependency scanner. Note:
 directory names in LIBPATH will be looked-up relative to the SConscript
-directory when they are used in a command. To force 
+directory when they are used in a command. To force
 &scons;
 to look-up a directory relative to the root of the source tree use #:
 
@@ -444,7 +461,7 @@ to look-up a directory relative to the root of the source tree use #:
 env = Environment(LIBPATH='#/libs')
 </example>
 
-The directory look-up can also be forced using the 
+The directory look-up can also be forced using the
 &Dir;()
 function:
 
@@ -534,6 +551,6 @@ The suffix used for PDF file names.
 <cvar name="RDirs">
 <summary>
 A function that converts a string into a list of Dir instances by
-searching the repositories. 
+searching the repositories.
 </summary>
 </cvar>
index d41cdafb3e3099b6c5e8738475d99a2ba9197d69..a8611052bc078927dd602fc4c07706fc772aee0f 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <cvar name="BUILDERS">
 <summary>
 A dictionary mapping the names of the builders
@@ -34,8 +39,8 @@ env['BUILDERS]['NewBuilder'] = foo
 
 <cvar name="Dir">
 <summary>
-A function that converts a file name into a Dir instance relative to the
-target being built. 
+A function that converts a string
+into a Dir instance relative to the target being built.
 </summary>
 </cvar>
 
@@ -91,15 +96,8 @@ env = Environment(ENV = {'PATH' : os.environ['PATH']})
 
 <cvar name="File">
 <summary>
-A function that converts a file name into a File instance relative to the
-target being built. 
-</summary>
-</cvar>
-
-<cvar name="RDirs">
-<summary>
-A function that converts a file name into a list of Dir instances by
-searching the repositories. 
+A function that converts a string into a File instance relative to the
+target being built.
 </summary>
 </cvar>
 
index b7d7af9a7c6a39d1a932347429b95ddfdb6470be..810ede73e2ce2535caab5572855b3115081984ae 100644 (file)
@@ -5,9 +5,8 @@ File system nodes.
 These Nodes represent the canonical external objects that people think
 of when they think of building software: files and directories.
 
-This initializes a "default_fs" Node with an FS at the current directory
-for its own purposes, and for use by scripts or modules looking for the
-canonical default.
+This holds a "default_fs" variable that should be initialized with an FS
+that can be used by scripts or modules looking for the canonical default.
 
 """
 
@@ -50,9 +49,14 @@ from SCons.Debug import logInstanceCreation
 import SCons.Errors
 import SCons.Node
 import SCons.Sig.MD5
+import SCons.Subst
 import SCons.Util
 import SCons.Warnings
 
+# The max_drift value:  by default, use a cached signature value for
+# any file that's been untouched for more than two days.
+default_max_drift = 2*24*60*60
+
 #
 # We stringify these file system Nodes a lot.  Turning a file system Node
 # into a string is non-trivial, because the final string representation
@@ -153,7 +157,13 @@ def LinkFunc(target, source, env):
         try:
             func(src,dest)
             break
-        except OSError:
+        except (IOError, OSError):
+            # An OSError indicates something happened like a permissions
+            # problem or an attempt to symlink across file-system
+            # boundaries.  An IOError indicates something like the file
+            # not existing.  In either case, keeping trying additional
+            # functions in the list and only raise an error if the last
+            # one failed.
             if func == Link_Funcs[-1]:
                 # exception of the last link method (copy) are fatal
                 raise
@@ -176,9 +186,8 @@ Unlink = SCons.Action.Action(UnlinkFunc, None)
 
 def MkdirFunc(target, source, env):
     t = target[0]
-    p = t.abspath
-    if not t.fs.exists(p):
-        t.fs.mkdir(p)
+    if not t.exists():
+        t.fs.mkdir(t.abspath)
     return 0
 
 Mkdir = SCons.Action.Action(MkdirFunc, None, presub=None)
@@ -238,10 +247,12 @@ def CachePushFunc(target, source, env):
         fs.rename(tempfile, cachefile)
         st = fs.stat(t.path)
         fs.chmod(cachefile, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
-    except OSError:
-        # It's possible someone else tried writing the file at the same
-        # time we did.  Print a warning but don't stop the build, since
-        # it doesn't affect the correctness of the build.
+    except (IOError, OSError):
+        # It's possible someone else tried writing the file at the
+        # same time we did, or else that there was some problem like
+        # the CacheDir being on a separate file system that's full.
+        # In any case, inability to push a file to cache doesn't affect
+        # the correctness of the build, so just print a warning.
         SCons.Warnings.warn(SCons.Warnings.CacheWriteErrorWarning,
                             "Unable to copy %s to cache. Cache file is %s"
                                 % (str(target), cachefile))
@@ -281,44 +292,6 @@ def get_DefaultRCSBuilder():
                                                   name = "DefaultRCSBuilder")
     return DefaultRCSBuilder
 
-#
-class ParentOfRoot:
-    """
-    An instance of this class is used as the parent of the root of a
-    filesystem (POSIX) or drive (Win32). This isn't actually a node,
-    but it looks enough like one so that we don't have to have
-    special purpose code everywhere to deal with dir being None. 
-    This class is an instance of the Null object pattern.
-    """
-    def __init__(self):
-        self.abspath = ''
-        self.path = ''
-        self.name=''
-        self.duplicate=0
-        self.srcdir=None
-        self.build_dirs=[]
-        
-    def is_under(self, dir):
-        return 0
-
-    def up(self):
-        return None
-
-    def getRepositories(self):
-        return []
-
-    def get_dir(self):
-        return None
-
-    def src_builder(self):
-        return _null
-
-    def entry_abspath(self, name):
-        return name
-
-    def entry_path(self, name):
-        return name
-
 # Cygwin's os.path.normcase pretends it's on a case-sensitive filesystem.
 _is_cygwin = sys.platform == "cygwin"
 if os.path.normcase("TeSt") == os.path.normpath("TeSt") and not _is_cygwin:
@@ -328,31 +301,96 @@ else:
     def _my_normcase(x):
         return string.upper(x)
 
+
+
+class DiskChecker:
+    def __init__(self, type, do, ignore):
+        self.type = type
+        self.do = do
+        self.ignore = ignore
+        self.set_do()
+    def set_do(self):
+        self.__call__ = self.do
+    def set_ignore(self):
+        self.__call__ = self.ignore
+    def set(self, list):
+        if self.type in list:
+            self.set_do()
+        else:
+            self.set_ignore()
+
+def do_diskcheck_match(node, predicate, errorfmt):
+    path = node.abspath
+    if predicate(path):
+        raise TypeError, errorfmt % path
+
+def ignore_diskcheck_match(node, predicate, errorfmt):
+    pass
+
+def do_diskcheck_rcs(node, name):
+    try:
+        rcs_dir = node.rcs_dir
+    except AttributeError:
+        rcs_dir = node.rcs_dir = node.Dir('RCS')
+    return rcs_dir.entry_exists_on_disk(name+',v')
+
+def ignore_diskcheck_rcs(node, name):
+    return None
+
+def do_diskcheck_sccs(node, name):
+    try:
+        sccs_dir = node.sccs_dir
+    except AttributeError:
+        sccs_dir = node.sccs_dir = node.Dir('SCCS')
+    return sccs_dir.entry_exists_on_disk('s.'+name)
+
+def ignore_diskcheck_sccs(node, name):
+    return None
+
+diskcheck_match = DiskChecker('match', do_diskcheck_match, ignore_diskcheck_match)
+diskcheck_rcs = DiskChecker('rcs', do_diskcheck_rcs, ignore_diskcheck_rcs)
+diskcheck_sccs = DiskChecker('sccs', do_diskcheck_sccs, ignore_diskcheck_sccs)
+
+diskcheckers = [
+    diskcheck_match,
+    diskcheck_rcs,
+    diskcheck_sccs,
+]
+
+def set_diskcheck(list):
+    for dc in diskcheckers:
+        dc.set(list)
+
+def diskcheck_types():
+    return map(lambda dc: dc.type, diskcheckers)
+
+
+
 class EntryProxy(SCons.Util.Proxy):
     def __get_abspath(self):
         entry = self.get()
-        return SCons.Util.SpecialAttrWrapper(entry.get_abspath(),
+        return SCons.Subst.SpecialAttrWrapper(entry.get_abspath(),
                                              entry.name + "_abspath")
 
     def __get_filebase(self):
         name = self.get().name
-        return SCons.Util.SpecialAttrWrapper(SCons.Util.splitext(name)[0],
+        return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(name)[0],
                                              name + "_filebase")
 
     def __get_suffix(self):
         name = self.get().name
-        return SCons.Util.SpecialAttrWrapper(SCons.Util.splitext(name)[1],
+        return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(name)[1],
                                              name + "_suffix")
 
     def __get_file(self):
         name = self.get().name
-        return SCons.Util.SpecialAttrWrapper(name, name + "_file")
+        return SCons.Subst.SpecialAttrWrapper(name, name + "_file")
 
     def __get_base_path(self):
         """Return the file's directory and file name, with the
         suffix stripped."""
         entry = self.get()
-        return SCons.Util.SpecialAttrWrapper(SCons.Util.splitext(entry.get_path())[0],
+        return SCons.Subst.SpecialAttrWrapper(SCons.Util.splitext(entry.get_path())[0],
                                              entry.name + "_base")
 
     def __get_posix_path(self):
@@ -363,7 +401,7 @@ class EntryProxy(SCons.Util.Proxy):
         else:
             entry = self.get()
             r = string.replace(entry.get_path(), os.sep, '/')
-            return SCons.Util.SpecialAttrWrapper(r, entry.name + "_posix")
+            return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_posix")
 
     def __get_win32_path(self):
         """Return the path with \ as the path separator,
@@ -373,7 +411,7 @@ class EntryProxy(SCons.Util.Proxy):
         else:
             entry = self.get()
             r = string.replace(entry.get_path(), os.sep, '\\')
-            return SCons.Util.SpecialAttrWrapper(r, entry.name + "_win32")
+            return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_win32")
 
     def __get_srcnode(self):
         return EntryProxy(self.get().srcnode())
@@ -461,6 +499,11 @@ class Base(SCons.Node.Node):
             self.path = name
         else:
             self.path = directory.entry_path(name)
+        if directory.tpath == '.':
+            self.tpath = name
+        else:
+            self.tpath = directory.entry_tpath(name)
+        self.path_elements = directory.path_elements + [self]
 
         self.dir = directory
         self.cwd = None # will hold the SConscript directory for target nodes
@@ -503,14 +546,46 @@ class Base(SCons.Node.Node):
 
     rstr = __str__
 
+    def stat(self):
+        "__cacheable__"
+        try: return self.fs.stat(self.abspath)
+        except os.error: return None
+
     def exists(self):
         "__cacheable__"
-        return self.fs.exists(self.abspath)
+        return not self.stat() is None
 
     def rexists(self):
         "__cacheable__"
         return self.rfile().exists()
 
+    def getmtime(self):
+        st = self.stat()
+        if st: return st[stat.ST_MTIME]
+        else: return None
+
+    def getsize(self):
+        st = self.stat()
+        if st: return st[stat.ST_SIZE]
+        else: return None
+
+    def isdir(self):
+        st = self.stat()
+        return not st is None and stat.S_ISDIR(st[stat.ST_MODE])
+
+    def isfile(self):
+        st = self.stat()
+        return not st is None and stat.S_ISREG(st[stat.ST_MODE])
+
+    if hasattr(os, 'symlink'):
+        def islink(self):
+            try: st = self.fs.lstat(self.abspath)
+            except os.error: return 0
+            return stat.S_ISLNK(st[stat.ST_MODE])
+    else:
+        def islink(self):
+            return 0                    # no symlinks
+
     def is_under(self, dir):
         if self is dir:
             return 1
@@ -533,7 +608,7 @@ class Base(SCons.Node.Node):
                                         klass=self.__class__)
                 return srcnode
             name = dir.name + os.sep + name
-            dir=dir.get_dir()
+            dir = dir.up()
         return self
 
     def get_path(self, dir=None):
@@ -541,18 +616,15 @@ class Base(SCons.Node.Node):
         Node.FS.Base object that owns us."""
         if not dir:
             dir = self.fs.getcwd()
-        path_elems = []
-        d = self
-        if d == dir:
-            path_elems.append('.')
-        else:
-            while d != dir and not isinstance(d, ParentOfRoot):
-                path_elems.append(d.name)
-                d = d.dir
-            path_elems.reverse()
-        ret = string.join(path_elems, os.sep)
-        return ret
-            
+        if self == dir:
+            return '.'
+        path_elems = self.path_elements
+        try: i = path_elems.index(dir)
+        except ValueError: pass
+        else: path_elems = path_elems[i+1:]
+        path_elems = map(lambda n: n.name, path_elems)
+        return string.join(path_elems, os.sep)
+
     def set_src_builder(self, builder):
         """Set the source code builder for this node."""
         self.sbuilder = builder
@@ -599,8 +671,11 @@ class Entry(Base):
     time comes, and then call the same-named method in the transformed
     class."""
 
+    def diskcheck_match(self):
+        pass
+
     def disambiguate(self):
-        if self.fs.isdir(self.abspath):
+        if self.isdir():
             self.__class__ = Dir
             self._morph()
         else:
@@ -631,18 +706,21 @@ class Entry(Base):
         Since this should return the real contents from the file
         system, we check to see into what sort of subclass we should
         morph this Entry."""
-        if self.fs.isfile(self.abspath):
+        if self.isfile():
             self.__class__ = File
             self._morph()
             return self.get_contents()
-        if self.fs.isdir(self.abspath):
+        if self.isdir():
             self.__class__ = Dir
             self._morph()
             return self.get_contents()
-        if self.fs.islink(self.abspath):
+        if self.islink():
             return ''             # avoid errors for dangling symlinks
         raise AttributeError
 
+    def rel_path(self, other):
+        return self.disambiguate().rel_path(other)
+
     def exists(self):
         """Return if the Entry exists.  Check the file system to see
         what we should turn into first.  Assume a file if there's no
@@ -669,7 +747,8 @@ _classEntry = Entry
 
 class LocalFS:
 
-    __metaclass__ = SCons.Memoize.Memoized_Metaclass
+    if SCons.Memoize.use_memoizer:
+        __metaclass__ = SCons.Memoize.Memoized_Metaclass
     
     # This class implements an abstraction layer for operations involving
     # a local file system.  Essentially, this wraps any function in
@@ -695,12 +774,16 @@ class LocalFS:
         return os.path.exists(path)
     def getmtime(self, path):
         return os.path.getmtime(path)
+    def getsize(self, path):
+        return os.path.getsize(path)
     def isdir(self, path):
         return os.path.isdir(path)
     def isfile(self, path):
         return os.path.isfile(path)
     def link(self, src, dst):
         return os.link(src, dst)
+    def lstat(self, path):
+        return os.lstat(path)
     def listdir(self, path):
         return os.listdir(path)
     def makedirs(self, path):
@@ -721,14 +804,11 @@ class LocalFS:
     if hasattr(os, 'symlink'):
         def islink(self, path):
             return os.path.islink(path)
-        def exists_or_islink(self, path):
-            return os.path.exists(path) or os.path.islink(path)
     else:
         def islink(self, path):
             return 0                    # no symlinks
-        exists_or_islink = exists
 
-if not SCons.Memoize.has_metaclass:
+if SCons.Memoize.use_old_memoization():
     _FSBase = LocalFS
     class LocalFS(SCons.Memoize.Memoizer, _FSBase):
         def __init__(self, *args, **kw):
@@ -757,20 +837,22 @@ class FS(LocalFS):
         The path argument must be a valid absolute path.
         """
         if __debug__: logInstanceCreation(self, 'Node.FS')
-        self.Top = None
-        if path == None:
-            self.pathTop = os.getcwd()
-        else:
-            self.pathTop = path
         self.Root = {}
         self.SConstruct_dir = None
         self.CachePath = None
         self.cache_force = None
         self.cache_show = None
+        self.max_drift = default_max_drift
+
+        if path is None:
+            self.pathTop = os.getcwd()
+        else:
+            self.pathTop = path
 
-    def set_toplevel_dir(self, path):
-        assert not self.Top, "You can only set the top-level path on an FS object that has not had its File, Dir, or Entry methods called yet."
-        self.pathTop = path
+        self.Top = self._doLookup(Dir, os.path.normpath(self.pathTop))
+        self.Top.path = '.'
+        self.Top.tpath = '.'
+        self._cwd = self.Top
 
     def clear_cache(self):
         "__cache_reset__"
@@ -778,15 +860,14 @@ class FS(LocalFS):
     
     def set_SConstruct_dir(self, dir):
         self.SConstruct_dir = dir
-        
-    def __setTopLevelDir(self):
-        if not self.Top:
-            self.Top = self._doLookup(Dir, os.path.normpath(self.pathTop))
-            self.Top.path = '.'
-            self._cwd = self.Top
-        
+
+    def get_max_drift(self):
+        return self.max_drift
+
+    def set_max_drift(self, max_drift):
+        self.max_drift = max_drift
+
     def getcwd(self):
-        self.__setTopLevelDir()
         return self._cwd
 
     def __checkClass(self, node, klass):
@@ -809,9 +890,10 @@ class FS(LocalFS):
         __cacheable__"""
 
         if not name:
-            # This is a stupid hack to compensate for the fact
-            # that the POSIX and Win32 versions of os.path.normpath()
-            # behave differently.  In particular, in POSIX:
+            # This is a stupid hack to compensate for the fact that
+            # the POSIX and Win32 versions of os.path.normpath() behave
+            # differently in older versions of Python.  In particular,
+            # in POSIX:
             #   os.path.normpath('./') == '.'
             # in Win32
             #   os.path.normpath('./') == ''
@@ -820,75 +902,81 @@ class FS(LocalFS):
             # This is a definite bug in the Python library, but we have
             # to live with it.
             name = '.'
-        path_comp = string.split(name, os.sep)
-        drive, path_first = os.path.splitdrive(path_comp[0])
-        if not path_first:
-            # Absolute path
+        path_orig = string.split(name, os.sep)
+        path_norm = string.split(_my_normcase(name), os.sep)
+
+        first_orig = path_orig.pop(0)   # strip first element
+        first_norm = path_norm.pop(0)   # strip first element
+
+        drive, path_first = os.path.splitdrive(first_orig)
+        if path_first:
+            path_orig = [ path_first, ] + path_orig
+            path_norm = [ _my_normcase(path_first), ] + path_norm
+        else:
             drive = _my_normcase(drive)
+            # Absolute path
             try:
                 directory = self.Root[drive]
             except KeyError:
                 if not create:
                     raise SCons.Errors.UserError
-                directory = RootDir(drive, ParentOfRoot(), self)
+                directory = RootDir(drive, self)
                 self.Root[drive] = directory
-            path_comp = path_comp[1:]
-        else:
-            path_comp = [ path_first, ] + path_comp[1:]
 
-        if not path_comp:
-            path_comp = ['']
+        if not path_orig:
+            return directory
+
+        last_orig = path_orig.pop()     # strip last element
+        last_norm = path_norm.pop()     # strip last element
             
         # Lookup the directory
-        for path_name in path_comp[:-1]:
-            path_norm = _my_normcase(path_name)
+        for orig, norm in map(None, path_orig, path_norm):
+            try:
+                entries = directory.entries
+            except AttributeError:
+                # We tried to look up the entry in either an Entry or
+                # a File.  Give whatever it is a chance to do what's
+                # appropriate: morph into a Dir or raise an exception.
+                directory.must_be_a_Dir()
+                entries = directory.entries
             try:
-                d = directory.entries[path_norm]
+                directory = entries[norm]
             except KeyError:
                 if not create:
                     raise SCons.Errors.UserError
 
-                # look at the actual filesystem and make sure there isn't
-                # a file already there
-                path = directory.entry_path(path_name)
-                if self.isfile(path):
-                    raise TypeError, \
-                          "File %s found where directory expected." % path
-
-                dir_temp = Dir(path_name, directory, self)
-                directory.entries[path_norm] = dir_temp
-                directory.add_wkid(dir_temp)
-                directory = dir_temp
-            else:
-                directory = d.must_be_a_Dir()
+                d = Dir(orig, directory, self)
+
+                # Check the file system (or not, as configured) to make
+                # sure there isn't already a file there.
+                d.diskcheck_match()
+
+                directory.entries[norm] = d
+                directory.add_wkid(d)
+                directory = d
+
+        directory.must_be_a_Dir()
 
-        entry_norm = _my_normcase(path_comp[-1])
         try:
-            e = directory.entries[entry_norm]
+            e = directory.entries[last_norm]
         except KeyError:
             if not create:
                 raise SCons.Errors.UserError
 
-            # make sure we don't create File nodes when there is actually
-            # a directory at that path on the disk, and vice versa
-            path = directory.entry_path(path_comp[-1])
-            if fsclass == File:
-                if self.isdir(path):
-                    raise TypeError, \
-                          "Directory %s found where file expected." % path
-            elif fsclass == Dir:
-                if self.isfile(path):
-                    raise TypeError, \
-                          "File %s found where directory expected." % path
-            
-            result = fsclass(path_comp[-1], directory, self)
-            directory.entries[entry_norm] = result 
+            result = fsclass(last_orig, directory, self)
+
+            # Check the file system (or not, as configured) to make
+            # sure there isn't already a directory at the path on
+            # disk where we just created a File node, and vice versa.
+            result.diskcheck_match()
+
+            directory.entries[last_norm] = result 
             directory.add_wkid(result)
         else:
             result = self.__checkClass(e, fsclass)
         return result 
 
-    def __transformPath(self, name, directory):
+    def _transformPath(self, name, directory):
         """Take care of setting up the correct top-level directory,
         usually in preparation for a call to doLookup().
 
@@ -898,7 +986,6 @@ class FS(LocalFS):
         If directory is None, and name is a relative path,
         then the same applies.
         """
-        self.__setTopLevelDir()
         if name and name[0] == '#':
             directory = self.Top
             name = name[1:]
@@ -916,7 +1003,6 @@ class FS(LocalFS):
         If change_os_dir is true, we will also change the "real" cwd
         to match.
         """
-        self.__setTopLevelDir()
         curr=self._cwd
         try:
             if not dir is None:
@@ -943,7 +1029,7 @@ class FS(LocalFS):
         else:
             if directory and not isinstance(directory, Dir):
                 directory = self.Dir(directory)
-            name, directory = self.__transformPath(name, directory)
+            name, directory = self._transformPath(name, directory)
             return self._doLookup(klass, name, directory, create)
     
     def File(self, name, directory = None, create = 1):
@@ -976,13 +1062,10 @@ class FS(LocalFS):
         """Link the supplied build directory to the source directory
         for purposes of building files."""
         
-        self.__setTopLevelDir()
         if not isinstance(src_dir, SCons.Node.Node):
             src_dir = self.Dir(src_dir)
         if not isinstance(build_dir, SCons.Node.Node):
             build_dir = self.Dir(build_dir)
-        if not src_dir.is_under(self.Top):
-            raise SCons.Errors.UserError, "Source directory must be under top of build tree."
         if src_dir.is_under(build_dir):
             raise SCons.Errors.UserError, "Source directory cannot be under build directory."
         if build_dir.srcdir:
@@ -996,118 +1079,23 @@ class FS(LocalFS):
         for d in dirs:
             if not isinstance(d, SCons.Node.Node):
                 d = self.Dir(d)
-            self.__setTopLevelDir()
             self.Top.addRepository(d)
 
-    def do_Rsearch(self, path, dir, func, clazz=_classEntry):
-        """Search for something in a Repository.  Returns the first
-        one found in the list, or None if there isn't one.
-        __cacheable__
-        """
-        d, name = os.path.split(path)
-        norm_name = _my_normcase(name)
-        if d:
-            dir = dir.Dir(d)
-        try:
-            node = dir.entries[norm_name]
-        except KeyError:
-            node = dir.node_on_disk(name, clazz)
-        else:
-            node = func(node)
-            if node:
-                dir = node.get_dir()
-        if node:
-            return node, dir
-        fname = '.'
-        while dir:
-            for rep in dir.getRepositories():
-                rdir = rep.Dir(fname)
-                try:
-                    node = rdir.entries[norm_name]
-                except KeyError:
-                    node = rdir.node_on_disk(name, clazz)
-                else:
-                    node = func(node)
-                if node:
-                    return node, dir
-            fname = dir.name + os.sep + fname
-            dir = dir.get_dir()
-        return None, None
-
-    def Rsearch(self, path, clazz=_classEntry, cwd=None):
-        if isinstance(path, SCons.Node.Node):
-            return path
-        def func(node, clazz=clazz):
-            if node.exists() and \
-               (isinstance(node, clazz) or isinstance(node, Entry) \
-                or not node.is_derived()):
-                   return node
-            return None
-        path, dir = self.__transformPath(path, cwd)
-        return self.do_Rsearch(path, dir, func, clazz)[0]
-
-    def Rsearchall(self, pathlist, must_exist=1, clazz=_classEntry, cwd=None):
-        """Search for a list of somethings in the Repository list.
-        __cacheable__
-        """
-        result = []
+    def Rfindalldirs(self, pathlist, cwd):
+        """__cacheable__"""
         if SCons.Util.is_String(pathlist):
             pathlist = string.split(pathlist, os.pathsep)
         if not SCons.Util.is_List(pathlist):
             pathlist = [pathlist]
-
-        if must_exist:
-            select = lambda x, clazz=clazz: isinstance(x, clazz) and x.exists()
-        else:
-            select = lambda x, clazz=clazz: isinstance(x, clazz)
-
+        result = []
         for path in filter(None, pathlist):
             if isinstance(path, SCons.Node.Node):
                 result.append(path)
                 continue
-
-            path, dir = self.__transformPath(path, cwd)
-            d, name = os.path.split(path)
-            norm_name = _my_normcase(name)
-            if d:
-                dir = dir.Dir(d)
-            try:
-                node = dir.entries[norm_name]
-            except KeyError:
-                # If there's no Node on disk, we'll filter
-                # out the returned None below.
-                if must_exist:
-                    n = dir.node_on_disk(name, clazz)
-                else:
-                    n = self._doLookup(clazz, name, dir)
-                    dir.srcdir_duplicate(name, clazz)
-                result.append(n)
-            else:
-                if not must_exist or node.exists():
-                    result.append(node)
-            fname = '.'
-            while dir:
-                for rep in dir.getRepositories():
-                    rdir = rep.Dir(fname)
-                    try:
-                        node = rdir.entries[norm_name]
-                    except KeyError:
-                        # If there's no Node on disk, we'll filter
-                        # out the returned None below.
-                        if must_exist:
-                            n = rdir.node_on_disk(name, clazz)
-                        else:
-                            n = self._doLookup(clazz, name, rdir)
-                            rdir.srcdir_duplicate(name, clazz)
-                        result.append(n)
-                    else:
-                        if (not must_exist or node.exists()) and \
-                           (isinstance(node, Dir) or not node.is_derived()):
-                            result.append(node)
-                fname = dir.name + os.sep + fname
-                dir = dir.get_dir()
-
-        return filter(None, result)
+            path, dir = self._transformPath(path, cwd)
+            dir = dir.Dir(path)
+            result.extend(dir.get_all_rdirs())
+        return result
 
     def CacheDir(self, path):
         self.CachePath = path
@@ -1136,7 +1124,6 @@ class FS(LocalFS):
             message = fmt % string.join(map(str, targets))
         return targets, message
 
-
 class Dir(Base):
     """A class for directories in a file system.
     """
@@ -1162,11 +1149,20 @@ class Dir(Base):
         self.entries['.'] = self
         self.entries['..'] = self.dir
         self.cwd = self
-        self.builder = get_MkdirBuilder()
         self.searched = 0
         self._sconsign = None
         self.build_dirs = []
 
+        # Don't just reset the executor, replace its action list,
+        # because it might have some pre-or post-actions that need to
+        # be preserved.
+        self.builder = get_MkdirBuilder()
+        self.get_executor().set_action_list(self.builder.action)
+
+    def diskcheck_match(self):
+        diskcheck_match(self, self.fs.isfile,
+                           "File %s found where directory expected.")
+
     def disambiguate(self):
         return self
 
@@ -1213,32 +1209,56 @@ class Dir(Base):
         srcdir.build_dirs.append(self)
 
     def getRepositories(self):
-        """Returns a list of repositories for this directory."""
+        """Returns a list of repositories for this directory.
+        __cacheable__"""
         if self.srcdir and not self.duplicate:
-            try:
-                return self._srcreps
-            except AttributeError:
-                self._srcreps = self.fs.Rsearchall(self.srcdir.path,
-                                                   clazz=Dir,
-                                                   must_exist=0,
-                                                   cwd=self.fs.Top) \
-                                + self.repositories
-                return self._srcreps
+            return self.srcdir.get_all_rdirs() + self.repositories
         return self.repositories
 
+    def get_all_rdirs(self):
+        """__cacheable__"""
+        result = [self]
+        fname = '.'
+        dir = self
+        while dir:
+            for rep in dir.getRepositories():
+                result.append(rep.Dir(fname))
+            fname = dir.name + os.sep + fname
+            dir = dir.up()
+        return result
+
     def addRepository(self, dir):
-        if not dir in self.repositories and dir != self:
+        if dir != self and not dir in self.repositories:
             self.repositories.append(dir)
+            dir.tpath = '.'
             self.__clearRepositoryCache()
 
     def up(self):
         return self.entries['..']
 
-    def root(self):
-        if not self.entries['..']:
-            return self
+    def rel_path(self, other):
+        """Return a path to "other" relative to this directory.
+        __cacheable__"""
+        if isinstance(other, Dir):
+            name = []
         else:
-            return self.entries['..'].root()
+            try:
+                name = [other.name]
+                other = other.dir
+            except AttributeError:
+                return str(other)
+        if self is other:
+            return name and name[0] or '.'
+        i = 0
+        for x, y in map(None, self.path_elements, other.path_elements):
+            if not x is y:
+                break
+            i = i + 1
+        path_elems = ['..']*(len(self.path_elements)-i) \
+                   + map(lambda n: n.name, other.path_elements[i:]) \
+                   + name
+             
+        return string.join(path_elems, os.sep)
 
     def scan(self):
         if not self.implicit is None:
@@ -1290,7 +1310,7 @@ class Dir(Base):
                 break
             listDirs.append(parent)
             p = parent.up()
-            if isinstance(p, ParentOfRoot):
+            if p is None:
                 raise SCons.Errors.StopError, parent.path
             parent = p
         listDirs.reverse()
@@ -1354,12 +1374,15 @@ class Dir(Base):
 
     def rdir(self):
         "__cacheable__"
-        rdir = self
         if not self.exists():
-            n = self.fs.Rsearch(self.path, clazz=Dir, cwd=self.fs.Top)
-            if n:
-                rdir = n
-        return rdir
+            norm_name = _my_normcase(self.name)
+            for dir in self.dir.get_all_rdirs():
+                try: node = dir.entries[norm_name]
+                except KeyError: node = dir.dir_on_disk(self.name)
+                if node and node.exists() and \
+                    (isinstance(dir, Dir) or isinstance(dir, Entry)):
+                        return node
+        return self
 
     def sconsign(self):
         """Return the .sconsign file info for this directory,
@@ -1390,6 +1413,9 @@ class Dir(Base):
     def entry_path(self, name):
         return self.path + os.sep + name
 
+    def entry_tpath(self, name):
+        return self.tpath + os.sep + name
+
     def must_be_a_Dir(self):
         """Called to make sure a Node is a Dir.  Since we're already
         one, this is a no-op for us."""
@@ -1397,15 +1423,19 @@ class Dir(Base):
 
     def entry_exists_on_disk(self, name):
         """__cacheable__"""
-        return self.fs.exists(self.entry_abspath(name))
-
-    def rcs_on_disk(self, name):
-        rcspath = 'RCS' + os.sep + name+',v'
-        return self.entry_exists_on_disk(rcspath)
-
-    def sccs_on_disk(self, name):
-        sccspath = 'SCCS' + os.sep + 's.'+name
-        return self.entry_exists_on_disk(sccspath)
+        try:
+            d = self.on_disk_entries
+        except AttributeError:
+            d = {}
+            try:
+                entries = os.listdir(self.abspath)
+            except OSError:
+                pass
+            else:
+                for entry in map(_my_normcase, entries):
+                    d[entry] = 1
+            self.on_disk_entries = d
+        return d.has_key(_my_normcase(name))
 
     def srcdir_list(self):
         """__cacheable__"""
@@ -1423,16 +1453,16 @@ class Dir(Base):
                     break
                 result.append(d)
             dirname = dir.name + os.sep + dirname
-            dir = dir.get_dir()
+            dir = dir.up()
 
         return result
 
-    def srcdir_duplicate(self, name, clazz):
+    def srcdir_duplicate(self, name):
         for dir in self.srcdir_list():
             if dir.entry_exists_on_disk(name):
-                srcnode = self.fs._doLookup(clazz, name, dir)
+                srcnode = dir.File(name)
                 if self.duplicate:
-                    node = self.fs._doLookup(clazz, name, self)
+                    node = self.File(name)
                     node.do_duplicate(srcnode)
                     return node
                 else:
@@ -1441,34 +1471,44 @@ class Dir(Base):
 
     def srcdir_find_file(self, filename):
         """__cacheable__"""
-        fs = self.fs
-        do_Rsearch = fs.do_Rsearch
-
         def func(node):
             if (isinstance(node, File) or isinstance(node, Entry)) and \
                (node.is_derived() or node.is_pseudo_derived() or node.exists()):
                     return node
             return None
 
-        node, d = do_Rsearch(filename, self, func, File)
-        if node:
-            return node, d
+        norm_name = _my_normcase(filename)
 
-        for dir in self.srcdir_list():
-            node, d = do_Rsearch(filename, dir, func, File)
+        for rdir in self.get_all_rdirs():
+            try: node = rdir.entries[norm_name]
+            except KeyError: node = rdir.file_on_disk(filename)
+            else: node = func(node)
             if node:
-                return File(filename, self, fs), d
+                return node, self
+
+        for srcdir in self.srcdir_list():
+            for rdir in srcdir.get_all_rdirs():
+                try: node = rdir.entries[norm_name]
+                except KeyError: node = rdir.file_on_disk(filename)
+                else: node = func(node)
+                if node:
+                    return File(filename, self, self.fs), srcdir
+
         return None, None
 
-    def node_on_disk(self, name, clazz):
+    def dir_on_disk(self, name):
+        if self.entry_exists_on_disk(name):
+            try: return self.Dir(name)
+            except TypeError: pass
+        return None
+
+    def file_on_disk(self, name):
         if self.entry_exists_on_disk(name) or \
-           self.sccs_on_disk(name) or \
-           self.rcs_on_disk(name):
-            try:
-                return self.fs._doLookup(clazz, name, self)
-            except TypeError:
-                pass
-        return self.srcdir_duplicate(name, clazz)
+           diskcheck_rcs(self, name) or \
+           diskcheck_sccs(self, name):
+            try: return self.File(name)
+            except TypeError: pass
+        return self.srcdir_duplicate(name)
 
 class RootDir(Dir):
     """A class for the root directory of a file system.
@@ -1478,30 +1518,108 @@ class RootDir(Dir):
     add a separator when creating the path names of entries within
     this directory.
     """
-    def __init__(self, name, directory, fs):
+    def __init__(self, name, fs):
         if __debug__: logInstanceCreation(self, 'Node.FS.RootDir')
-        Base.__init__(self, name, directory, fs)
-        self.path = self.path + os.sep
-        self.abspath = self.abspath + os.sep
+        # We're going to be our own parent directory (".." entry and .dir
+        # attribute) so we have to set up some values so Base.__init__()
+        # won't gag won't it calls some of our methods.
+        self.abspath = ''
+        self.path = ''
+        self.tpath = ''
+        self.path_elements = []
+        self.duplicate = 0
+        Base.__init__(self, name, self, fs)
+
+        # Now set our paths to what we really want them to be: the
+        # initial drive letter (the name) plus the directory separator.
+        self.abspath = name + os.sep
+        self.path = name + os.sep
+        self.tpath = name + os.sep
         self._morph()
 
+    def __str__(self):
+        return self.abspath
+
     def entry_abspath(self, name):
         return self.abspath + name
 
     def entry_path(self, name):
         return self.path + name
 
-class BuildInfo:
-    bsig = None
-    def __cmp__(self, other):
-        try:
-            return cmp(self.bsig, other.bsig)
-        except AttributeError:
+    def entry_tpath(self, name):
+        return self.tpath + name
+
+    def is_under(self, dir):
+        if self is dir:
             return 1
+        else:
+            return 0
+
+    def up(self):
+        return None
+
+    def get_dir(self):
+        return None
+
+    def src_builder(self):
+        return _null
+
+class NodeInfo(SCons.Node.NodeInfo):
+    def __cmp__(self, other):
+        try: return cmp(self.bsig, other.bsig)
+        except AttributeError: return 1
+    def update(self, node):
+        self.timestamp = node.get_timestamp()
+        self.size = node.getsize()
+
+class BuildInfo(SCons.Node.BuildInfo):
+    def __init__(self, node):
+        SCons.Node.BuildInfo.__init__(self, node)
+        self.node = node
+    def convert_to_sconsign(self):
+        """Convert this BuildInfo object for writing to a .sconsign file
+
+        We hung onto the node that we refer to so that we can translate
+        the lists of bsources, bdepends and bimplicit Nodes into strings
+        relative to the node, but we don't want to write out that Node
+        itself to the .sconsign file, so we delete the attribute in
+        preparation.
+        """
+        rel_path = self.node.rel_path
+        delattr(self, 'node')
+        for attr in ['bsources', 'bdepends', 'bimplicit']:
+            try:
+                val = getattr(self, attr)
+            except AttributeError:
+                pass
+            else:
+                setattr(self, attr, map(rel_path, val))
+    def convert_from_sconsign(self, dir, name):
+        """Convert a newly-read BuildInfo object for in-SCons use
+
+        An on-disk BuildInfo comes without a reference to the node
+        for which it's intended, so we have to convert the arguments
+        and add back a self.node attribute.  The bsources, bdepends and
+        bimplicit lists all come from disk as paths relative to that node,
+        so convert them to actual Nodes for use by the rest of SCons.
+        """
+        self.node = dir.Entry(name)
+        Entry_func = self.node.dir.Entry
+        for attr in ['bsources', 'bdepends', 'bimplicit']:
+            try:
+                val = getattr(self, attr)
+            except AttributeError:
+                pass
+            else:
+                setattr(self, attr, map(Entry_func, val))
 
 class File(Base):
     """A class for files in a file system.
     """
+    def diskcheck_match(self):
+        diskcheck_match(self, self.fs.isdir,
+                           "Directory %s found where file expected.")
+
     def __init__(self, name, directory, fs):
         if __debug__: logInstanceCreation(self, 'Node.FS.File')
         Base.__init__(self, name, directory, fs)
@@ -1517,6 +1635,11 @@ class File(Base):
         the SConscript directory of this file."""
         return self.fs.Dir(name, self.cwd)
 
+    def Dirs(self, pathlist):
+        """Create a list of directories relative to the SConscript
+        directory of this file."""
+        return map(lambda p, s=self: s.Dir(p), pathlist)
+
     def File(self, name):
         """Create a file node named 'name' relative to
         the SConscript directory of this file."""
@@ -1524,8 +1647,7 @@ class File(Base):
 
     def RDirs(self, pathlist):
         """Search for a list of directories in the Repository list."""
-        return self.fs.Rsearchall(pathlist, clazz=Dir, must_exist=0,
-                                  cwd=self.cwd)
+        return self.fs.Rfindalldirs(pathlist, self.cwd)
 
     def _morph(self):
         """Turn a file system node into a File object.  __cache_reset__"""
@@ -1536,9 +1658,6 @@ class File(Base):
     def disambiguate(self):
         return self
 
-    def root(self):
-        return self.dir.root()
-
     def scanner_key(self):
         return self.get_suffix()
 
@@ -1549,7 +1668,7 @@ class File(Base):
 
     def get_timestamp(self):
         if self.rexists():
-            return self.fs.getmtime(self.rfile().abspath)
+            return self.rfile().getmtime()
         else:
             return 0
 
@@ -1559,8 +1678,7 @@ class File(Base):
         # in one build (SConstruct file) is a source in a different build.
         # See test/chained-build.py for the use case.
         entry = self.get_stored_info()
-        for key, val in obj.__dict__.items():
-            entry.__dict__[key] = val
+        entry.merge(obj)
         self.dir.sconsign().set_entry(self.name, entry)
 
     def get_stored_info(self):
@@ -1568,26 +1686,27 @@ class File(Base):
         try:
             stored = self.dir.sconsign().get_entry(self.name)
         except (KeyError, OSError):
-            return BuildInfo()
+            return self.new_binfo()
         else:
-            if isinstance(stored, BuildInfo):
-                return stored
-            # The stored build information isn't a BuildInfo object.
-            # This probably means it's an old SConsignEntry from SCons
-            # 0.95 or before.  The relevant attribute names are the same,
-            # though, so just copy the attributes over to an object of
-            # the correct type.
-            binfo = BuildInfo()
-            for key, val in stored.__dict__.items():
-                setattr(binfo, key, val)
-            return binfo
+            if not hasattr(stored, 'ninfo'):
+                # Transition:  The .sconsign file entry has no NodeInfo
+                # object, which means it's a slightly older BuildInfo.
+                # Copy over the relevant attributes.
+                ninfo = stored.ninfo = self.new_ninfo()
+                for attr in ninfo.__dict__.keys():
+                    try:
+                        setattr(ninfo, attr, getattr(stored, attr))
+                    except AttributeError:
+                        pass
+            return stored
 
     def get_stored_implicit(self):
         binfo = self.get_stored_info()
-        try:
-            return binfo.bimplicit
-        except AttributeError:
-            return None
+        try: return binfo.bimplicit
+        except AttributeError: return None
+
+    def rel_path(self, other):
+        return self.dir.rel_path(other)
 
     def get_found_includes(self, env, scanner, path):
         """Return the included implicit dependencies in this file.
@@ -1649,13 +1768,13 @@ class File(Base):
         # Push this file out to cache before the superclass Node.built()
         # method has a chance to clear the build signature, which it
         # will do if this file has a source scanner.
-        if self.fs.CachePath and self.fs.exists(self.path):
+        if self.fs.CachePath and self.exists():
             CachePush(self, [], None)
         self.fs.clear_cache()
         SCons.Node.Node.built(self)
 
     def visited(self):
-        if self.fs.CachePath and self.fs.cache_force and self.fs.exists(self.path):
+        if self.fs.CachePath and self.fs.cache_force and self.exists():
             CachePush(self, None, None)
 
     def has_src_builder(self):
@@ -1677,9 +1796,9 @@ class File(Base):
             else:
                 scb = self.dir.src_builder()
                 if scb is _null:
-                    if self.dir.sccs_on_disk(self.name):
+                    if diskcheck_sccs(self.dir, self.name):
                         scb = get_DefaultSCCSBuilder()
-                    elif self.dir.rcs_on_disk(self.name):
+                    elif diskcheck_rcs(self.dir, self.name):
                         scb = get_DefaultRCSBuilder()
                     else:
                         scb = None
@@ -1720,7 +1839,7 @@ class File(Base):
 
     def remove(self):
         """Remove this file."""
-        if self.fs.exists_or_islink(self.path):
+        if self.exists() or self.islink():
             self.fs.unlink(self.path)
             return 1
         return None
@@ -1747,28 +1866,39 @@ class File(Base):
         "__cacheable__"
         # Duplicate from source path if we are set up to do this.
         if self.duplicate and not self.is_derived() and not self.linked:
-            src=self.srcnode()
+            src = self.srcnode()
             if src is self:
                 return Base.exists(self)
+            # At this point, src is meant to be copied in a build directory.
             src = src.rfile()
-            if src.abspath != self.abspath and src.exists():
-                self.do_duplicate(src)
+            if src.abspath != self.abspath:
+                if src.exists():
+                    self.do_duplicate(src)
+                    # Can't return 1 here because the duplication might
+                    # not actually occur if the -n option is being used.
+                else:
+                    # The source file does not exist.  Make sure no old
+                    # copy remains in the build directory.
+                    if Base.exists(self) or self.islink():
+                        self.fs.unlink(self.path)
+                    # Return None explicitly because the Base.exists() call
+                    # above will have cached its value if the file existed.
+                    return None
         return Base.exists(self)
 
+    #
+    # SIGNATURE SUBSYSTEM
+    #
+
     def new_binfo(self):
-        return BuildInfo()
+        return BuildInfo(self)
 
-    def del_cinfo(self):
-        try:
-            del self.binfo.csig
-        except AttributeError:
-            pass
-        try:
-            del self.binfo.timestamp
-        except AttributeError:
-            pass
+    def new_ninfo(self):
+        ninfo = NodeInfo()
+        ninfo.update(self)
+        return ninfo
 
-    def calc_csig(self, calc=None):
+    def get_csig(self, calc=None):
         """
         Generate a node's content signature, the digested signature
         of its content.
@@ -1777,45 +1907,43 @@ class File(Base):
         cache - alternate node to use for the signature cache
         returns - the content signature
         """
-        if calc is None:
-            calc = self.calculator()
-
         try:
-            return self.binfo.csig
+            return self.binfo.ninfo.csig
         except AttributeError:
             pass
-        
-        if calc.max_drift >= 0:
-            old = self.get_stored_info()
-        else:
-            old = BuildInfo()
 
-        try:
-            mtime = self.get_timestamp()
-        except OSError:
-            mtime = 0
-            raise SCons.Errors.UserError, "no such %s" % self
+        if calc is None:
+            calc = self.calculator()
 
-        try:
-            if (old.timestamp and old.csig and old.timestamp == mtime):
-                # use the signature stored in the .sconsign file
-                csig = old.csig
-            else:
-                csig = calc.module.signature(self)
-        except AttributeError:
-            csig = calc.module.signature(self)
+        max_drift = self.fs.max_drift
+        mtime = self.get_timestamp()
+        use_stored = max_drift >= 0 and (time.time() - mtime) > max_drift
 
-        if calc.max_drift >= 0 and (time.time() - mtime) > calc.max_drift:
+        csig = None
+        if use_stored:
+            old = self.get_stored_info().ninfo
             try:
-                binfo = self.binfo
+                if old.timestamp and old.csig and old.timestamp == mtime:
+                    csig = old.csig
             except AttributeError:
-                binfo = self.binfo = self.new_binfo()
-            binfo.csig = csig
-            binfo.timestamp = mtime
+                pass
+        if csig is None:
+            csig = calc.module.signature(self)
+
+        binfo = self.get_binfo()
+        ninfo = binfo.ninfo
+        ninfo.csig = csig
+        ninfo.update(self)
+
+        if use_stored:
             self.store_info(binfo)
 
         return csig
 
+    #
+    #
+    #
+
     def current(self, calc=None):
         self.binfo = self.gen_binfo(calc)
         return self._cur2()
@@ -1829,27 +1957,32 @@ class File(Base):
             if r != self:
                 # ...but there is one in a Repository...
                 old = r.get_stored_info()
-                if old == self.binfo:
+                new = self.get_binfo()
+                if new == old:
                     # ...and it's even up-to-date...
                     if self._local:
                         # ...and they'd like a local copy.
                         LocalCopy(self, r, None)
-                        self.store_info(self.binfo)
+                        self.store_info(new)
                     return 1
             return None
         else:
             old = self.get_stored_info()
-            return (old == self.binfo)
+            new = self.get_binfo()
+            return (new == old)
 
     def rfile(self):
         "__cacheable__"
-        rfile = self
         if not self.exists():
-            n = self.fs.Rsearch(self.path, clazz=File,
-                                cwd=self.fs.Top)
-            if n:
-                rfile = n
-        return rfile
+            norm_name = _my_normcase(self.name)
+            for dir in self.dir.get_all_rdirs():
+                try: node = dir.entries[norm_name]
+                except KeyError: node = dir.file_on_disk(self.name)
+                if node and node.exists() and \
+                   (isinstance(node, File) or isinstance(node, Entry) \
+                    or not node.is_derived()):
+                        return node
+        return self
 
     def rstr(self):
         return str(self.rfile())
@@ -1857,12 +1990,15 @@ class File(Base):
     def cachepath(self):
         if not self.fs.CachePath:
             return None, None
-        if self.binfo.bsig is None:
+        ninfo = self.get_binfo().ninfo
+        if not hasattr(ninfo, 'bsig'):
+            raise SCons.Errors.InternalError, "cachepath(%s) found no bsig" % self.path
+        elif ninfo.bsig is None:
             raise SCons.Errors.InternalError, "cachepath(%s) found a bsig of None" % self.path
         # Add the path to the cache signature, because multiple
         # targets built by the same action will all have the same
         # build signature, and we have to differentiate them somehow.
-        cache_sig = SCons.Sig.MD5.collect([self.binfo.bsig, self.path])
+        cache_sig = SCons.Sig.MD5.collect([ninfo.bsig, self.path])
         subdir = string.upper(cache_sig[0])
         dir = os.path.join(self.fs.CachePath, subdir)
         return dir, os.path.join(dir, cache_sig)
@@ -1875,7 +2011,7 @@ class File(Base):
         File, this is a TypeError..."""
         raise TypeError, "Tried to lookup File '%s' as a Dir." % self.path
 
-default_fs = FS()
+default_fs = None
 
 def find_file(filename, paths, verbose=None):
     """
index adef880dca12b83715bc37f9174b319f3c5588fe..565384f7e2727019847ae037767de48f7c9af319 100644 (file)
@@ -307,6 +307,7 @@ class BuildDirTestCase(unittest.TestCase):
         try:
             dir_made = []
             d9.builder = Builder(fs.Dir, action=MkdirAction(dir_made))
+            d9.reset_executor()
             f9.exists()
             expect = os.path.join('build', 'var2', 'new_dir')
             assert dir_made[0].path == expect, dir_made[0].path
@@ -379,13 +380,10 @@ class BuildDirTestCase(unittest.TestCase):
         assert (stat.S_IMODE(st[stat.ST_MODE]) & stat.S_IWRITE), \
                stat.S_IMODE(st[stat.ST_MODE])
 
-        exc_caught = 0
-        try:
-            fs = SCons.Node.FS.FS()
-            fs.BuildDir('build', '/test/foo')
-        except SCons.Errors.UserError:
-            exc_caught = 1
-        assert exc_caught, "Should have caught a UserError."
+        # This used to generate a UserError when we forbid the source
+        # directory from being outside the top-level SConstruct dir.
+        fs = SCons.Node.FS.FS()
+        fs.BuildDir('build', '/test/foo')
 
         exc_caught = 0
         try:
@@ -605,15 +603,170 @@ class BuildDirTestCase(unittest.TestCase):
 
         self.failIf(errors)
 
-class FSTestCase(unittest.TestCase):
-    def runTest(self):
+class BaseTestCase(_tempdirTestCase):
+    def test_stat(self):
+        """Test the Base.stat() method"""
+        test = self.test
+        test.write("e1", "e1\n")
+        fs = SCons.Node.FS.FS()
+
+        e1 = fs.Entry('e1')
+        s = e1.stat()
+        assert not s is None, s
+
+        e2 = fs.Entry('e2')
+        s = e2.stat()
+        assert s is None, s
+
+    def test_getmtime(self):
+        """Test the Base.getmtime() method"""
+        test = self.test
+        test.write("file", "file\n")
+        fs = SCons.Node.FS.FS()
+
+        file = fs.Entry('file')
+        assert file.getmtime()
+
+        file = fs.Entry('nonexistent')
+        mtime = file.getmtime()
+        assert mtime is None, mtime
+
+    def test_getsize(self):
+        """Test the Base.getsize() method"""
+        test = self.test
+        test.write("file", "file\n")
+        fs = SCons.Node.FS.FS()
+
+        file = fs.Entry('file')
+        size = file.getsize()
+        assert size == 5, size
+
+        file = fs.Entry('nonexistent')
+        size = file.getsize()
+        assert size is None, size
+
+    def test_isdir(self):
+        """Test the Base.isdir() method"""
+        test = self.test
+        test.subdir('dir')
+        test.write("file", "file\n")
+        fs = SCons.Node.FS.FS()
+
+        dir = fs.Entry('dir')
+        assert dir.isdir()
+
+        file = fs.Entry('file')
+        assert not file.isdir()
+
+        nonexistent = fs.Entry('nonexistent')
+        assert not nonexistent.isdir()
+
+    def test_isfile(self):
+        """Test the Base.isfile() method"""
+        test = self.test
+        test.subdir('dir')
+        test.write("file", "file\n")
+        fs = SCons.Node.FS.FS()
+
+        dir = fs.Entry('dir')
+        assert not dir.isfile()
+
+        file = fs.Entry('file')
+        assert file.isfile()
+
+        nonexistent = fs.Entry('nonexistent')
+        assert not nonexistent.isfile()
+
+    if hasattr(os, 'symlink'):
+        def test_islink(self):
+            """Test the Base.islink() method"""
+            test = self.test
+            test.subdir('dir')
+            test.write("file", "file\n")
+            test.symlink("symlink", "symlink")
+            fs = SCons.Node.FS.FS()
+
+            dir = fs.Entry('dir')
+            assert not dir.islink()
+
+            file = fs.Entry('file')
+            assert not file.islink()
+
+            symlink = fs.Entry('symlink')
+            assert symlink.islink()
+
+            nonexistent = fs.Entry('nonexistent')
+            assert not nonexistent.islink()
+
+class NodeInfoTestCase(_tempdirTestCase):
+    def test___init__(self):
+        """Test NodeInfo initialization"""
+        ni = SCons.Node.FS.NodeInfo()
+        assert not hasattr(ni, 'bsig')
+
+    def test___cmp__(self):
+        """Test comparing NodeInfo objects"""
+        ni1 = SCons.Node.FS.NodeInfo()
+        ni2 = SCons.Node.FS.NodeInfo()
+
+        msg = "cmp(%s, %s) returned %s, not %s"
+
+        c = cmp(ni1, ni2)
+        assert c == 1, msg % (ni1, ni2, c, 1)
+
+        ni1.bsig = 777
+        c = cmp(ni1, ni2)
+        assert c == 1, msg % (ni1.bsig, ni2, c, 1)
+
+        ni2.bsig = 666
+        c = cmp(ni1, ni2)
+        assert c == 1, msg % (ni1.bsig, ni2.bsig, c, 1)
+
+        ni2.bsig = 777
+        c = cmp(ni1, ni2)
+        assert c == 0, msg % (ni1.bsig, ni2.bsig, c, 0)
+
+        ni2.bsig = 888
+        c = cmp(ni1, ni2)
+        assert c == -1, msg % (ni1.bsig, ni2.bsig, c, -1)
+
+    def test_update(self):
+        """Test updating a NodeInfo with on-disk information"""
+        test = self.test
+        test.write('fff', "fff\n")
+        fff = self.fs.File('fff')
+
+        ni = SCons.Node.FS.NodeInfo()
+        assert not hasattr(ni, 'timestamp')
+        assert not hasattr(ni, 'size')
+
+        ni.update(fff)
+        assert ni.timestamp == os.path.getmtime('fff'), ni.timestamp
+        assert ni.size == os.path.getsize('fff'), ni.size
+
+class BuildInfoTestCase(_tempdirTestCase):
+    def test___init__(self):
+        """Test BuildInfo initialization"""
+        fff = self.fs.File('fff')
+        bi = SCons.Node.FS.BuildInfo(fff)
+        assert bi.node is fff, bi.node
+
+    def test_convert_to_sconsign(self):
+        """Test converting to .sconsign file format"""
+
+    def test_convert_from_sconsign(self):
+        """Test converting from .sconsign file format"""
+
+class FSTestCase(_tempdirTestCase):
+    def test_runTest(self):
         """Test FS (file system) Node operations
 
         This test case handles all of the file system node
         tests in one environment, so we don't have to set up a
         complicated directory structure for each test individually.
         """
-        test = TestCmd(workdir = '')
+        test = self.test
+
         test.subdir('sub', ['sub', 'dir'])
 
         wp = test.workpath('')
@@ -817,6 +970,7 @@ class FSTestCase(unittest.TestCase):
         assert not built_it
         d1.add_source([SCons.Node.Node()])    # XXX FAKE SUBCLASS ATTRIBUTE
         d1.builder_set(Builder(fs.File))
+        d1.reset_executor()
         d1.env_set(Environment())
         d1.build()
         assert built_it
@@ -825,6 +979,7 @@ class FSTestCase(unittest.TestCase):
         assert not built_it
         f1.add_source([SCons.Node.Node()])    # XXX FAKE SUBCLASS ATTRIBUTE
         f1.builder_set(Builder(fs.File))
+        f1.reset_executor()
         f1.env_set(Environment())
         f1.build()
         assert built_it
@@ -971,7 +1126,7 @@ class FSTestCase(unittest.TestCase):
         # the reading of files in text mode.  This tests that
         # get_contents() returns the binary contents.
         test.write("binary_file", "Foo\x1aBar")
-        f1 = SCons.Node.FS.default_fs.File(test.workpath("binary_file"))
+        f1 = fs.File(test.workpath("binary_file"))
         assert f1.get_contents() == "Foo\x1aBar", f1.get_contents()
 
         def nonexistent(method, s):
@@ -1184,8 +1339,112 @@ class FSTestCase(unittest.TestCase):
         t = z.target_from_source('pre-', '-suf', lambda x: x[:-1])
         assert str(t) == 'pre-z-suf', str(t)
 
+    def test_same_name(self):
+        """Test that a local same-named file isn't found for # Dir lookup"""
+        test = self.test
+        fs = self.fs
+
+        test.subdir('subdir')
+        test.write(['subdir', 'build'], "subdir/build\n")
+
+        subdir = fs.Dir('subdir')
+        fs.chdir(subdir, change_os_dir=1)
+        path, dir = fs._transformPath('#build/file', subdir)
+        self.fs._doLookup(SCons.Node.FS.File, path, dir)
+
+    def test_above_root(self):
+        """Testing looking up a path above the root directory"""
+        test = self.test
+        fs = self.fs
+
+        d1 = fs.Dir('d1')
+        d2 = d1.Dir('d2')
+        dirs = string.split(os.path.normpath(d2.abspath), os.sep)
+        above_path = apply(os.path.join, ['..']*len(dirs) + ['above'])
+        above = d2.Dir(above_path)
+
+    def test_rel_path(self):
+        """Test the rel_path() method"""
+        test = self.test
+        fs = self.fs
+
+        d1 = fs.Dir('d1')
+        d1_f = d1.File('f')
+        d1_d2 = d1.Dir('d2')
+        d1_d2_f = d1_d2.File('f')
+
+        d3 = fs.Dir('d3')
+        d3_f = d3.File('f')
+        d3_d4 = d3.Dir('d4')
+        d3_d4_f = d3_d4.File('f')
+
+        cases = [
+                d1,             d1,             '.',
+                d1,             d1_f,           'f',
+                d1,             d1_d2,          'd2',
+                d1,             d1_d2_f,        'd2/f',
+                d1,             d3,             '../d3',
+                d1,             d3_f,           '../d3/f',
+                d1,             d3_d4,          '../d3/d4',
+                d1,             d3_d4_f,        '../d3/d4/f',
+
+                d1_f,           d1,             '.',
+                d1_f,           d1_f,           'f',
+                d1_f,           d1_d2,          'd2',
+                d1_f,           d1_d2_f,        'd2/f',
+                d1_f,           d3,             '../d3',
+                d1_f,           d3_f,           '../d3/f',
+                d1_f,           d3_d4,          '../d3/d4',
+                d1_f,           d3_d4_f,        '../d3/d4/f',
+
+                d1_d2,          d1,             '..',
+                d1_d2,          d1_f,           '../f',
+                d1_d2,          d1_d2,          '.',
+                d1_d2,          d1_d2_f,        'f',
+                d1_d2,          d3,             '../../d3',
+                d1_d2,          d3_f,           '../../d3/f',
+                d1_d2,          d3_d4,          '../../d3/d4',
+                d1_d2,          d3_d4_f,        '../../d3/d4/f',
+
+                d1_d2_f,        d1,             '..',
+                d1_d2_f,        d1_f,           '../f',
+                d1_d2_f,        d1_d2,          '.',
+                d1_d2_f,        d1_d2_f,        'f',
+                d1_d2_f,        d3,             '../../d3',
+                d1_d2_f,        d3_f,           '../../d3/f',
+                d1_d2_f,        d3_d4,          '../../d3/d4',
+                d1_d2_f,        d3_d4_f,        '../../d3/d4/f',
+        ]
+
+        d1.rel_path(d3)
+
+        failed = 0
+        while cases:
+            dir, other, expect = cases[:3]
+            expect = os.path.normpath(expect)
+            del cases[:3]
+            result = dir.rel_path(other)
+            if result != expect:
+                if failed == 0: print
+                fmt = "    dir_path(%(dir)s, %(other)s) => '%(result)s' did not match '%(expect)s'"
+                print fmt % locals()
+                failed = failed + 1
+        assert failed == 0, "%d rel_path() cases failed" % failed
+
 class DirTestCase(_tempdirTestCase):
 
+    def test__morph(self):
+        """Test handling of actions when morphing an Entry into a Dir"""
+        test = self.test
+        e = self.fs.Entry('eee')
+        x = e.get_executor()
+        x.add_pre_action('pre')
+        x.add_post_action('post')
+        e.must_be_a_Dir()
+        a = x.get_action_list()
+        assert a[0] == 'pre', a
+        assert a[2] == 'post', a
+
     def test_entry_exists_on_disk(self):
         """Test the Dir.entry_exists_on_disk() method
         """
@@ -1196,11 +1455,15 @@ class DirTestCase(_tempdirTestCase):
 
         test.subdir('d')
         test.write(['d', 'exists'], "d/exists\n")
+        test.write(['d', 'Case-Insensitive'], "d/Case-Insensitive\n")
 
         d = self.fs.Dir('d')
         assert d.entry_exists_on_disk('exists')
         assert not d.entry_exists_on_disk('does_not_exist')
 
+        if os.path.normcase("TeSt") != os.path.normpath("TeSt") or sys.platform == "cygwin":
+            assert d.entry_exists_on_disk('case-insensitive')
+
     def test_srcdir_list(self):
         """Test the Dir.srcdir_list() method
         """
@@ -1266,11 +1529,11 @@ class DirTestCase(_tempdirTestCase):
         src0 = self.fs.Dir('src0')
         self.fs.BuildDir(bld0, src0, duplicate=0)
 
-        n = bld0.srcdir_duplicate('does_not_exist', SCons.Node.FS.File)
+        n = bld0.srcdir_duplicate('does_not_exist')
         assert n is None, n
         assert not os.path.exists(test.workpath('bld0', 'does_not_exist'))
 
-        n = bld0.srcdir_duplicate('exists', SCons.Node.FS.File)
+        n = bld0.srcdir_duplicate('exists')
         assert str(n) == os.path.normpath('src0/exists'), str(n)
         assert not os.path.exists(test.workpath('bld0', 'exists'))
 
@@ -1281,11 +1544,11 @@ class DirTestCase(_tempdirTestCase):
         src1 = self.fs.Dir('src1')
         self.fs.BuildDir(bld1, src1, duplicate=1)
 
-        n = bld1.srcdir_duplicate('does_not_exist', SCons.Node.FS.File)
+        n = bld1.srcdir_duplicate('does_not_exist')
         assert n is None, n
         assert not os.path.exists(test.workpath('bld1', 'does_not_exist'))
 
-        n = bld1.srcdir_duplicate('exists', SCons.Node.FS.File)
+        n = bld1.srcdir_duplicate('exists')
         assert str(n) == os.path.normpath('bld1/exists'), str(n)
         assert os.path.exists(test.workpath('bld1', 'exists'))
 
@@ -1321,7 +1584,7 @@ class DirTestCase(_tempdirTestCase):
         exists_e.exists = return_true
 
         def check(result, expect):
-           result = map(str, result)
+            result = map(str, result)
             expect = map(os.path.normpath, expect)
             assert result == expect, result
 
@@ -1437,8 +1700,38 @@ class DirTestCase(_tempdirTestCase):
         n = bld1.srcdir_find_file('on-disk-e2')
         check(n, ['bld1/on-disk-e2', 'bld1'])
 
-class EntryTestCase(unittest.TestCase):
-    def runTest(self):
+    def test_dir_on_disk(self):
+        """Test the Dir.dir_on_disk() method"""
+        self.test.subdir('sub', ['sub', 'exists'])
+        self.test.write(['sub', 'file'], "self/file\n")
+        sub = self.fs.Dir('sub')
+
+        r = sub.dir_on_disk('does_not_exist')
+        assert not r, r
+
+        r = sub.dir_on_disk('exists')
+        assert r, r
+
+        r = sub.dir_on_disk('file')
+        assert not r, r
+
+    def test_file_on_disk(self):
+        """Test the Dir.file_on_disk() method"""
+        self.test.subdir('sub', ['sub', 'dir'])
+        self.test.write(['sub', 'exists'], "self/exists\n")
+        sub = self.fs.Dir('sub')
+
+        r = sub.file_on_disk('does_not_exist')
+        assert not r, r
+
+        r = sub.file_on_disk('exists')
+        assert r, r
+
+        r = sub.file_on_disk('dir')
+        assert not r, r
+
+class EntryTestCase(_tempdirTestCase):
+    def test_runTest(self):
         """Test methods specific to the Entry sub-class.
         """
         test = TestCmd(workdir='')
@@ -1527,6 +1820,57 @@ class EntryTestCase(unittest.TestCase):
         # Doesn't exist, no sources, and no builder: no sig
         assert sig is None, sig
 
+    def test_Entry_Entry_lookup(self):
+        """Test looking up an Entry within another Entry"""
+        self.fs.Entry('#topdir')
+        self.fs.Entry('#topdir/a/b/c')
+
+
+
+class FileTestCase(_tempdirTestCase):
+
+    def test_Dirs(self):
+        """Test the File.Dirs() method"""
+        fff = self.fs.File('subdir/fff')
+        # This simulates that the SConscript file that defined
+        # fff is in subdir/.
+        fff.cwd = self.fs.Dir('subdir')
+        d1 = self.fs.Dir('subdir/d1')
+        d2 = self.fs.Dir('subdir/d2')
+        dirs = fff.Dirs(['d1', 'd2'])
+        assert dirs == [d1, d2], map(str, dirs)
+
+    def test_exists(self):
+        """Test the File.exists() method"""
+        fs = self.fs
+        test = self.test
+
+        src_f1 = fs.File('src/f1')
+        assert not src_f1.exists(), "%s apparently exists?" % src_f1
+
+        test.subdir('src')
+        test.write(['src', 'f1'], "src/f1\n")
+
+        assert not src_f1.exists(), "%s did not cache previous exists() value" % src_f1
+        src_f1.clear()
+        assert src_f1.exists(), "%s apparently does not exist?" % src_f1
+
+        test.subdir('build')
+        fs.BuildDir('build', 'src')
+        build_f1 = fs.File('build/f1')
+
+        assert build_f1.exists(), "%s did not realize that %s exists" % (build_f1, src_f1)
+        assert os.path.exists(build_f1.abspath), "%s did not get duplicated on disk" % build_f1.abspath
+
+        test.unlink(['src', 'f1'])
+        src_f1.clear()  # so the next exists() call will look on disk again
+
+        assert build_f1.exists(), "%s did not cache previous exists() value" % build_f1
+        build_f1.clear()
+        build_f1.linked = None
+        assert not build_f1.exists(), "%s did not realize that %s disappeared" % (build_f1, src_f1)
+        assert not os.path.exists(build_f1.abspath), "%s did not get removed after %s was removed" % (build_f1, src_f1)
+
 
 
 class RepositoryTestCase(_tempdirTestCase):
@@ -1566,6 +1910,28 @@ class RepositoryTestCase(_tempdirTestCase):
         r = map(lambda x, np=os.path.normpath: np(str(x)), rep)
         assert r == expect, r
 
+    def test_get_all_rdirs(self):
+        """Test the Dir.get_all_rdirs() method"""
+        self.fs.Repository('foo')
+        self.fs.Repository(os.path.join('foo', 'bar'))
+        self.fs.Repository('bar/foo')
+        self.fs.Repository('bar')
+
+        expect = [
+            '.',
+            self.rep1,
+            self.rep2,
+            self.rep3,
+            'foo',
+            os.path.join('foo', 'bar'),
+            os.path.join('bar', 'foo'),
+            'bar'
+        ]
+
+        rep = self.fs.Dir('#').get_all_rdirs()
+        r = map(lambda x, np=os.path.normpath: np(str(x)), rep)
+        assert r == expect, r
+
     def test_rdir(self):
         """Test the Dir.rdir() method"""
         return_true = lambda: 1
@@ -1660,95 +2026,42 @@ class RepositoryTestCase(_tempdirTestCase):
         r = e2.rfile()
         assert r is re2, r
 
-    def test_Rsearches(self):
-        """Test the Rsearch() methods"""
+    def test_Rfindalldirs(self):
+        """Test the Rfindalldirs() methods"""
         fs = self.fs
         test = self.test
 
-        test.write([self.rep1, 'f2'], "")
-        test.subdir([self.rep2, 'f3'])
-        test.write([self.rep3, 'f3'], "")
-
-        r = fs.Rsearch('f1')
-        assert r is None, r
-
-        r = fs.Rsearch('f2')
-        assert r, r
-
-        f3 = fs.File('f3')
-        r = fs.Rsearch(f3)
-        assert r is f3, r
-
-    def test_Rsearchall(self):
-        """Test the Rsearchall() methods"""
-        fs = self.fs
-        test = self.test
-
-        list = fs.Rsearchall(fs.Dir('d1'))
-        assert len(list) == 1, list
-        assert list[0].path == 'd1', list[0].path
-
-        list = fs.Rsearchall([fs.Dir('d1')])
-        assert len(list) == 1, list
-        assert list[0].path == 'd1', list[0].path
-
-        list = fs.Rsearchall('d2')
-        assert list == [], list
-
-        list = fs.Rsearchall('#d2')
-        assert list == [], list
-
-        fs.File('d2').built() # Clear exists cache
-        test.subdir(['work', 'd2'])
-
-        list = fs.Rsearchall('d2')
-        assert map(str, list) == ['d2'], list
-
-        fs.File('../rep2/d2').built() # Clear exists cache
-        test.subdir(['rep2', 'd2'])
-
-        list = fs.Rsearchall('d2')
-        assert map(str, list) == ['d2', test.workpath('rep2', 'd2')], list
-
-        fs.File('../rep1/d2').built() # Clear exists cache
-        test.subdir(['rep1', 'd2'])
-
-        list = fs.Rsearchall('d2')
-        assert map(str, list) == ['d2',
-                                  test.workpath('rep1', 'd2'),
-                                  test.workpath('rep2', 'd2')], list
-
-        list = fs.Rsearchall(['d3', 'd4'])
-        assert list == [], list
-
-        fs.File('d3').built() # Clear exists cache
-        test.subdir(['work', 'd3'])
-
-        list = map(str, fs.Rsearchall(['d3', 'd4']))
-        assert list == ['d3'], list
-
-        fs.File('../rep3/d4').built() # Clear exists cache
-        test.subdir(['rep3', 'd4'])
+        d1 = fs.Dir('d1')
+        d2 = fs.Dir('d2')
+        rep1_d1 = fs.Dir(test.workpath('rep1', 'd1'))
+        rep2_d1 = fs.Dir(test.workpath('rep2', 'd1'))
+        rep3_d1 = fs.Dir(test.workpath('rep3', 'd1'))
+        sub = fs.Dir('sub')
+        sub_d1 = sub.Dir('d1')
+        rep1_sub_d1 = fs.Dir(test.workpath('rep1', 'sub', 'd1'))
+        rep2_sub_d1 = fs.Dir(test.workpath('rep2', 'sub', 'd1'))
+        rep3_sub_d1 = fs.Dir(test.workpath('rep3', 'sub', 'd1'))
 
-        list = map(str, fs.Rsearchall(['d3', 'd4']))
-        assert list == ['d3', test.workpath('rep3', 'd4')], list
+        r = fs.Rfindalldirs(d1, fs.Top)
+        assert r == [d1], map(str, r)
 
-        list = map(str, fs.Rsearchall(string.join(['d3', 'd4'], os.pathsep)))
-        assert list == ['d3', test.workpath('rep3', 'd4')], list
+        r = fs.Rfindalldirs([d1, d2], fs.Top)
+        assert r == [d1, d2], map(str, r)
 
-        work_d4 = fs.File(os.path.join('work', 'd4'))
+        r = fs.Rfindalldirs('d1', fs.Top)
+        assert r == [d1, rep1_d1, rep2_d1, rep3_d1], map(str, r)
 
-        list = map(str, fs.Rsearchall(['d3', work_d4]))
-        assert list == ['d3', str(work_d4)], list
+        r = fs.Rfindalldirs('#d1', fs.Top)
+        assert r == [d1, rep1_d1, rep2_d1, rep3_d1], map(str, r)
 
-        list = fs.Rsearchall('')
-        assert list == [], list
+        r = fs.Rfindalldirs('d1', sub)
+        assert r == [sub_d1, rep1_sub_d1, rep2_sub_d1, rep3_sub_d1], map(str, r)
 
-        list = fs.Rsearchall([None])
-        assert list == [], list
+        r = fs.Rfindalldirs('#d1', sub)
+        assert r == [d1, rep1_d1, rep2_d1, rep3_d1], map(str, r)
 
-        list = fs.Rsearchall([''])
-        assert list == [], list
+        r = fs.Rfindalldirs(['d1', d2], fs.Top)
+        assert r == [d1, rep1_d1, rep2_d1, rep3_d1, d2], map(str, r)
 
     def test_rexists(self):
         """Test the Entry.rexists() method"""
@@ -1756,17 +2069,17 @@ class RepositoryTestCase(_tempdirTestCase):
         test = self.test
 
         test.write([self.rep1, 'f2'], "")
+        test.write([self.rep2, "i_exist"], "\n")
+        test.write(["work", "i_exist_too"], "\n")
 
         fs.BuildDir('build', '.')
 
         f = fs.File(test.workpath("work", "i_do_not_exist"))
         assert not f.rexists()
 
-        test.write([self.rep2, "i_exist"], "\n")
         f = fs.File(test.workpath("work", "i_exist"))
         assert f.rexists()
 
-        test.write(["work", "i_exist_too"], "\n")
         f = fs.File(test.workpath("work", "i_exist_too"))
         assert f.rexists()
 
@@ -1903,7 +2216,7 @@ class StringDirTestCase(unittest.TestCase):
 
 class stored_infoTestCase(unittest.TestCase):
     def runTest(self):
-        """Test how storing build information"""
+        """Test how we store build information"""
         test = TestCmd(workdir = '')
         test.subdir('sub')
         fs = SCons.Node.FS.FS(test.workpath(''))
@@ -1911,7 +2224,8 @@ class stored_infoTestCase(unittest.TestCase):
         d = fs.Dir('sub')
         f = fs.File('file1', d)
         bi = f.get_stored_info()
-        assert bi.bsig == None, bi.bsig
+        assert bi.ninfo.timestamp == 0, bi.ninfo.timestamp
+        assert bi.ninfo.size == None, bi.ninfo.size
 
         class MySConsign:
             class Null:
@@ -2023,6 +2337,7 @@ class prepareTestCase(unittest.TestCase):
         dir_made = []
         new_dir = fs.Dir("new_dir")
         new_dir.builder = Builder(fs.Dir, action=MkdirAction(dir_made))
+        new_dir.reset_executor()
         xyz = fs.File(os.path.join("new_dir", "xyz"))
 
         xyz.set_state(SCons.Node.up_to_date)
@@ -2161,7 +2476,7 @@ class CacheDirTestCase(unittest.TestCase):
         try:
             f5 = fs.File("cd.f5")
             f5.binfo = f5.new_binfo()
-            f5.binfo.bsig = 'a_fake_bsig'
+            f5.binfo.ninfo.bsig = 'a_fake_bsig'
             cp = f5.cachepath()
             dirname = os.path.join('cache', 'A')
             filename = os.path.join(dirname, 'a_fake_bsig')
@@ -2196,7 +2511,7 @@ class CacheDirTestCase(unittest.TestCase):
             test.write(cd_f7, "cd.f7\n")
             f7 = fs.File(cd_f7)
             f7.binfo = f7.new_binfo()
-            f7.binfo.bsig = 'f7_bsig'
+            f7.binfo.ninfo.bsig = 'f7_bsig'
 
             warn_caught = 0
             try:
@@ -2531,9 +2846,7 @@ class SaveStringsTestCase(unittest.TestCase):
 
 if __name__ == "__main__":
     suite = unittest.TestSuite()
-    suite.addTest(FSTestCase())
     suite.addTest(BuildDirTestCase())
-    suite.addTest(EntryTestCase())
     suite.addTest(find_fileTestCase())
     suite.addTest(StringDirTestCase())
     suite.addTest(stored_infoTestCase())
@@ -2547,6 +2860,12 @@ if __name__ == "__main__":
     suite.addTest(SpecialAttrTestCase())
     suite.addTest(SaveStringsTestCase())
     tclasses = [
+        BaseTestCase,
+        BuildInfoTestCase,
+        EntryTestCase,
+        FileTestCase,
+        NodeInfoTestCase,
+        FSTestCase,
         DirTestCase,
         RepositoryTestCase,
     ]
index ce677815c006c83d07d3de7344e528895e422268..8c2e6ea6934a0912f25c64b27d6b5636bcdb6f8e 100644 (file)
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 import os
+import re
+import string
 import sys
 import types
 import unittest
+import UserList
 
 import SCons.Errors
 import SCons.Node
@@ -39,7 +42,27 @@ built_source =  None
 cycle_detected = None
 built_order = 0
 
-class MyAction:
+def _actionAppend(a1, a2):
+    all = []
+    for curr_a in [a1, a2]:
+        if isinstance(curr_a, MyAction):
+            all.append(curr_a)
+        elif isinstance(curr_a, MyListAction):
+            all.extend(curr_a.list)
+        elif type(curr_a) == type([1,2]):
+            all.extend(curr_a)
+        else:
+            raise 'Cannot Combine Actions'
+    return MyListAction(all)
+
+class MyActionBase:
+    def __add__(self, other):
+        return _actionAppend(self, other)
+
+    def __radd__(self, other):
+        return _actionAppend(other, self)
+
+class MyAction(MyActionBase):
     def __init__(self):
         self.order = 0
 
@@ -53,29 +76,36 @@ class MyAction:
         self.order = built_order
         return 0
 
-    def get_actions(self):
-        return [self]
-
-class MyNonGlobalAction:
-    def __init__(self):
-        self.order = 0
-        self.built_it = None
-        self.built_target =  None
-        self.built_source =  None
-
+class MyExecutor:
+    def __init__(self, env=None, targets=[], sources=[]):
+        self.env = env
+        self.targets = targets
+        self.sources = sources
+    def get_build_env(self):
+        return self.env
+    def get_build_scanner_path(self, scanner):
+        return 'executor would call %s' % scanner
+    def cleanup(self):
+        self.cleaned_up = 1
+    def scan_targets(self, scanner):
+        if not scanner:
+            return
+        d = scanner(self.targets)
+        for t in self.targets:
+            t.implicit.extend(d)
+    def scan_sources(self, scanner):
+        if not scanner:
+            return
+        d = scanner(self.sources)
+        for t in self.targets:
+            t.implicit.extend(d)
+
+class MyListAction(MyActionBase):
+    def __init__(self, list):
+        self.list = list
     def __call__(self, target, source, env, errfunc):
-        # Okay, so not ENTIRELY non-global...
-        global built_order
-        self.built_it = 1
-        self.built_target = target
-        self.built_source = source
-        self.built_args = env
-        built_order = built_order + 1
-        self.order = built_order
-        return 0
-
-    def get_actions(self):
-        return [self]
+        for A in self.list:
+            A(target, source, env, errfunc)
 
 class Environment:
     def __init__(self, **kw):
@@ -91,13 +121,23 @@ class Environment:
         return apply(Environment, (), d)
     def _update(self, dict):
         self._dict.update(dict)
+    def get_calculator(self):
+        return SCons.Sig.default_calc
+    def get_factory(self, factory):
+        return factory or MyNode
+    def get_scanner(self, scanner_key):
+        return self._dict['SCANNERS'][0]
 
 class Builder:
-    def __init__(self, is_explicit=1):
-        self.env = Environment()
+    def __init__(self, env=None, is_explicit=1):
+        if env is None: env = Environment()
+        self.env = env
         self.overrides = {}
         self.action = MyAction()
+        self.source_factory = MyNode
         self.is_explicit = is_explicit
+        self.target_scanner = None
+        self.source_scanner = None
     def targets(self, t):
         return [t]
     def get_actions(self):
@@ -139,8 +179,12 @@ class Scanner:
     def __call__(self, node):
         self.called = 1
         return node.found_includes
+    def path(self, env, dir, target=None, source=None):
+        return ()
     def select(self, node):
         return self
+    def recurse_nodes(self, nodes):
+        return nodes
 
 class MyNode(SCons.Node.Node):
     """The base Node class contains a number of do-nothing methods that
@@ -156,6 +200,116 @@ class MyNode(SCons.Node.Node):
     def get_found_includes(self, env, scanner, target):
         return scanner(self)
 
+class Calculator:
+    def __init__(self, val):
+        self.max_drift = 0
+        class M:
+            def __init__(self, val):
+                self.val = val
+            def signature(self, args):
+                return self.val
+            def collect(self, args):
+                return reduce(lambda x, y: x+y, args, self.val)
+        self.module = M(val)
+
+
+
+class NodeInfoTestCase(unittest.TestCase):
+
+    def test___cmp__(self):
+        """Test comparing NodeInfo objects"""
+        ni1 = SCons.Node.NodeInfo()
+        ni2 = SCons.Node.NodeInfo()
+
+        assert ni1 == ni2, "%s != %s" % (ni1.__dict__, ni2.__dict__)
+
+        ni1.foo = 777
+        assert ni1 != ni2, "%s == %s" % (ni1.__dict__, ni2.__dict__)
+
+        ni2.foo = 888
+        assert ni1 != ni2, "%s == %s" % (ni1.__dict__, ni2.__dict__)
+
+        ni1.foo = 888
+        assert ni1 == ni2, "%s != %s" % (ni1.__dict__, ni2.__dict__)
+
+    def test_merge(self):
+        """Test merging NodeInfo attributes"""
+        ni1 = SCons.Node.NodeInfo()
+        ni2 = SCons.Node.NodeInfo()
+
+        ni1.a1 = 1
+        ni1.a2 = 2
+
+        ni2.a2 = 222
+        ni2.a3 = 333
+
+        ni1.merge(ni2)
+        assert ni1.__dict__ == {'a1':1, 'a2':222, 'a3':333}, ni1.__dict__
+
+    def test_update(self):
+        """Test the update() method"""
+        ni = SCons.Node.NodeInfo()
+        ni.update(SCons.Node.Node())
+
+
+
+class BuildInfoTestCase(unittest.TestCase):
+
+    def test___init__(self):
+        """Test BuildInfo initialization"""
+        bi = SCons.Node.BuildInfo(SCons.Node.Node())
+        assert hasattr(bi, 'ninfo')
+
+        class MyNode(SCons.Node.Node):
+            def new_ninfo(self):
+                return 'ninfo initialization'
+        bi = SCons.Node.BuildInfo(MyNode())
+        assert bi.ninfo == 'ninfo initialization', bi.ninfo
+
+    def test___cmp__(self):
+        """Test comparing BuildInfo objects"""
+        bi1 = SCons.Node.BuildInfo(SCons.Node.Node())
+        bi2 = SCons.Node.BuildInfo(SCons.Node.Node())
+
+        assert bi1 == bi2, "%s != %s" % (bi1.__dict__, bi2.__dict__)
+
+        bi1.ninfo.foo = 777
+        assert bi1 != bi2, "%s == %s" % (bi1.__dict__, bi2.__dict__)
+
+        bi2.ninfo.foo = 888
+        assert bi1 != bi2, "%s == %s" % (bi1.__dict__, bi2.__dict__)
+
+        bi1.ninfo.foo = 888
+        assert bi1 == bi2, "%s != %s" % (bi1.__dict__, bi2.__dict__)
+
+        bi1.foo = 999
+        assert bi1 == bi2, "%s != %s" % (bi1.__dict__, bi2.__dict__)
+
+    def test_merge(self):
+        """Test merging BuildInfo attributes"""
+        bi1 = SCons.Node.BuildInfo(SCons.Node.Node())
+        bi2 = SCons.Node.BuildInfo(SCons.Node.Node())
+
+        bi1.a1 = 1
+        bi1.a2 = 2
+
+        bi2.a2 = 222
+        bi2.a3 = 333
+
+        bi1.ninfo.a4 = 4
+        bi1.ninfo.a5 = 5
+        bi2.ninfo.a5 = 555
+        bi2.ninfo.a6 = 666
+
+        bi1.merge(bi2)
+        assert bi1.a1 == 1, bi1.a1
+        assert bi1.a2 == 222, bi1.a2
+        assert bi1.a3 == 333, bi1.a3
+        assert bi1.ninfo.a4 == 4, bi1.ninfo.a4
+        assert bi1.ninfo.a5 == 555, bi1.ninfo.a5
+        assert bi1.ninfo.a6 == 666, bi1.ninfo.a6
+
+
 
 
 class NodeTestCase(unittest.TestCase):
@@ -236,36 +390,62 @@ class NodeTestCase(unittest.TestCase):
         assert built_args["on"] == 3, built_args
         assert built_args["off"] == 4, built_args
 
-        built_it = None
-        built_order = 0
-        node = MyNode("xxx")
-        node.builder_set(Builder())
-        node.env_set(Environment())
-        node.sources = ["yyy", "zzz"]
-        pre1 = MyNonGlobalAction()
-        pre2 = MyNonGlobalAction()
-        post1 = MyNonGlobalAction()
-        post2 = MyNonGlobalAction()
-        node.add_pre_action(pre1)
-        node.add_pre_action(pre2)
-        node.add_post_action(post1)
-        node.add_post_action(post2)
-        node.build()
-        assert built_it
-        assert pre1.built_it
-        assert pre2.built_it
-        assert post1.built_it
-        assert post2.built_it
-        assert pre1.order == 1, pre1.order
-        assert pre2.order == 2, pre1.order
-        # The action of the builder itself is order 3...
-        assert post1.order == 4, pre1.order
-        assert post2.order == 5, pre1.order
-
-        for act in [ pre1, pre2, post1, post2 ]:
-            assert type(act.built_target[0]) == type(MyNode("bar")), type(act.built_target[0])
-            assert str(act.built_target[0]) == "xxx", str(act.built_target[0])
-            assert act.built_source == ["yyy", "zzz"], act.built_source
+    def test_get_build_scanner_path(self):
+        """Test the get_build_scanner_path() method"""
+        n = SCons.Node.Node()
+        x = MyExecutor()
+        n.set_executor(x)
+        p = n.get_build_scanner_path('fake_scanner')
+        assert p == "executor would call fake_scanner", p
+
+    def test_get_executor(self):
+        """Test the get_executor() method"""
+        n = SCons.Node.Node()
+
+        try:
+            n.get_executor(0)
+        except AttributeError:
+            pass
+        else:
+            self.fail("did not catch expected AttributeError")
+
+        class Builder:
+            action = 'act'
+            env = 'env1'
+            overrides = {}
+
+        n = SCons.Node.Node()
+        n.builder_set(Builder())
+        x = n.get_executor()
+        assert x.env == 'env1', x.env
+
+        n = SCons.Node.Node()
+        n.builder_set(Builder())
+        n.env_set('env2')
+        x = n.get_executor()
+        assert x.env == 'env2', x.env
+
+    def test_set_executor(self):
+        """Test the set_executor() method"""
+        n = SCons.Node.Node()
+        n.set_executor(1)
+        assert n.executor == 1, n.executor
+
+    def test_executor_cleanup(self):
+        """Test letting the executor cleanup its cache"""
+        n = SCons.Node.Node()
+        x = MyExecutor()
+        n.set_executor(x)
+        n.executor_cleanup()
+        assert x.cleaned_up
+
+    def test_reset_executor(self):
+        """Test the reset_executor() method"""
+        n = SCons.Node.Node()
+        n.set_executor(1)
+        assert n.executor == 1, n.executor
+        n.reset_executor()
+        assert not hasattr(n, 'executor'), "unexpected executor attribute"
 
     def test_built(self):
         """Test the built() method"""
@@ -291,14 +471,6 @@ class NodeTestCase(unittest.TestCase):
         n = SCons.Node.Node()
         n.visited()
 
-    def test_depends_on(self):
-        """Test the depends_on() method
-        """
-        parent = SCons.Node.Node()
-        child = SCons.Node.Node()
-        parent.add_dependency([child])
-        assert parent.depends_on([child])
-
     def test_builder_set(self):
         """Test setting a Node's Builder
         """
@@ -320,11 +492,24 @@ class NodeTestCase(unittest.TestCase):
         """
         n1 = SCons.Node.Node()
         assert not n1.has_explicit_builder()
-        n1.builder_set(Builder(is_explicit=1))
+        n1.set_explicit(1)
         assert n1.has_explicit_builder()
-        n1.builder_set(Builder(is_explicit=None))
+        n1.set_explicit(None)
         assert not n1.has_explicit_builder()
 
+    def test_get_builder(self):
+        """Test the get_builder() method"""
+        n1 = SCons.Node.Node()
+        b = n1.get_builder()
+        assert b is None, b
+        b = n1.get_builder(777)
+        assert b == 777, b
+        n1.builder_set(888)
+        b = n1.get_builder()
+        assert b == 888, b
+        b = n1.get_builder(999)
+        assert b == 888, b
+
     def test_multiple_side_effect_has_builder(self):
         """Test the multiple_side_effect_has_builder() method
         """
@@ -361,6 +546,23 @@ class NodeTestCase(unittest.TestCase):
         node = SCons.Node.Node()
         assert node.current() is None
 
+    def test_children_are_up_to_date(self):
+        """Test the children_are_up_to_date() method used by subclasses
+        """
+        n1 = SCons.Node.Node()
+        n2 = SCons.Node.Node()
+
+        calc = Calculator(111)
+
+        n1.add_source(n2)
+        assert n1.children_are_up_to_date(calc), "expected up to date"
+        n2.set_state(SCons.Node.executed)
+        assert not n1.children_are_up_to_date(calc), "expected not up to date"
+        n2.set_state(SCons.Node.up_to_date)
+        assert n1.children_are_up_to_date(calc), "expected up to date"
+        n1.always_build = 1
+        assert not n1.children_are_up_to_date(calc), "expected not up to date"
+
     def test_env_set(self):
         """Test setting a Node's Environment
         """
@@ -377,85 +579,80 @@ class NodeTestCase(unittest.TestCase):
         a = node.builder.get_actions()
         assert isinstance(a[0], MyAction), a[0]
 
-    def test_calc_bsig(self):
+    def test_get_bsig(self):
         """Test generic build signature calculation
         """
-        class Calculator:
-            def __init__(self, val):
-                self.max_drift = 0
-                class M:
-                    def __init__(self, val):
-                        self.val = val
-                    def collect(self, args):
-                        return reduce(lambda x, y: x+y, args, self.val)
-                self.module = M(val)
         node = SCons.Node.Node()
-        result = node.calc_bsig(Calculator(222))
+        result = node.get_bsig(Calculator(222))
         assert result == 222, result
-        result = node.calc_bsig(Calculator(333))
+        result = node.get_bsig(Calculator(333))
         assert result == 222, result
 
-    def test_calc_csig(self):
+    def test_get_csig(self):
         """Test generic content signature calculation
         """
-        class Calculator:
-            def __init__(self, val):
-                self.max_drift = 0
-                class M:
-                    def __init__(self, val):
-                        self.val = val
-                    def signature(self, args):
-                        return self.val
-                self.module = M(val)
         node = SCons.Node.Node()
-        result = node.calc_csig(Calculator(444))
+        result = node.get_csig(Calculator(444))
         assert result == 444, result
-        result = node.calc_csig(Calculator(555))
+        result = node.get_csig(Calculator(555))
         assert result == 444, result
 
+    def test_get_binfo(self):
+        """Test fetching/creating a build information structure
+        """
+        node = SCons.Node.Node()
+
+        binfo = node.get_binfo()
+        assert isinstance(binfo, SCons.Node.BuildInfo), binfo
+
+        node.binfo = 777
+        binfo = node.get_binfo()
+        assert binfo == 777, binfo
+
     def test_gen_binfo(self):
         """Test generating a build information structure
         """
-        class Calculator:
-            def __init__(self, val):
-                self.max_drift = 0
-                class M:
-                    def __init__(self, val):
-                        self.val = val
-                    def collect(self, args):
-                        return reduce(lambda x, y: x+y, args, self.val)
-                self.module = M(val)
-
         node = SCons.Node.Node()
-        binfo = node.gen_binfo(Calculator(666))
+        d = SCons.Node.Node()
+        i = SCons.Node.Node()
+        node.depends = [d]
+        node.implicit = [i]
+        node.gen_binfo(Calculator(666))
+        binfo = node.binfo
         assert isinstance(binfo, SCons.Node.BuildInfo), binfo
         assert hasattr(binfo, 'bsources')
         assert hasattr(binfo, 'bsourcesigs')
-        assert hasattr(binfo, 'bdepends')
+        assert binfo.bdepends == [d]
         assert hasattr(binfo, 'bdependsigs')
-        assert hasattr(binfo, 'bimplicit')
+        assert binfo.bimplicit == [i]
         assert hasattr(binfo, 'bimplicitsigs')
-        assert binfo.bsig == 666, binfo.bsig
+        assert binfo.ninfo.bsig == 1998, binfo.ninfo.bsig
 
     def test_explain(self):
         """Test explaining why a Node must be rebuilt
         """
-        node = SCons.Node.Node()
+        class testNode(SCons.Node.Node):
+            def __str__(self): return 'xyzzy'
+        node = testNode()
         node.exists = lambda: None
-        node.__str__ = lambda: 'xyzzy'
+        # Can't do this with new-style classes (python bug #1066490)
+        #node.__str__ = lambda: 'xyzzy'
         result = node.explain()
         assert result == "building `xyzzy' because it doesn't exist\n", result
 
-        node = SCons.Node.Node()
+        class testNode2(SCons.Node.Node):
+            def __str__(self): return 'null_binfo'
+        node = testNode2()
         result = node.explain()
         assert result == None, result
 
-        class Null_BInfo:
-            def __init__(self):
+        def get_null_info():
+            class Null_BInfo:
                 pass
+            return Null_BInfo()
 
-        node.get_stored_info = Null_BInfo
-        node.__str__ = lambda: 'null_binfo'
+        node.get_stored_info = get_null_info
+        #see above: node.__str__ = lambda: 'null_binfo'
         result = node.explain()
         assert result == "Cannot explain why `null_binfo' is being rebuilt: No previous build information found\n", result
 
@@ -526,6 +723,8 @@ class NodeTestCase(unittest.TestCase):
 
     def test_prepare(self):
         """Test preparing a node to be built
+
+        By extension, this also tests the missing() method.
         """
         node = SCons.Node.Node()
 
@@ -682,41 +881,55 @@ class NodeTestCase(unittest.TestCase):
         assert deps == [], deps
 
         s = Scanner()
-        d = MyNode("ddd")
-        node.found_includes = [d]
+        d1 = MyNode("d1")
+        d2 = MyNode("d2")
+        node.found_includes = [d1, d2]
 
         # Simple return of the found includes
         deps = node.get_implicit_deps(env, s, target)
-        assert deps == [d], deps
+        assert deps == [d1, d2], deps
 
-        # No "recursive" attribute on scanner doesn't recurse
+        # By default, our fake scanner recurses
         e = MyNode("eee")
-        d.found_includes = [e]
+        f = MyNode("fff")
+        g = MyNode("ggg")
+        d1.found_includes = [e, f]
+        d2.found_includes = [e, f]
+        f.found_includes = [g]
         deps = node.get_implicit_deps(env, s, target)
-        assert deps == [d], map(str, deps)
+        assert deps == [d1, d2, e, f, g], map(str, deps)
 
-        # Explicit "recursive" attribute on scanner doesn't recurse
-        s.recursive = None
+        # Recursive scanning eliminates duplicates
+        e.found_includes = [f]
         deps = node.get_implicit_deps(env, s, target)
-        assert deps == [d], map(str, deps)
+        assert deps == [d1, d2, e, f, g], map(str, deps)
 
-        # Explicit "recursive" attribute on scanner which does recurse
-        s.recursive = 1
+        # Scanner method can select specific nodes to recurse
+        def no_fff(nodes):
+            return filter(lambda n: str(n)[0] != 'f', nodes)
+        s.recurse_nodes = no_fff
         deps = node.get_implicit_deps(env, s, target)
-        assert deps == [d, e], map(str, deps)
+        assert deps == [d1, d2, e, f], map(str, deps)
 
-        # Recursive scanning eliminates duplicates
-        f = MyNode("fff")
-        d.found_includes = [e, f]
-        e.found_includes = [f]
+        # Scanner method can short-circuit recursing entirely
+        s.recurse_nodes = lambda nodes: []
         deps = node.get_implicit_deps(env, s, target)
-        assert deps == [d, e, f], map(str, deps)
+        assert deps == [d1, d2], map(str, deps)
+
+    def test_get_scanner(self):
+        """Test fetching the environment scanner for a Node
+        """
+        node = SCons.Node.Node()
+        scanner = Scanner()
+        env = Environment(SCANNERS = [scanner])
+        s = node.get_scanner(env)
+        assert s == scanner, s
+        s = node.get_scanner(env, {'X':1})
+        assert s == scanner, s
 
     def test_get_source_scanner(self):
         """Test fetching the source scanner for a Node
         """
-        class Builder:
-            pass
         target = SCons.Node.Node()
         source = SCons.Node.Node()
         s = target.get_source_scanner(source)
@@ -726,32 +939,48 @@ class NodeTestCase(unittest.TestCase):
         ts2 = Scanner()
         ts3 = Scanner()
 
-        source.backup_source_scanner = ts1
-        s = target.get_source_scanner(source)
+        class Builder1(Builder):
+            def __call__(self, source):
+                r = SCons.Node.Node()
+                r.builder = self
+                return [r]
+        class Builder2(Builder1):
+            def __init__(self, scanner):
+                self.source_scanner = scanner
+
+        builder = Builder2(ts1)
+            
+        targets = builder([source])
+        s = targets[0].get_source_scanner(source)
         assert s is ts1, s
 
-        target.builder = Builder()
+        target.builder_set(Builder2(ts1))
         target.builder.source_scanner = ts2
         s = target.get_source_scanner(source)
         assert s is ts2, s
 
-        target.source_scanner = ts3
-        s = target.get_source_scanner(source)
+        builder = Builder1(env=Environment(SCANNERS = [ts3]))
+
+        targets = builder([source])
+        
+        s = targets[0].get_source_scanner(source)
         assert s is ts3, s
 
+
     def test_scan(self):
         """Test Scanner functionality
         """
+        env = Environment()
         node = MyNode("nnn")
         node.builder = Builder()
-        node.env_set(Environment())
-        s = Scanner()
+        node.env_set(env)
+        x = MyExecutor(env, [node])
 
+        s = Scanner()
         d = MyNode("ddd")
         node.found_includes = [d]
 
-        assert node.target_scanner == None, node.target_scanner
-        node.target_scanner = s
+        node.builder.target_scanner = s
         assert node.implicit is None
 
         node.scan()
@@ -783,13 +1012,14 @@ class NodeTestCase(unittest.TestCase):
         SCons.Node.implicit_deps_unchanged = None
         try:
             sn = StoredNode("eee")
-            sn._children = ['fake']
-            sn.target_scanner = s
+            sn.builder_set(Builder())
+            sn.builder.target_scanner = s
 
             sn.scan()
 
             assert sn.implicit == [], sn.implicit
-            assert not hasattr(sn, '_children'), "unexpected _children attribute"
+            assert sn.children() == [], sn.children()
+
         finally:
             SCons.Sig.default_calc = save_default_calc
             SCons.Node.implicit_cache = save_implicit_cache
@@ -864,7 +1094,7 @@ class NodeTestCase(unittest.TestCase):
         """Test setting and getting the state of a node
         """
         node = SCons.Node.Node()
-        assert node.get_state() == None
+        assert node.get_state() == SCons.Node.no_state
         node.set_state(SCons.Node.executing)
         assert node.get_state() == SCons.Node.executing
         assert SCons.Node.pending < SCons.Node.executing
@@ -999,14 +1229,17 @@ class NodeTestCase(unittest.TestCase):
         n.implicit = 'testimplicit'
         n.waiting_parents = ['foo', 'bar']
 
+        x = MyExecutor()
+        n.set_executor(x)
+
         n.clear()
 
-        assert n.get_state() is None, n.get_state()
         assert not hasattr(n, 'binfo'), n.bsig
         assert n.includes is None, n.includes
         assert n.found_includes == {}, n.found_includes
         assert n.implicit is None, n.implicit
         assert n.waiting_parents == [], n.waiting_parents
+        assert x.cleaned_up
 
     def test_get_subst_proxy(self):
         """Test the get_subst_proxy method."""
@@ -1026,12 +1259,6 @@ class NodeTestCase(unittest.TestCase):
         s = n.get_suffix()
         assert s == '', s
 
-    def test_generate_build_dict(self):
-        """Test the base Node generate_build_dict() method"""
-        n = SCons.Node.Node()
-        dict = n.generate_build_dict()
-        assert dict == {}, dict
-
     def test_postprocess(self):
         """Test calling the base Node postprocess() method"""
         n = SCons.Node.Node()
@@ -1056,9 +1283,46 @@ class NodeTestCase(unittest.TestCase):
         n1.call_for_all_waiting_parents(func)
         assert result == [n1, n2], result
 
+class NodeListTestCase(unittest.TestCase):
+    def test___str__(self):
+        """Test"""
+        n1 = MyNode("n1")
+        n2 = MyNode("n2")
+        n3 = MyNode("n3")
+        nl = SCons.Node.NodeList([n3, n2, n1])
+
+        l = [1]
+        ul = UserList.UserList([2])
+        try:
+            l.extend(ul)
+        except TypeError:
+            # An older version of Python (*cough* 1.5.2 *cough*)
+            # that doesn't allow UserList objects to extend lists.
+            pass
+        else:
+            s = str(nl)
+            assert s == "['n3', 'n2', 'n1']", s
+
+        r = repr(nl)
+        r = re.sub('at (0[xX])?[0-9a-fA-F]+', 'at 0x', r)
+        # Don't care about ancestry: just leaf value of MyNode
+        r = re.sub('<.*?\.MyNode', '<MyNode', r)
+        # New-style classes report as "object"; classic classes report
+        # as "instance"...
+        r = re.sub("object", "instance", r)
+        l = string.join(["<MyNode instance at 0x>"]*3, ", ")
+        assert r == '[%s]' % l, r
+
 
 
 if __name__ == "__main__":
-    suite = unittest.makeSuite(NodeTestCase, 'test_')
+    suite = unittest.TestSuite()
+    tclasses = [ BuildInfoTestCase,
+                 NodeInfoTestCase,
+                 NodeTestCase,
+                 NodeListTestCase ]
+    for tclass in tclasses:
+        names = unittest.getTestCaseNames(tclass, 'test_')
+        suite.addTests(map(tclass, names))
     if not unittest.TextTestRunner().run(suite).wasSuccessful():
         sys.exit(1)
index 38cff929751d8f17408859854cdbe49bcf80d6a3..e73e5f389b166912d99b8d5bec340be0a6dee994 100644 (file)
@@ -48,8 +48,10 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 import copy
 import string
+import UserList
 
 from SCons.Debug import logInstanceCreation
+import SCons.Executor
 import SCons.SConsign
 import SCons.Util
 
@@ -60,6 +62,7 @@ import SCons.Util
 # it has no builder of its own.  The canonical example is a file
 # system directory, which is only up to date if all of its children
 # were up to date.
+no_state = 0
 pending = 1
 executing = 2
 up_to_date = 3
@@ -67,7 +70,17 @@ executed = 4
 failed = 5
 stack = 6 # nodes that are in the current Taskmaster execution stack
 
-# controls whether implicit depedencies are cached:
+StateString = {
+    0 : "0",
+    1 : "pending",
+    2 : "executing",
+    3 : "up_to_date",
+    4 : "executed",
+    5 : "failed",
+    6 : "stack",
+}
+
+# controls whether implicit dependencies are cached:
 implicit_cache = 0
 
 # controls whether implicit dep changes are ignored:
@@ -82,20 +95,69 @@ def do_nothing(node): pass
 
 Annotate = do_nothing
 
-class BuildInfo:
+# Classes for signature info for Nodes.
+
+class NodeInfo:
+    """
+    A generic class for signature information for a Node.
+
+    We actually expect that modules containing Node subclasses will also
+    subclass NodeInfo, to provide their own logic for dealing with their
+    own Node-specific signature information.
+    """
+    def __init__(self):
+        """A null initializer so that subclasses have a superclass
+        initialization method to call for future use.
+        """
+        pass
     def __cmp__(self, other):
         return cmp(self.__dict__, other.__dict__)
+    def update(self, node):
+        pass
+    def merge(self, other):
+        for key, val in other.__dict__.items():
+            self.__dict__[key] = val
+
+class BuildInfo:
+    """
+    The generic build information for a Node.
+
+    This is what gets stored in a .sconsign file for each target file.
+    It contains a NodeInfo instance for this node (signature information
+    that's specific to the type of Node) and direct attributes for the
+    generic build stuff we have to track:  sources, explicit dependencies,
+    implicit dependencies, and action information.
+    """
+    def __init__(self, node):
+        self.ninfo = node.new_ninfo()
+        self.bsourcesigs = []
+        self.bdependsigs = []
+        self.bimplicitsigs = []
+        self.bactsig = None
+    def __cmp__(self, other):
+        return cmp(self.ninfo, other.ninfo)
+    def merge(self, other):
+        for key, val in other.__dict__.items():
+            try:
+                merge = self.__dict__[key].merge
+            except (AttributeError, KeyError):
+                self.__dict__[key] = val
+            else:
+                merge(val)
 
 class Node:
     """The base Node class, for entities that we know how to
     build, or use to build other Nodes.
     """
 
+    if SCons.Memoize.use_memoizer:
+        __metaclass__ = SCons.Memoize.Memoized_Metaclass
+
     class Attrs:
         pass
 
     def __init__(self):
-        if __debug__: logInstanceCreation(self, 'Node')
+        if __debug__: logInstanceCreation(self, 'Node.Node')
         # Note that we no longer explicitly initialize a self.builder
         # attribute to None here.  That's because the self.builder
         # attribute may be created on-the-fly later by a subclass (the
@@ -118,17 +180,13 @@ class Node:
         self.implicit = None    # implicit (scanned) dependencies (None means not scanned yet)
         self.waiting_parents = []
         self.wkids = None       # Kids yet to walk, when it's an array
-        self.target_scanner = None      # explicit scanner from this node's Builder
-        self.source_scanner = None
-        self.backup_source_scanner = None
 
         self.env = None
-        self.state = None
+        self.state = no_state
         self.precious = None
         self.always_build = None
         self.found_includes = {}
         self.includes = None
-        self.overrides = {}     # construction variable overrides for building this node
         self.attributes = self.Attrs() # Generic place to stick information about the Node.
         self.side_effect = 0 # true iff this node is a side effect
         self.side_effects = [] # the side effects of building this target
@@ -144,15 +202,14 @@ class Node:
     def get_suffix(self):
         return ''
 
-    def generate_build_dict(self):
-        """Return an appropriate dictionary of values for building
-        this Node."""
-        return {}
-
     def get_build_env(self):
-        """Fetch the appropriate Environment to build this node."""
-        executor = self.get_executor()
-        return executor.get_build_env()
+        """Fetch the appropriate Environment to build this node.
+        __cacheable__"""
+        return self.get_executor().get_build_env()
+
+    def get_build_scanner_path(self, scanner):
+        """Fetch the appropriate scanner path for this node."""
+        return self.get_executor().get_build_scanner_path(scanner)
 
     def set_executor(self, executor):
         """Set the action executor for this node."""
@@ -166,15 +223,35 @@ class Node:
         except AttributeError:
             if not create:
                 raise
-            import SCons.Executor
-            executor = SCons.Executor.Executor(self.builder.action,
-                                               self.builder.env,
-                                               [self.builder.overrides],
-                                               [self],
-                                               self.sources)
+            try:
+                act = self.builder.action
+            except AttributeError:
+                executor = SCons.Executor.Null(targets=[self])
+            else:
+                executor = SCons.Executor.Executor(act,
+                                                   self.env or self.builder.env,
+                                                   [self.builder.overrides],
+                                                   [self],
+                                                   self.sources)
             self.executor = executor
         return executor
 
+    def executor_cleanup(self):
+        """Let the executor clean up any cached information."""
+        try:
+            executor = self.get_executor(create=None)
+        except AttributeError:
+            pass
+        else:
+            executor.cleanup()
+
+    def reset_executor(self):
+        "Remove cached executor; forces recompute when needed."
+        try:
+            delattr(self, 'executor')
+        except AttributeError:
+            pass
+
     def retrieve_from_cache(self):
         """Try to retrieve the node's content from a cache
 
@@ -193,15 +270,15 @@ class Node:
         so only do thread safe stuff here. Do thread unsafe stuff in
         built().
         """
-        if not self.has_builder():
-            return
-        def errfunc(stat, node=self):
-            raise SCons.Errors.BuildError(node=node, errstr="Error %d" % stat)
+        def exitstatfunc(stat, node=self):
+            if stat:
+                msg = "Error %d" % stat
+                raise SCons.Errors.BuildError(node=node, errstr=msg)
         executor = self.get_executor()
-        apply(executor, (self, errfunc), kw)
+        apply(executor, (self, exitstatfunc), kw)
 
     def built(self):
-        """Called just after this node is sucessfully built."""
+        """Called just after this node is successfully built."""
 
         # Clear the implicit dependency caches of any Nodes
         # waiting for this Node to be built.
@@ -210,30 +287,27 @@ class Node:
             parent.del_binfo()
         
         try:
-            new_binfo = self.binfo
+            new = self.binfo
         except AttributeError:
             # Node arrived here without build info; apparently it
             # doesn't need it, so don't bother calculating or storing
             # it.
-            new_binfo = None
+            new = None
 
         # Reset this Node's cached state since it was just built and
         # various state has changed.
-        save_state = self.get_state()
         self.clear()
-        self.set_state(save_state)
-
-        # Had build info, so it should be stored in the signature
-        # cache.  However, if the build info included a content
-        # signature then it should be recalculated before being
-        # stored.
         
-        if new_binfo:
-            if hasattr(new_binfo, 'csig'):
-                new_binfo = self.gen_binfo()  # sets self.binfo
+        if new:
+            # It had build info, so it should be stored in the signature
+            # cache.  However, if the build info included a content
+            # signature then it must be recalculated before being stored.
+            if hasattr(new.ninfo, 'csig'):
+                self.get_csig()
             else:
-                self.binfo = new_binfo
-            self.store_info(new_binfo)
+                new.ninfo.update(self)
+                self.binfo = new
+            self.store_info(self.binfo)
 
     def add_to_waiting_parents(self, node):
         self.waiting_parents.append(node)
@@ -246,21 +320,16 @@ class Node:
     def postprocess(self):
         """Clean up anything we don't need to hang onto after we've
         been built."""
-        try:
-            executor = self.get_executor(create=None)
-        except AttributeError:
-            pass
-        else:
-            executor.cleanup()
+        self.executor_cleanup()
 
     def clear(self):
         """Completely clear a Node of all its cached state (so that it
         can be re-evaluated by interfaces that do continuous integration
         builds).
+        __reset_cache__
         """
-        self.set_state(None)
+        self.executor_cleanup()
         self.del_binfo()
-        self.del_cinfo()
         try:
             delattr(self, '_calculated_sig')
         except AttributeError:
@@ -276,15 +345,8 @@ class Node:
         without requiring a build.."""
         pass
 
-    def depends_on(self, nodes):
-        """Does this node depend on any of 'nodes'?"""
-        for node in nodes:
-            if node in self.children():
-                return 1
-
-        return 0
-
     def builder_set(self, builder):
+        "__cache_reset__"
         self.builder = builder
 
     def has_builder(self):
@@ -307,6 +369,9 @@ class Node:
             b = self.builder
         return not b is None
 
+    def set_explicit(self, is_explicit):
+        self.is_explicit = is_explicit
+
     def has_explicit_builder(self):
         """Return whether this Node has an explicit builder
 
@@ -314,7 +379,18 @@ class Node:
         non-explicit, so that it can be overridden by an explicit
         builder that the user supplies (the canonical example being
         directories)."""
-        return self.has_builder() and self.builder.is_explicit
+        try:
+            return self.is_explicit
+        except AttributeError:
+            self.is_explicit = None
+            return self.is_explicit
+
+    def get_builder(self, default_builder=None):
+        """Return the set builder, or a specified default value"""
+        try:
+            return self.builder
+        except AttributeError:
+            return default_builder
 
     multiple_side_effect_has_builder = has_builder
 
@@ -327,6 +403,7 @@ class Node:
         signatures when they are used as source files to other derived files. For
         example: source with source builders are not derived in this sense,
         and hence should not return true.
+        __cacheable__
         """
         return self.has_builder() or self.side_effect
 
@@ -343,7 +420,7 @@ class Node:
         """
         return [], None
 
-    def get_found_includes(self, env, scanner, target):
+    def get_found_includes(self, env, scanner, path):
         """Return the scanned include lines (implicit dependencies)
         found in this node.
 
@@ -353,7 +430,7 @@ class Node:
         """
         return []
 
-    def get_implicit_deps(self, env, scanner, target):
+    def get_implicit_deps(self, env, scanner, path):
         """Return a list of implicit dependencies for this node.
 
         This method exists to handle recursive invocation of the scanner
@@ -367,59 +444,57 @@ class Node:
         # for this Node.
         scanner = scanner.select(self)
 
-        try:
-            recurse = scanner.recursive
-        except AttributeError:
-            recurse = None
-
         nodes = [self]
         seen = {}
         seen[self] = 1
         deps = []
         while nodes:
-           n = nodes.pop(0)
-           d = filter(lambda x, seen=seen: not seen.has_key(x),
-                      n.get_found_includes(env, scanner, target))
-           if d:
-               deps.extend(d)
-               for n in d:
-                   seen[n] = 1
-               if recurse:
-                   nodes.extend(d)
+            n = nodes.pop(0)
+            d = filter(lambda x, seen=seen: not seen.has_key(x),
+                       n.get_found_includes(env, scanner, path))
+            if d:
+                deps.extend(d)
+                for n in d:
+                    seen[n] = 1
+                nodes.extend(scanner.recurse_nodes(d))
 
         return deps
 
-    # cache used to make implicit_factory fast.
-    implicit_factory_cache = {}
-    
-    def implicit_factory(self, path):
-        """
-        Turn a cache implicit dependency path into a node.
-        This is called so many times that doing caching
-        here is a significant performance boost.
-        """
-        try:
-            return self.implicit_factory_cache[path]
-        except KeyError:
-            n = self.builder.source_factory(path)
-            self.implicit_factory_cache[path] = n
-            return n
+    def get_scanner(self, env, kw={}):
+        return env.get_scanner(self.scanner_key())
 
     def get_source_scanner(self, node):
         """Fetch the source scanner for the specified node
 
         NOTE:  "self" is the target being built, "node" is
         the source file for which we want to fetch the scanner.
+
+        Implies self.has_builder() is true; again, expect to only be
+        called from locations where this is already verified.
+
+        This function may be called very often; it attempts to cache
+        the scanner found to improve performance.
         """
-        if self.source_scanner:
-            return self.source_scanner
+        scanner = None
         try:
             scanner = self.builder.source_scanner
-            if scanner:
-                return scanner
         except AttributeError:
             pass
-        return node.backup_source_scanner or None
+        if not scanner:
+            # The builder didn't have an explicit scanner, so go look up
+            # a scanner from env['SCANNERS'] based on the node's scanner
+            # key (usually the file extension).
+            scanner = self.get_scanner(self.get_build_env())
+        if scanner:
+            scanner = scanner.select(node)
+        return scanner
+
+    def add_to_implicit(self, deps):
+        if not hasattr(self, 'implicit') or self.implicit is None:
+            self.implicit = []
+            self.implicit_dict = {}
+            self._children_reset()
+        self._add_child(self.implicit, self.implicit_dict, deps)
 
     def scan(self):
         """Scan this node's dependents for implicit dependencies."""
@@ -439,34 +514,44 @@ class Node:
         # Here's where we implement --implicit-cache.
         if implicit_cache and not implicit_deps_changed:
             implicit = self.get_stored_implicit()
-            if implicit is not None:
-                implicit = map(self.implicit_factory, implicit)
-                self._add_child(self.implicit, self.implicit_dict, implicit)
+            if implicit:
+                factory = build_env.get_factory(self.builder.source_factory)
+                nodes = []
+                for i in implicit:
+                    try:
+                        n = factory(i)
+                    except TypeError:
+                        # The implicit dependency was cached as one type
+                        # of Node last time, but the configuration has
+                        # changed (probably) and it's a different type
+                        # this time.  Just ignore the mismatch and go
+                        # with what our current configuration says the
+                        # Node is.
+                        pass
+                    else:
+                        nodes.append(n)
+                self._add_child(self.implicit, self.implicit_dict, nodes)
                 calc = build_env.get_calculator()
-                if implicit_deps_unchanged or self.current(calc, scan=0):
+                if implicit_deps_unchanged or self.current(calc):
                     return
-                else:
-                    # one of this node's sources has changed, so
-                    # we need to recalculate the implicit deps,
-                    # and the bsig:
-                    self.implicit = []
-                    self.implicit_dict = {}
-                    self._children_reset()
-                    self.del_binfo()
-
-        for child in self.children(scan=0):
-            scanner = self.get_source_scanner(child)
-            if scanner:
-                deps = child.get_implicit_deps(build_env, scanner, self)
-                self._add_child(self.implicit, self.implicit_dict, deps)
-
-        # scan this node itself for implicit dependencies
-        deps = self.get_implicit_deps(build_env, self.target_scanner, self)
-        self._add_child(self.implicit, self.implicit_dict, deps)
+                # one of this node's sources has changed, so
+                # we need to recalculate the implicit deps,
+                # and the bsig:
+                self.implicit = []
+                self.implicit_dict = {}
+                self._children_reset()
+                self.del_binfo()
+
+        executor = self.get_executor()
 
-        # XXX See note above re: --implicit-cache.
-        #if implicit_cache:
-        #    self.store_implicit()
+        # Have the executor scan the sources.
+        executor.scan_sources(self.builder.source_scanner)
+
+        # If there's a target scanner, have the executor scan the target
+        # node itself and associated targets that might be built.
+        scanner = self.builder.target_scanner
+        if scanner:
+            executor.scan_targets(scanner)
 
     def scanner_key(self):
         return None
@@ -476,6 +561,10 @@ class Node:
             return
         self.env = env
 
+    #
+    # SIGNATURE SUBSYSTEM
+    #
+
     def calculator(self):
         import SCons.Defaults
         
@@ -485,45 +574,41 @@ class Node:
     def calc_signature(self, calc=None):
         """
         Select and calculate the appropriate build signature for a node.
+        __cacheable__
 
         self - the node
         calc - the signature calculation module
         returns - the signature
         """
-        try:
-            return self._calculated_sig
-        except AttributeError:
-            if self.is_derived():
-                import SCons.Defaults
-                
-                env = self.env or SCons.Defaults.DefaultEnvironment()
-                if env.use_build_signature():
-                    sig = self.calc_bsig(calc)
-                else:
-                    sig = self.calc_csig(calc)
-            elif not self.rexists():
-                sig = None
-            else:
-                sig = self.calc_csig(calc)
-            self._calculated_sig = sig
-            return sig
+        if self.is_derived():
+            import SCons.Defaults
+
+            env = self.env or SCons.Defaults.DefaultEnvironment()
+            if env.use_build_signature():
+                return self.get_bsig(calc)
+        elif not self.rexists():
+            return None
+        return self.get_csig(calc)
+
+    def new_ninfo(self):
+        return NodeInfo()
 
     def new_binfo(self):
-        return BuildInfo()
+        return BuildInfo(self)
 
-    def del_binfo(self):
-        """Delete the bsig from this node."""
+    def get_binfo(self):
         try:
-            delattr(self, 'binfo')
+            return self.binfo
         except AttributeError:
-            pass
+            self.binfo = self.new_binfo()
+            return self.binfo
 
-    def calc_bsig(self, calc=None):
+    def del_binfo(self):
+        """Delete the build info from this node."""
         try:
-            return self.binfo.bsig
+            delattr(self, 'binfo')
         except AttributeError:
-            self.binfo = self.gen_binfo(calc)
-            return self.binfo.bsig
+            pass
 
     def gen_binfo(self, calc=None, scan=1):
         """
@@ -538,68 +623,70 @@ class Node:
         node's children's signatures.  We expect that they're
         already built and updated by someone else, if that's
         what's wanted.
+        __cacheable__
         """
 
         if calc is None:
             calc = self.calculator()
 
-        binfo = self.new_binfo()
+        binfo = self.get_binfo()
 
         if scan:
             self.scan()
 
-        sources = self.filter_ignore(self.sources)
-        depends = self.filter_ignore(self.depends)
-        if self.implicit is None:
-            implicit = []
-        else:
-            implicit = self.filter_ignore(self.implicit)
-
+        executor = self.get_executor()
         def calc_signature(node, calc=calc):
             return node.calc_signature(calc)
-        sourcesigs = map(calc_signature, sources)
+
+        sources = executor.process_sources(None, self.ignore)
+        sourcesigs = executor.process_sources(calc_signature, self.ignore)
+
+        depends = self.depends
+        implicit = self.implicit or []
+
+        if self.ignore:
+            depends = filter(self.do_not_ignore, depends)
+            implicit = filter(self.do_not_ignore, implicit)
+
         dependsigs = map(calc_signature, depends)
         implicitsigs = map(calc_signature, implicit)
 
         sigs = sourcesigs + dependsigs + implicitsigs
 
         if self.has_builder():
-            executor = self.get_executor()
-            binfo.bact = executor.strfunction()
+            binfo.bact = str(executor)
             binfo.bactsig = calc.module.signature(executor)
             sigs.append(binfo.bactsig)
 
-        binfo.bsources = map(str, sources)
-        binfo.bdepends = map(str, depends)
-        binfo.bimplicit = map(str, implicit)
+        binfo.bsources = sources
+        binfo.bdepends = depends
+        binfo.bimplicit = implicit
 
         binfo.bsourcesigs = sourcesigs
         binfo.bdependsigs = dependsigs
         binfo.bimplicitsigs = implicitsigs
 
-        binfo.bsig = calc.module.collect(filter(None, sigs))
+        binfo.ninfo.bsig = calc.module.collect(filter(None, sigs))
 
         return binfo
 
-    def del_cinfo(self):
+    def get_bsig(self, calc=None):
+        binfo = self.get_binfo()
         try:
-            del self.binfo.csig
+            return binfo.ninfo.bsig
         except AttributeError:
-            pass
+            self.binfo = self.gen_binfo(calc)
+            return self.binfo.ninfo.bsig
 
-    def calc_csig(self, calc=None):
+    def get_csig(self, calc=None):
+        binfo = self.get_binfo()
         try:
-            binfo = self.binfo
-        except AttributeError:
-            binfo = self.binfo = self.new_binfo()
-        try:
-            return binfo.csig
+            return binfo.ninfo.csig
         except AttributeError:
             if calc is None:
                 calc = self.calculator()
-            binfo.csig = calc.module.signature(self)
-            self.store_info(binfo)
-            return binfo.csig
+            csig = binfo.ninfo.csig = calc.module.signature(self)
+            return csig
 
     def store_info(self, obj):
         """Make the build signature permanent (that is, store it in the
@@ -613,6 +700,10 @@ class Node:
         """Fetch the stored implicit dependencies"""
         return None
 
+    #
+    #
+    #
+
     def set_precious(self, precious = 1):
         """Set the Node's precious value."""
         self.precious = precious
@@ -630,18 +721,24 @@ class Node:
         """Does this node exist locally or in a repositiory?"""
         # There are no repositories by default:
         return self.exists()
+
+    def missing(self):
+        """__cacheable__"""
+        return not self.is_derived() and \
+               not self.is_pseudo_derived() and \
+               not self.linked and \
+               not self.rexists()
     
     def prepare(self):
         """Prepare for this Node to be created.
         The default implemenation checks that all children either exist
         or are derived.
         """
-        def missing(node):
-            return not node.is_derived() and \
-                   not node.is_pseudo_derived() and \
-                   not node.linked and \
-                   not node.rexists()
-        missing_sources = filter(missing, self.children())
+        l = self.depends
+        if not self.implicit is None:
+            l = l + self.implicit
+        missing_sources = self.get_executor().get_missing_sources() \
+                          + filter(lambda c: c.missing(), l)
         if missing_sources:
             desc = "Source `%s' not found, needed by target `%s'." % (missing_sources[0], self)
             raise SCons.Errors.StopError, desc
@@ -709,33 +806,15 @@ class Node:
             self.wkids.append(wkid)
 
     def _children_reset(self):
-        try:
-            delattr(self, '_children')
-        except AttributeError:
-            pass
+        "__cache_reset__"
+        # We need to let the Executor clear out any calculated
+        # bsig info that it's cached so we can re-calculate it.
+        self.executor_cleanup()
 
-    def filter_ignore(self, nodelist):
-        ignore = self.ignore
-        result = []
-        for node in nodelist:
-            if node not in ignore:
-                result.append(node)
-        return result
+    def do_not_ignore(self, node):
+        return node not in self.ignore
 
-    def children(self, scan=1):
-        """Return a list of the node's direct children, minus those
-        that are ignored by this node."""
-        if scan:
-            self.scan()
-        try:
-            return self._children
-        except AttributeError:
-            c = self.all_children(scan=0)
-            self._children = self.filter_ignore(c)
-            return self._children
-
-    def all_children(self, scan=1):
-        """Return a list of all the node's direct children."""
+    def _all_children_get(self):
         # The return list may contain duplicate Nodes, especially in
         # source trees where there are a lot of repeated #includes
         # of a tangle of .h files.  Profiling shows, however, that
@@ -753,13 +832,31 @@ class Node:
         # using dictionary keys, lose the order, and the only ordered
         # dictionary patterns I found all ended up using "not in"
         # internally anyway...)
-        if scan:
-            self.scan()
         if self.implicit is None:
             return self.sources + self.depends
         else:
             return self.sources + self.depends + self.implicit
 
+    def _children_get(self):
+        "__cacheable__"
+        children = self._all_children_get()
+        if self.ignore:
+            children = filter(self.do_not_ignore, children)
+        return children
+
+    def all_children(self, scan=1):
+        """Return a list of all the node's direct children."""
+        if scan:
+            self.scan()
+        return self._all_children_get()
+
+    def children(self, scan=1):
+        """Return a list of the node's direct children, minus those
+        that are ignored by this node."""
+        if scan:
+            self.scan()
+        return self._children_get()
+
     def set_state(self, state):
         self.state = state
 
@@ -779,6 +876,8 @@ class Node:
         rebind their current() method to this method."""
         # Allow the children to calculate their signatures.
         self.binfo = self.gen_binfo(calc)
+        if self.always_build:
+            return None
         state = 0
         for kid in self.children(None):
             s = kid.get_state()
@@ -791,16 +890,6 @@ class Node:
         the command interpreter literally."""
         return 1
 
-    def add_pre_action(self, act):
-        """Adds an Action performed on this Node only before
-        building it."""
-        self.pre_actions.append(act)
-
-    def add_post_action(self, act):
-        """Adds and Action performed on this Node only after
-        building it."""
-        self.post_actions.append(act)
-
     def render_include_tree(self):
         """
         Return a text representation, suitable for displaying to the
@@ -810,8 +899,9 @@ class Node:
             env = self.get_build_env()
             for s in self.sources:
                 scanner = self.get_source_scanner(s)
-                def f(node, env=env, scanner=scanner, target=self):
-                    return node.get_found_includes(env, scanner, target)
+                path = self.get_build_scanner_path(scanner)
+                def f(node, env=env, scanner=scanner, path=path):
+                    return node.get_found_includes(env, scanner, path)
                 return SCons.Util.render_tree(s, f, 1)
         else:
             return None
@@ -884,53 +974,63 @@ class Node:
                 result[k] = s
 
         try:
-            old_bkids = old.bsources + old.bdepends + old.bimplicit
+            osig = {}
+            dictify(osig, old.bsources, old.bsourcesigs)
+            dictify(osig, old.bdepends, old.bdependsigs)
+            dictify(osig, old.bimplicit, old.bimplicitsigs)
         except AttributeError:
             return "Cannot explain why `%s' is being rebuilt: No previous build information found\n" % self
 
-        osig = {}
-        dictify(osig, old.bsources, old.bsourcesigs)
-        dictify(osig, old.bdepends, old.bdependsigs)
-        dictify(osig, old.bimplicit, old.bimplicitsigs)
-
-        new_bsources = map(str, self.binfo.bsources)
-        new_bdepends = map(str, self.binfo.bdepends)
-        new_bimplicit = map(str, self.binfo.bimplicit)
+        new = self.get_binfo()
 
         nsig = {}
-        dictify(nsig, new_bsources, self.binfo.bsourcesigs)
-        dictify(nsig, new_bdepends, self.binfo.bdependsigs)
-        dictify(nsig, new_bimplicit, self.binfo.bimplicitsigs)
+        dictify(nsig, new.bsources, new.bsourcesigs)
+        dictify(nsig, new.bdepends, new.bdependsigs)
+        dictify(nsig, new.bimplicit, new.bimplicitsigs)
+
+        old_bkids = old.bsources + old.bdepends + old.bimplicit
+        new_bkids = new.bsources + new.bdepends + new.bimplicit
 
-        new_bkids = new_bsources + new_bdepends + new_bimplicit
-        lines = map(lambda x: "`%s' is no longer a dependency\n" % x,
-                    filter(lambda x, nk=new_bkids: not x in nk, old_bkids))
+        # The sources and dependencies we'll want to report are all stored
+        # as relative paths to this target's directory, but we want to
+        # report them relative to the top-level SConstruct directory,
+        # so we only print them after running them through this lambda
+        # to turn them into the right relative Node and then return
+        # its string.
+        stringify = lambda s, E=self.dir.Entry: str(E(s))
+
+        lines = []
+
+        removed = filter(lambda x, nk=new_bkids: not x in nk, old_bkids)
+        if removed:
+            removed = map(stringify, removed)
+            fmt = "`%s' is no longer a dependency\n"
+            lines.extend(map(lambda s, fmt=fmt: fmt % s, removed))
 
         for k in new_bkids:
             if not k in old_bkids:
-                lines.append("`%s' is a new dependency\n" % k)
+                lines.append("`%s' is a new dependency\n" % stringify(k))
             elif osig[k] != nsig[k]:
-                lines.append("`%s' changed\n" % k)
+                lines.append("`%s' changed\n" % stringify(k))
 
         if len(lines) == 0 and old_bkids != new_bkids:
             lines.append("the dependency order changed:\n" +
-                         "%sold: %s\n" % (' '*15, old_bkids) +
-                         "%snew: %s\n" % (' '*15, new_bkids))
+                         "%sold: %s\n" % (' '*15, map(stringify, old_bkids)) +
+                         "%snew: %s\n" % (' '*15, map(stringify, new_bkids)))
 
         if len(lines) == 0:
-            newact, newactsig = self.binfo.bact, self.binfo.bactsig
             def fmt_with_title(title, strlines):
                 lines = string.split(strlines, '\n')
                 sep = '\n' + ' '*(15 + len(title))
                 return ' '*15 + title + string.join(lines, sep) + '\n'
-            if old.bactsig != newactsig:
-                if old.bact == newact:
+            if old.bactsig != new.bactsig:
+                if old.bact == new.bact:
                     lines.append("the contents of the build action changed\n" +
-                                 fmt_with_title('action: ', newact))
+                                 fmt_with_title('action: ', new.bact))
                 else:
                     lines.append("the build action changed:\n" +
                                  fmt_with_title('old: ', old.bact) +
-                                 fmt_with_title('new: ', newact))
+                                 fmt_with_title('new: ', new.bact))
 
         if len(lines) == 0:
             return "rebuilding `%s' for unknown reasons\n" % self
@@ -942,6 +1042,28 @@ class Node:
             lines = ["%s:\n" % preamble] + lines
             return string.join(lines, ' '*11)
 
+l = [1]
+ul = UserList.UserList([2])
+try:
+    l.extend(ul)
+except TypeError:
+    def NodeList(l):
+        return l
+else:
+    class NodeList(UserList.UserList):
+        def __str__(self):
+            return str(map(str, self.data))
+del l
+del ul
+
+if SCons.Memoize.use_old_memoization():
+    _Base = Node
+    class Node(SCons.Memoize.Memoizer, _Base):
+        def __init__(self, *args, **kw):
+            apply(_Base.__init__, (self,)+args, kw)
+            SCons.Memoize.Memoizer.__init__(self)
+
+
 def get_children(node, parent): return node.children()
 def ignore_cycle(node, stack): pass
 def do_nothing(node, parent): pass
index a6cb720e55bdc02e304257a42b2c188a18fc4438..0cdd62bdeb324792857972f7ad8d01368c19985b 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <cvar name="ESCAPE">
 <summary>
 A function that will be called to escape shell special characters in
@@ -84,10 +89,10 @@ The suffix used for executable file names.
 
 <cvar name="SHELL">
 <summary>
-A string naming the shell program that will be passed to the 
+A string naming the shell program that will be passed to the
 &cv-SPAWN;
-function. 
-See the 
+function.
+See the
 &cv-SPAWN;
 construction variable for more information.
 </summary>
index cb05e528497f27457590b6e71b6710ff7735a55e..a1bb7fde757925baef82138d5a8e95e56037513f 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <cvar name="RPATH">
 <summary>
 A list of paths to search for shared libraries when running programs.
index c893f0c10826c5429f9583b8a7b453fef4ecc208..f284a408e92d2063f5caf9902facb3ec33d02760 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <cvar name="MAXLINELENGTH">
 <summary>
 The maximum number of characters allowed on an external command line.
index 2a9d99301b5f8e6e8fd8b3da5fa13f1a759701f0..bb36048259927856e1812f7769ab1f499962d76a 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="386asm">
 <summary>
 XXX
index 43841a026cd25196a41abac80d68382ec2dc776a..3fef72d999552f574fa0f4ce48a64b16678bebbb 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="BitKeeper">
 <summary>
 XXX
@@ -14,7 +19,7 @@ The BitKeeper executable.
 <cvar name="BITKEEPERCOM">
 <summary>
 The command line for
-fetching source files using BitKEeper.
+fetching source files using BitKeeper.
 </summary>
 </cvar>
 
index 9a072943447deed6b76a47bc831d4c0c3537cfb6..9ad5fb54a111f68110698b7697810cff65ef81e0 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="CVS">
 <summary>
 XXX
index 247330e8fe67900343b21245c233a4adb4290d47..87565af006901d42208d0c4e1e97a2a53159e2b8 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="Perforce">
 <summary>
 XXX
index 40d972f33485fc879ce36e0132a8436d439f59f0..5e3b83df06fe69467bbbb1d1e5f3d86e15cee9e3 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="RCS">
 <summary>
 XXX
index 08aa949d2e3259d6e8eb3829c915cb9d01099bfc..822547cc71ca5a9d81d8a35169e3ca8178216375 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="SCCS">
 <summary>
 XXX
index e5560d1cab69f9748efe4fa0b492f03cad7cb686..c3a4f5f22961606c3ed51236a14276fbf3579596 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="Subversion">
 <summary>
 XXX
index 86b830c1d59ebb3eb7a3173c3e24fc9784008042..0cce79ba2c9f038ff99db1e9bd734c3e9cd56790 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <builder name="CFile">
 <summary>
 Builds a C source file given a lex (<filename>.l</filename>)
@@ -6,7 +11,8 @@ or yacc (<filename>.y</filename>) input file.
 The suffix specified by the &cv-CFILESUFFIX; construction variable
 (<filename>.c</filename> by default)
 is automatically added to the target
-if it is not already present. Example:
+if it is not already present.
+Example:
 
 <example>
 # builds foo.c
@@ -25,7 +31,8 @@ input file.
 The suffix specified by the &cv-CXXFILESUFFIX; construction variable
 (<filename>.cc</filename> by default)
 is automatically added to the target
-if it is not already present. Example:
+if it is not already present.
+Example:
 
 <example>
 # builds foo.cc
@@ -44,6 +51,16 @@ builder method.
 </summary>
 </builder>
 
+<builder name="LoadableModule">
+<summary>
+On most systems,
+this is the same as
+&b-SharedLibrary;.
+On Mac OS X (Darwin) platforms,
+this creates a loadable module bundle.
+</summary>
+</builder>
+
 <builder name="Object">
 <summary>
 A synonym for the
@@ -173,7 +190,7 @@ The target object file prefix
 by default, the same as &cv-OBJPREFIX;)
 and suffix
 (specified by the &cv-SHOBJSUFFIX; construction variable)
-are automatically added to the target if not already present. 
+are automatically added to the target if not already present.
 Examples:
 
 <example>
@@ -181,6 +198,13 @@ env.SharedObject(target = 'ddd', source = 'ddd.c')
 env.SharedObject(target = 'eee.o', source = 'eee.cpp')
 env.SharedObject(target = 'fff.obj', source = 'fff.for')
 </example>
+
+Note that the source files will be scanned
+according to the suffix mappings in the
+<literal>SourceFileScanner</literal>
+object.
+See the section "Scanner Objects,"
+below, for a more information.
 </summary>
 </builder>
 
@@ -245,6 +269,8 @@ Source files must have one of the following extensions:
   .FOR    Fortran file
   .fpp    Fortran file + C pre-processor
   .FPP    Fortran file + C pre-processor
+  .m      Object C file
+  .mm     Object C++ file
   .s      assembly language file
   .S      WIN32:  assembly language file
           POSIX:  assembly language file + C pre-processor
@@ -266,6 +292,13 @@ env.StaticObject(target = 'aaa', source = 'aaa.c')
 env.StaticObject(target = 'bbb.o', source = 'bbb.c++')
 env.StaticObject(target = 'ccc.obj', source = 'ccc.f')
 </example>
+
+Note that the source files will be scanned
+according to the suffix mappings in
+<literal>SourceFileScanner</literal>
+object.
+See the section "Scanner Objects,"
+below, for a more information.
 </summary>
 </builder>
 
@@ -314,7 +347,10 @@ SCons also treats files with the suffixes
 <filename>.c++</filename>,
 and
 <filename>.C++</filename>
-as C++ files.
+as C++ files,
+and files with
+<filename>.mm</filename>
+suffixes as Objective C++ files.
 On case-sensitive systems (Linux, UNIX, and other POSIX-alikes),
 SCons also treats
 <filename>.C</filename>
index d3867794a3e7e509eba45c00e85ad40dde9a0e90..2f03aa65d1a6df88d7e6ce6b3bce1d128d59e733 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="aixc++">
 <summary>
 XXX
index cb27adb215d8c44b2af8c929a1e34a33d545e394..a7a043c5fc7fce687fa40dacc4e295bef29dbd22 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="aixcc">
 <summary>
 XXX
index 7e7988c4ca3836c9e3ba21cb94cc57c0082b3f7d..9043b66fe01f891be36f349d366a8dd42df19029 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="aixf77">
 <summary>
 XXX
index 378dcbfa6a06669d090edb2cc8a4e095105d35b1..a1aa05bfb134c007cd0ffa6902c53574177bedc6 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="aixlink">
 <summary>
 XXX
index 13eea3116994103d4167df1647e90699197904f1..b9ea63d22d1ab7145032b2b21e134e1db2c2771c 100644 (file)
@@ -1,4 +1,9 @@
-<!-- Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <cvar name="FRAMEWORKSFLAGS">">
 <summary>
 On Mac OS X with gcc,
index de3246f07bda9f4581c0995b2f057ea068b41d0c..baebd272afb6a8bab04f3bffe01ffd0b0dfa709d 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="ar">
 <summary>
 XXX
index a9395dfdfbe7a8bbc3b010891da48f5ac3df66eb..a2447bd6e07a3e80d22ad8162e5278388e5a8326 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="as">
 <summary>
 XXX
index ded614c671724e285718ebf73bf4f4aae827c598..1cdb9c0b36318788e1d5ee25f19abe9d2520501d 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="bcc32">
 <summary>
 XXX
index eaa8e6c81755900b2db49dd35a2a869014fb0c58..eb0a8fee2f25551e9ca96380598b2c77b47c970c 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="c++">
 <summary>
 XXX
index fb688adefeb68ea77cd88652928fcebb1cac0bd0..84980db1f653b2bc91db0fabd5b82fe04c15c2b5 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="cc">
 <summary>
 XXX
@@ -71,6 +76,7 @@ The default list is:
 [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
  ".h", ".H", ".hxx", ".hpp", ".hh",
  ".F", ".fpp", ".FPP",
+ ".m", ".mm",
  ".S", ".spp", ".SPP"]
 </example>
 </summary>
index bd848aed5529ee1e4df6e2a780074289dfa8c23e..9acde9b59da2462ef01cda54273b539068e1776a 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="cvf">
 <summary>
 XXX
index 371e5bc36c31f3a77267db17dc954849d30964d9..a4da87a007cb4eaefded3e3221fe50f481385cdb 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="default">
 <summary>
 XXX
index 99ca8d9afe321df07e0e339717b58994cd2b50cc..62ab78e597f8f50cf91becd02f93f748f72a2bc8 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="dmd">
 <summary>
 XXX
index fbb49333c6845059fdd3d77c7afa341e1b6953d7..4d82ffe5da84c6c1e34e4241c874e28c423d78ff 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="dvipdf">
 <summary>
 XXX
index c290469707353028d5458a8b8e6788d51b39bc66..cb0d7d87c20aa3a9234dfc7c423c83b2891e67f4 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="dvips">
 <summary>
 XXX
index caf959fd1754adf41e2c298ef2ef6b4c2b0061cb..c07717502c2712f0404d3ea8a69d842124fc9181 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="f77">
 <summary>
 XXX
index b2f08576b89593ad4f7eedcb4ca5575777bec44a..5c252cc387378863bb942be5aacfd7b2e1596822 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="f90">
 <summary>
 XXX
index df7442221f49d30226f1a33dd9d7b24a3d0d1e5c..86331a40ce4591d4302148a1b8cdd92712fa120d 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="f95">
 <summary>
 XXX
index bfc34fa7f583776526672c093172763736eecf73..c47234340271ae735e0094451b92f7defb562458 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="fortran">
 <summary>
 XXX
@@ -16,7 +21,7 @@ for all versions of Fortran.
 <summary>
 The command line used to compile a Fortran source file to an object file.
 By default, any options specified
-in the &cv-FORTRANFLAGS;, &cv-CPPFLAGS;, &cv-_CPPDEFFLAGS;, 
+in the &cv-FORTRANFLAGS;, &cv-CPPFLAGS;, &cv-_CPPDEFFLAGS;,
 &cv-_FORTRANMODFLAG;, and &cv-_FORTRANINCFLAGS; construction variables
 are included on this command line.
 </summary>
@@ -51,7 +56,7 @@ for the variables that expand those options.
 <summary>
 An automatically-generated construction variable
 containing the Fortran compiler command-line options
-for specifying directories to be searched for include 
+for specifying directories to be searched for include
 files and module files.
 The value of &cv-_FORTRANINCFLAGS; is created
 by prepending/appending &cv-INCPREFIX; and &cv-INCSUFFIX;
@@ -63,8 +68,8 @@ of each directory in &cv-FORTRANPATH;.
 <cvar name="FORTRANMODDIR">
 <summary>
 Directory location where the Fortran compiler should place
-any module files it generates.  This variable is empty, by default. Some 
-Fortran compilers will internally append this directory in the search path 
+any module files it generates.  This variable is empty, by default. Some
+Fortran compilers will internally append this directory in the search path
 for module files, as well.
 </summary>
 </cvar>
@@ -94,7 +99,7 @@ when the &cv-_FORTRANMODFLAG; variables is automatically generated.
 An automatically-generated construction variable
 containing the Fortran compiler command-line option
 for specifying the directory location where the Fortran
-compiler should place any module files that happen to get 
+compiler should place any module files that happen to get
 generated during compilation.
 The value of &cv-_FORTRANMODFLAG; is created
 by prepending/appending &cv-FORTRANMODDIRPREFIX; and &cv-FORTRANMODDIRSUFFIX;
@@ -146,7 +151,7 @@ to look-up a directory relative to the root of the source tree use #:
 env = Environment(FORTRANPATH='#/include')
 </example>
 
-The directory look-up can also be forced using the 
+The directory look-up can also be forced using the
 &Dir;()
 function:
 
@@ -178,7 +183,7 @@ env = Environment(FORTRANCOM="my_compiler $_FORTRANINCFLAGS -c -o $TARGET $SOURC
 <cvar name="FORTRANPPCOM">
 <summary>
 The command line used to compile a Fortran source file to an object file
-after first running the file through the C preprocessor. 
+after first running the file through the C preprocessor.
 By default, any options specified in the &cv-FORTRANFLAGS;, &cv-CPPFLAGS;,
 _CPPDEFFLAGS, &cv-_FORTRANMODFLAG;, and &cv-_FORTRANINCFLAGS;
 construction variables are included on this command line.
index b6fb5b071cd2b17317e23de76ccc335b8c65de5f..4991811956b40cd8046fac70ebd2c766ec45c104 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="g++">
 <summary>
 XXX
index 94f415a24cb0b2ee88056b6b7413e52f6e6ba8a5..6357f94d5fdf6f63358dc42c2e6fb50b7166b02b 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="g77">
 <summary>
 XXX
index 29179e2bac3cb5f595ebd8ab2a2496716ed452f0..19ad1a902ff0482c13848de52dd80af76e2a2e41 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="gas">
 <summary>
 XXX
index 51dac073f486a1d208064ee7651d84e88cf4c95c..15f19cf0f144e15833b14649211b46d7196bd55d 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="gcc">
 <summary>
 XXX
index d7c1a42623bc1781ef58c5aad6f502607fefa4cd..d454af445770f5cef5243c5fe093d946eac5c9f0 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="gnulink">
 <summary>
 XXX
index 377bfc34acfa835bf3ecb8cf86dc907ce8e706b7..d4840d6b13a68306c58acee6ca9729f51a4b1e4d 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="gs">
 <summary>
 XXX
index 5c13718e7d3e1aa17175859a9876e0dda97a7565..ca0314c9dbd82d69e349b6b5bdd23159ef4ccc26 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="hpc++">
 <summary>
 XXX
index db2fccd676ba604978b1073a28f784e828a97bd4..9f63b5538dde5874f50f3250b265637e9710d74e 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="hpcc">
 <summary>
 XXX
index 71f5e225cf3e36bebf78b533e09977797dc5d7bc..1bd3b78afa2b3558a1d61fd6baf9e2b9434b7b33 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="hplink">
 <summary>
 XXX
index a6fdea2d6aa1ac7e351f77a31b2bbfe7bc9e861b..c41486e6d537fb9cafec09e9dafad7dbc44e0b9e 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="icc">
 <summary>
 XXX
index be20912c695ff3959c33b054c7a78f52b1d26931..5b8c3559241cede721077d5baae63bba45fcfe0a 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="icl">
 <summary>
 XXX
index 34dfecb5201c85d7c19cda5218009c33d19d7af7..4b5b912dcf6e763eeff6e47bd15216679f4c58e4 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="ifl">
 <summary>
 XXX
index 2cb889bd36f9d8cf6c96f164eecf993161b934cc..0303dec5897813a3445189d35a1c3679f36210eb 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="ifort">
 <summary>
 XXX
index 4f868833d82a70be497de1b48b43dfa79ccfba68..03acfa4af932671be1038e06f9919e57ecb785ac 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="ilink">
 <summary>
 XXX
index 0d62be49be6380a5f478c681a3f349f0d9d83686..370d0464a05adb2bfc95eea7f946eccbd3e96280 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="ilink32">
 <summary>
 XXX
index 47cfbecb551e5a1c29d900bb751f09ffbce65b96..0141c22f89666713fa4dff384b94d5194b1e7d15 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="intelc">
 <summary>
 XXX
index b89468d9366f78bc45052b280973fbda1b399b91..45d9ebca0d98b29b4a37d070a85ff99ee34e586d 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="jar">
 <summary>
 XXX
index 9cd40b54558440fd626bf2d5dcdb4d81032ef608..86fd507d94ff3df489af982053898f32b0ba726a 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="javac">
 <summary>
 XXX
index 76997840bc4ad66809aa9a2afe15cef062703ac3..84d0068683554ffea2bdab10ca8e2f7e241dc807 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="javah">
 <summary>
 XXX
index b8b1bb34da64845162f573405eeee7fcc7cd321d..96c0f4a81aa4e164d7989ddde47d13ef95ada1a0 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="latex">
 <summary>
 XXX
index 3fb62e11a8cdc818aaadc869e46d9b82de171547..51401dcb99673b0a72d7221242ae4c3c05045ee4 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="lex">
 <summary>
 XXX
index 420a5b70774e3d8003f7dd350320ffa1265aaee6..52694adb1ba6d6b5b0b056aa3a484740b8ed0441 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="link">
 <summary>
 XXX
index 12a9d50e591448ce6004cd837cc57370d6c2e1ff..58ffc483a78ca276da87e881b3c467ba3cdb737d 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="linkloc">
 <summary>
 XXX
index 1f917703a675e96e9d214ae9041a6ca307f0aac2..7a0f9c38cbba66ea984b42d13a921e9558ebdd19 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="m4">
 <summary>
 XXX
index 82c14cfdb9e02248154c0306c3a3ddb790dabc20..ee1ed1d7d428a619b41e414faba247cefee35fac 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="masm">
 <summary>
 XXX
index 4d5c7e0f169a00489130e07adeddebf21b530e63..8885785fad7359d427f31863dc0131f012dbf2b1 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="midl">
 <summary>
 XXX
index 273a8612b6e905e931f0d8ff2fd02ea892d14506..9f9cf1f365383a60f6ced9b7f1b1d7ee939d6a43 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="mingw">
 <summary>
 XXX
index 7da4365e3b7031fd328e816fa313c717294fda41..9d56fd5c24412d13cf42d8534165964de17ddd34 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="mslib">
 <summary>
 XXX
index 82249e7f16eba1ba3e71d6cb7a6c24325bd3f335..2b901c6e5e31316aa9142c32a1f366f0419bc9c4 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="mslink">
 <summary>
 XXX
@@ -26,7 +31,8 @@ tools other than Microsoft Visual C++.
 When this variable is
 defined SCons will add options to the compiler and linker command line to
 cause them to generate external debugging information, and will also set up the
-dependencies for the PDB file. Example:
+dependencies for the PDB file.
+Example:
 
 <example>
 env['PDB'] = 'hello.pdb'
index 76529b115c8a01ccbe03ff6b18bbc985f311920a..252d9628812856b3c6d70556a732e3dd07713e31 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="msvc">
 <summary>
 XXX
@@ -12,7 +17,7 @@ Calling this builder method
 returns a list of two targets: the PCH as the first element, and the object
 file as the second element. Normally the object file is ignored.
 This builder method is only
-provided when Microsoft Visual C++ is being used as the compiler. 
+provided when Microsoft Visual C++ is being used as the compiler.
 The PCH builder method is generally used in
 conjuction with the PCH construction variable to force object files to use
 the precompiled header:
@@ -29,11 +34,12 @@ Builds a Microsoft Visual C++ resource file.
 This builder method is only provided
 when Microsoft Visual C++ or MinGW is being used as the compiler. The
 <filename>.res</filename>
-(or 
+(or
 <filename>.o</filename>
 for MinGW) suffix is added to the target name if no other suffix is given.
 The source
-file is scanned for implicit dependencies as though it were a C file. Example:
+file is scanned for implicit dependencies as though it were a C file.
+Example:
 
 <example>
 env.RES('resource.rc')
@@ -48,7 +54,8 @@ object files. This variable is ignored by tools other than Microsoft Visual C++.
 When this variable is
 defined SCons will add options to the compiler command line to
 cause it to use the precompiled header, and will also set up the
-dependencies for the PCH file. Example: 
+dependencies for the PCH file.
+Example:
 
 <example>
 env['PCH'] = 'StdAfx.pch'
index 9af096080b8bc7eed5096e6ebc054363c29f0db0..babc20f8f3b58340860f1ee9d02bfe591d703d26 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="msvs">
 <summary>
 XXX
@@ -12,7 +17,7 @@ and by default builds a solution file as well.
 
 This builds a Visual Studio project file, based on the version of
 Visual Studio that is configured (either the latest installed version,
-or the version specified by 
+or the version specified by
 &cv-MSVS_VERSION;
 in the Environment constructor).
 For Visual Studio 6, it will generate a
@@ -43,7 +48,7 @@ Builder (see below).
 
 It takes several lists of filenames to be placed into the project
 file.
-These are currently these are limited to 
+These are currently limited to
 <literal>srcs</literal>,
 <literal>incs</literal>,
 <literal>localincs</literal>,
@@ -60,7 +65,8 @@ In addition to the above lists of values (which are all optional,
 although not specifying any of them results in an empty project file),
 the following values may be specified:
 
-<literal>target</literal>: The name of the target
+<literal>target</literal>:
+The name of the target
 <filename>.dsp</filename>
 or
 <filename>.vcproj</filename>
@@ -88,7 +94,7 @@ character:
 The default target platform is Win32.
 Multiple calls to
 &b-MSVSProject;
- with different variants are allowed;
+with different variants are allowed;
 all variants will be added to the project file with their appropriate
 build targets and sources.
 
@@ -133,15 +139,15 @@ Builds a Microsoft Visual Studio solution file.
 This builds a Visual Studio solution file,
 based on the version of Visual Studio that is configured
 (either the latest installed version,
-or the version specified by 
+or the version specified by
 &cv-MSVS_VERSION;
 in the construction environment).
 For Visual Studio 6, it will generate a
-<filename>dsw</filename>
+<filename>.dsw</filename>
 file.
 For Visual Studio 7 (.NET), it will
 generate a
-<filename>sln</filename>
+<filename>.sln</filename>
 file.
 
 The following values must be specified:
@@ -185,35 +191,35 @@ local.MSVSSolution(target = 'Bar' + env['MSVSSOLUTIONSUFFIX'],
 When the Microsoft Visual Studio tools are initialized, they set up
 this dictionary with the following keys:
 
-<envar>VERSION</envar>
+<envar>VERSION</envar>:
 the version of MSVS being used (can be set via
 MSVS_VERSION)
 
-<envar>VERSIONS</envar>
+<envar>VERSIONS</envar>:
 the available versions of MSVS installed
 
-<envar>VCINSTALLDIR</envar>
+<envar>VCINSTALLDIR</envar>:
 installed directory of Visual C++
 
-<envar>VSINSTALLDIR</envar>
+<envar>VSINSTALLDIR</envar>:
 installed directory of Visual Studio
 
-<envar>FRAMEWORKDIR</envar>
+<envar>FRAMEWORKDIR</envar>:
 installed directory of the .NET framework
 
-<envar>FRAMEWORKVERSIONS</envar>
+<envar>FRAMEWORKVERSIONS</envar>:
 list of installed versions of the .NET framework, sorted latest to oldest.
 
-<envar>FRAMEWORKVERSION</envar>
+<envar>FRAMEWORKVERSION</envar>:
 latest installed version of the .NET framework
 
-<envar>FRAMEWORKSDKDIR</envar>
+<envar>FRAMEWORKSDKDIR</envar>:
 installed location of the .NET SDK.
 
-<envar>PLATFORMSDKDIR</envar>
+<envar>PLATFORMSDKDIR</envar>:
 installed location of the Platform SDK.
 
-<envar>PLATFORMSDK_MODULES</envar>
+<envar>PLATFORMSDK_MODULES</envar>:
 dictionary of installed Platform SDK modules,
 where the dictionary keys are keywords for the various modules, and
 the values are 2-tuples where the first is the release date, and the
@@ -239,18 +245,18 @@ minimal set of paths needed to run the tools successfully.
 
 For VS6, the mininimal set is:
 <example>
-   INCLUDE:'VSDir\VC98\ATL\include;VSDir\VC98\MFC\include;VSDir\VC98\include'
-   LIB:'VSDir\VC98\MFC\lib;VSDir\VC98\lib'
-   PATH:'VSDir\Common\MSDev98\bin;VSDir\VC98\bin'
+   INCLUDE:'&lt;VSDir&gt;\VC98\ATL\include;&lt;VSDir&gt;\VC98\MFC\include;&lt;VSDir&gt;\VC98\include'
+   LIB:'&lt;VSDir&gt;\VC98\MFC\lib;&lt;VSDir&gt;\VC98\lib'
+   PATH:'&lt;VSDir&gt;\Common\MSDev98\bin;&lt;VSDir&gt;\VC98\bin'
 </example>
 For VS7, it is:
 <example>
-   INCLUDE:'VSDir\Vc7\atlmfc\include;VSDir\Vc7\include'
-   LIB:'VSDir\Vc7\atlmfc\lib;VSDir\Vc7\lib'
-   PATH:'VSDir\Common7\Tools\bin;VSDir\Common7\Tools;VSDir\Vc7\bin'
+   INCLUDE:'&lt;VSDir&gt;\Vc7\atlmfc\include;&lt;VSDir&gt;\Vc7\include'
+   LIB:'&lt;VSDir&gt;\Vc7\atlmfc\lib;&lt;VSDir&gt;\Vc7\lib'
+   PATH:'&lt;VSDir&gt;\Common7\Tools\bin;&lt;VSDir&gt;\Common7\Tools;&lt;VSDir&gt;\Vc7\bin'
 </example>
 
-Where 'VSDir' is the installed location of Visual Studio.
+Where '&lt;VSDir&gt;' is the installed location of Visual Studio.
 </summary>
 </cvar>
 
@@ -260,7 +266,7 @@ The string
 placed in a generated Microsoft Visual Studio solution file
 as the value of the
 <literal>SccProjectFilePathRelativizedFromConnection0</literal>
-and 
+and
 <literal>SccProjectFilePathRelativizedFromConnection1</literal>
 attributes of the
 <literal>GlobalSection(SourceCodeControl)</literal>
@@ -385,7 +391,7 @@ directory to the default
 <envar>LIB</envar>
 external environment variable.
 The current default value is
-<literal>1</literal>
+<literal>1</literal>,
 which means these directories
 are added to the paths by default.
 This default value is likely to change
@@ -413,7 +419,7 @@ installed on your machine.
 So, if you have version 6 and version 7 (MSVS .NET) installed,
 it will prefer version 7.
 You can override this by
-specifying the 
+specifying the
 <envar>MSVS_VERSION</envar>
 variable in the Environment initialization, setting it to the
 appropriate version ('6.0' or '7.0', for example).
index 83eaab3f322cd744bc5ab6caac9cf911d19f2d99..443eda75637a5fdbcdeef3d4faba58486471e8fe 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="mwcc">
 <summary>
 XXX
index ade98488048bbda32a1f4ca00df7b84171a4ffc1..9943927eb65a9b85a1cbdf3fd4d56f4c6a0afdbc 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="mwld">
 <summary>
 XXX
index 328386e285c8f3fadb352db059d57856f01bac7a..071f5378013f7d423ab9dcd49ac7f9f484712365 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="nasm">
 <summary>
 XXX
index 78780798db1eda68d897c6db22a0af291e37303d..e9fe793ed36ffd6bfb0170e0e90a4ff760d26034 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="pdflatex">
 <summary>
 XXX
index 701a28098456f6680ff9ba863ed90282a5be837a..47e4138a298d9d340fd16fad6452a1f5da6698bc 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="pdftex">
 <summary>
 XXX
index b5335b6107936c81c1b3679991dec3983620f116..6a4ac7885b67b73adc070daa1366e59bb787f0f5 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="qt">
 <summary>
 XXX
@@ -7,8 +12,8 @@ XXX
 
 <builder name="Moc">
 <summary>
-Builds an output file from a moc input file. Moc input files are either 
-header files or cxx files. This builder is only available after using the 
+Builds an output file from a moc input file. Moc input files are either
+header files or cxx files. This builder is only available after using the
 tool 'qt'. See the &cv-QTDIR; variable for more information.
 Example:
 
@@ -23,7 +28,7 @@ env.Moc('foo.cpp') # generates foo.moc
 <summary>
 Builds a header file, an implementation file and a moc file from an ui file.
 and returns the corresponding nodes in the above order.
-This builder is only available after using the tool 'qt'. Note: you can 
+This builder is only available after using the tool 'qt'. Note: you can
 specify <filename>.ui</filename> files directly as source
 files to the &b-Program;,
 &b-Library; and &b-SharedLibrary; builders
@@ -63,38 +68,41 @@ Environment(tools=['default','qt'])
 
 The qt tool supports the following operations:
 
-.B Automatic moc file generation from header files.
+<emphasis Role="strong">Automatic moc file generation from header files.</emphasis>
 You do not have to specify moc files explicitly, the tool does it for you.
 However, there are a few preconditions to do so: Your header file must have
 the same filebase as your implementation file and must stay in the same
-directory. It must have one of the suffixes .h, .hpp, .H, .hxx, .hh. You 
+directory. It must have one of the suffixes .h, .hpp, .H, .hxx, .hh. You
 can turn off automatic moc file generation by setting QT_AUTOSCAN to 0.
 See also the corresponding builder method
 .B Moc()
 
-.B Automatic moc file generation from cxx files.
-As stated in the qt documentation, include the moc file at the end of 
+<emphasis Role="strong">Automatic moc file generation from cxx files.</emphasis>
+As stated in the qt documentation, include the moc file at the end of
 the cxx file. Note that you have to include the file, which is generated
-by the transformation ${QT_MOCCXXPREFIX}basename${QT_MOCCXXSUFFIX}, by default
-basename.moc. A warning is generated after building the moc file, if you 
-do not include the correct file. If you are using BuildDir, you may 
-need to specify duplicate=1. You can turn off automatic moc file generation 
-by setting QT_AUTOSCAN to 0. See also the corresponding builder method
-.B Moc()
-
-.B Automatic handling of .ui files.
+by the transformation ${QT_MOCCXXPREFIX}&lt;basename&gt;${QT_MOCCXXSUFFIX}, by default
+&lt;basename&gt;.moc. A warning is generated after building the moc file, if you
+do not include the correct file. If you are using BuildDir, you may
+need to specify duplicate=1. You can turn off automatic moc file generation
+by setting QT_AUTOSCAN to 0. See also the corresponding
+&b-Moc;
+builder method.
+
+<emphasis Role="strong">Automatic handling of .ui files.</emphasis>
 The implementation files generated from .ui files are handled much the same
 as yacc or lex files. Each .ui file given as a source of Program, Library or
-SharedLibrary will generate three files, the declaration file, the 
-implementation file and a moc file. Because there are also generated headers, 
-you may need to specify duplicate=1 in calls to BuildDir. See also the corresponding builder method
-.B Uic()
+SharedLibrary will generate three files, the declaration file, the
+implementation file and a moc file. Because there are also generated headers,
+you may need to specify duplicate=1 in calls to BuildDir.
+See also the corresponding
+&b-Uic;
+builder method.
 </summary>
 </cvar>
 
 <cvar name="QT_AUTOSCAN">
 <summary>
-Turn off scanning for mocable files. Use the Moc Builder to explicitely 
+Turn off scanning for mocable files. Use the Moc Builder to explicitely
 specify files to run moc on.
 </summary>
 </cvar>
@@ -131,7 +139,7 @@ this variable to None, the tool won't change the &cv-LIBS; variable.
 <cvar name="QT_LIBPATH">
 <summary>
 The path where the qt libraries are installed.
-The default value is '&cv-QTDIR;/lib'. 
+The default value is '&cv-QTDIR;/lib'.
 Note: If you set this variable to None, the tool won't change the &cv-LIBPATH;
 construction variable.
 </summary>
@@ -139,7 +147,7 @@ construction variable.
 
 <cvar name="QT_MOC">
 <summary>
-Default value is '&cv-QT_BINPATH;/bin/moc'.
+Default value is '&cv-QT_BINPATH;/moc'.
 </summary>
 </cvar>
 
@@ -151,7 +159,7 @@ Default value is ''. Prefix for moc output files, when source is a cxx file.
 
 <cvar name="QT_MOCCXXSUFFIX">
 <summary>
-Default value is '.moc'. Suffix for moc output files, when source is a cxx 
+Default value is '.moc'. Suffix for moc output files, when source is a cxx
 file.
 </summary>
 </cvar>
@@ -262,7 +270,7 @@ Default value is 'uic_'. Prefix for uic generated implementation files.
 
 <cvar name="QT_UICIMPLSUFFIX">
 <summary>
-Default value is '&cv-CXXFILESUFFIX;'. Suffix for uic generated implementation 
+Default value is '&cv-CXXFILESUFFIX;'. Suffix for uic generated implementation
 files.
 </summary>
 </cvar>
index 390aaafa7506dd85deb2c4d55c885a261c177021..1fe4bd854a472f89206218aa7f1249d1b8e203a2 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="rmic">
 <summary>
 XXX
index 9fdf13e5736f647e50b2e62174be5c8a6eea46c1..74fc3beb82454f022b2d06608e8230b624dceb46 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="rpcgen">
 <summary>
 XXX
index cd1d4140923f8f88d01609f5b83e24cd7b4287d5..ccea1ca800e8ec1ba2e3fb6d533b11a1cac5c6e1 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="sgiar">
 <summary>
 XXX
index 318ebbf2b8eba1901cf00db607cdb030af41f3b5..a507f7948a9a2e6e70f3091faec910c4f3033be3 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="sgic++">
 <summary>
 XXX
index bd752ec00d616f1ca6783e505a294f4aaa0189a5..285ae8c51960cb60091dbcbc565c70e113275ed7 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="sgicc">
 <summary>
 XXX
index 64eecb867a8cfea45111e81087f77ef94cee873e..8fa8f7d7cd3e4ccc8bf2b2e7c70d790327137902 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="sgilink">
 <summary>
 XXX
index b94443caa9a655c1344a22ce72ae255fc890d9d6..e22563d8dcd7e221a86ceb7a7bd337bd001842d5 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="sunar">
 <summary>
 XXX
index fcd6b0aef39b5890aa356b52840963e14be867e9..c18dd9090ba703625b7f63fa51d68cb83a911797 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="sunc++">
 <summary>
 XXX
index ab86294dd4df39c88fa4d6b2475021dc3412d40b..9f6d3408eb8667c6ea1c59192d78162dae809268 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="suncc">
 <summary>
 XXX
index 127651ee9d458d878b6a9a0ca16fedf384c1eb16..6cad24f7d4830e7972a478aa300f3898f1307053 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="sunlink">
 <summary>
 XXX
index 5c08412bc7706786f048eb5ba0d89d186f077459..0bdda96ec72a6ec06666780ddf0291828a0b8261 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="swig">
 <summary>
 XXX
index c00910a6ec21101c69c754a12a484340d7ce1065..88265dc8ac8984835cdaa5bb421c4cabadc4c22f 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="tar">
 <summary>
 XXX
@@ -17,6 +22,12 @@ for a given target;
 each additional call
 adds to the list of entries
 that will be built into the archive.
+Any source directories will
+be scanned for changes to
+any on-disk files,
+regardless of whether or not
+&scons;
+knows about them from other Builder or function calls.
 
 <example>
 env.Tar('src.tar', 'src')
index df7196e2055d2ebd8efa4c64b172a444df92479f..b30b36d9a33057d90a2048f60836f5d818be3775 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="tex">
 <summary>
 XXX
index 03515685642ae70b024adff73925707af6dab0df..9415c7d319d9ebf9e3fe82a2e41fa6db8957e40d 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="tlib">
 <summary>
 XXX
index 97bdf9b4e4f5085422ca13f567ec5d48efba8816..48bb3236d0b380bf1097d4f9fa01f6557f54bc3b 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="yacc">
 <summary>
 XXX
index 4e33c1586659b632c9f2d51f1b8d2fb3c517e979..5e28bee40f9f5075b6743fa491a4927a5da1da04 100644 (file)
@@ -1,4 +1,9 @@
-<!-- __COPYRIGHT__ -->
+<!--
+__COPYRIGHT__
+
+This file is processed by the bin/SConsDoc.py module.
+See its __doc__ string for a discussion of the format.
+-->
 <tool name="zip">
 <summary>
 XXX
@@ -17,6 +22,12 @@ for a given target;
 each additional call
 adds to the list of entries
 that will be built into the archive.
+Any source directories will
+be scanned for changes to
+any on-disk files,
+regardless of whether or not
+&scons;
+knows about them from other Builder or function calls.
 
 <example>
 env.Zip('src.zip', 'src')
@@ -67,11 +78,11 @@ module used by the internal Python function
 to control whether the zip archive
 is compressed or not.
 The default value is
-<varname>zipfile.ZIP_DEFLATED</varname>,
+<literal>zipfile.ZIP_DEFLATED</literal>,
 which creates a compressed zip archive.
 This value has no effect when using Python 1.5.2
 or if the
-<varname>zipfile</varname>
+<literal>zipfile</literal>
 module is otherwise unavailable.
 </summary>
 </cvar>