Commits

Anonymous committed 0b42bcf

Add design documentation.

Comments (0)

Files changed (18)

 Build "etc/Conscript";
 
 #
+# Documentation.
+#
+Link 'build/doc' => 'doc';
+
+Export qw( date env revision version );
+
+Build 'build/doc/Conscript';
+
+#
 # If we're running in the actual Aegis project, pack up a complete
 # source .tar.gz from the project files and files in the change,
 # so we can share it with helpful developers who don't use Aegis.
+*,D
+.*.swp
+.consign
+version.sgml
+#
+#
+#
+
+Import qw(
+    date
+    env
+    revision
+    version
+);
+
+#
+$verfile = SourcePath("version.sgml");
+open(FILE, ">$verfile") || die "Cannot open '$verfile': $!";
+print FILE <<_EOF_;
+<!--
+THIS IS AN AUTOMATICALLY-GENERATED FILE.  DO NOT EDIT.
+-->
+<!ENTITY build_date "$date">
+<!ENTITY build_version "$version">
+<!ENTITY build_revision "$revision">
+_EOF_
+close(FILE);
+
+Ignore("#$verfile");
+
+#
+#
+#
+
+@doc_dirs = qw(
+    design
+);
+
+# Find internal dependencies in .sgml files:
+#
+#	<!entity bground SYSTEM "bground.sgml">
+#	<graphic fileref="file.jpg">
+#
+# This only finds one per line, and assumes that anything
+# defined as a SYSTEM entity is, in fact, a file included
+# somewhere in the document.
+sub scansgml {
+    my @includes = ();
+    do {
+	if (/<!entity\s+(?:%\s+)?(?:\S+)\s+SYSTEM\s+"([^"]*)">/i) {
+	    push(@includes, $1);
+  	} elsif (/<graphic[^>]*\sfileref="([^"]*)"/) {
+	    push(@includes, "design/$1");
+	}
+    } while (<scan::quickscan::SCAN>);
+    @includes;
+}
+
+$env->QuickScan(\&scansgml, "scons.mod");
+$env->QuickScan(\&scansgml, "copyright.sgml");
+
+foreach $doc (@doc_dirs) {
+    my $main = "$doc/main.sgml";
+    my $out = "main.out";
+
+    $env->QuickScan(\&scansgml, $main);
+
+    $env->Command("HTML/$doc/book1.html", $main,
+	qq(jw -b html -o %>:d %<));
+
+    $env->Command("PS/$doc.ps", $main,
+	[qq(jw -b ps -o %>:d %<),
+	 qq(mv %>:d/main.ps %>),
+	]);
+
+    $env->Command("PDF/$doc.pdf", $main,
+	[qq(jw -b pdf -o %>:d %<),
+	 qq(mv %>:d/main.pdf %>),
+#	 qq(rm -f %>:d/$out),
+	]);
+}

doc/copyright.sgml

+<!--
+
+  Legal copyright notice.  Since some of this was published by Software
+  Carpentry for the contest, make sure we reference them and their
+  Open Publication license.
+
+-->
+
+<blockquote>
+ <para>
+
+  Portions of this document, by the same author, were previously
+  published Copyright 2000 by CodeSourcery LLC, under the Software Carpentry
+  Open Publication License, the terms of which are available at
+  <ulink url="http://www.software-carpentry.com/openpub-license.html">
+   http://www.software-carpentry.com/openpub-license.html
+  </ulink>.
+
+ </para>
+</blockquote>

doc/design/.aeignore

+*,D
+.*.swp
+.consign

doc/design/acks.sgml

+<!--
+
+  Copyright 2001 Steven Knight
+
+-->
+
+ <para>
+
+   I'm grateful to the following people
+   for their influence, knowing or not,
+   on the design of &SCons;:
+
+ </para>
+
+ <variablelist>
+  <varlistentry>
+   <term>Bob Sidebotham</term>
+   <listitem>
+     <para>
+
+     First, as the original author of &Cons;, Bob did the real heavy
+     lifting of creating the underlying model for dependency management
+     and software construction, as well as implementing it in Perl.
+     During the first years of &Cons;' existence, Bob did a skillful
+     job of integrating input and code from the first users, and
+     consequently is a source of practical wisdom and insight into the
+     problems of real-world software construction.  His continuing
+     advice has been invaluable.
+
+     </para>
+   </listitem>
+  </varlistentry>
+
+  <varlistentry>
+   <term>The &SCons; Development Team</term>
+   <listitem>
+     <para>
+
+     A big round of thanks go to those brave souls who have
+     gotten in on the ground floor:
+     David Abrahams,
+     Charles Crain,
+     Steven Leblanc.
+     Anthony Roach,
+     and
+     Steven Shaw.
+     Their contributions,
+     through their general knowledge of software build issues in general
+     Python in particular,
+     have made &SCons; what it is today.
+
+     </para>
+   </listitem>
+  </varlistentry>
+
+  <varlistentry>
+   <term>The &Cons; Community</term>
+   <listitem>
+     <para>
+
+     The real-world build problems that the users of &Cons;
+     share on the <command>cons-discuss</command> mailing list
+     have informed much of the thinking that
+     has gone into the &SCons; design.
+     In particular,
+     Rajesh Vaidheeswarran,
+     the current maintainer of &Cons;,
+     has been a very steady influence.
+     I've also picked up valuable insight from
+     mailing-list participants
+     Johan Holmberg,
+     Damien Neil,
+     Gary Oberbrunner,
+     Wayne Scott,
+     and Greg Spencer.
+
+     </para>
+   </listitem>
+  </varlistentry>
+
+  <varlistentry>
+   <term>Peter Miller</term>
+   <listitem>
+
+     <para>
+
+     Peter has indirectly
+     influenced two aspects of the &SCons; design:
+
+     </para>
+
+     <para>
+
+     Miller's influential paper
+     <citetitle>Recursive Make Considered Harmful</citetitle>
+     was what led me, indirectly, to my involvement with &Cons;
+     in the first place.
+     Experimenting with the single-Makefile approach he describes in
+     <citetitle>RMCH</citetitle> led me to conclude that while it worked
+     as advertised, it was not an extensible scheme.  This solidified
+     my frustration with Make and led me to try &Cons;, which at its
+     core shares the single-process, universal-DAG model of the "RMCH"
+     single-Makefile technique.
+
+     </para>
+
+     <para>
+
+     The testing framework that Miller created for his
+     Aegis change management system
+     changed the way I approach software development
+     by providing a framework for rigorous, repeatable
+     testing during development.
+     It was my success at using Aegis for personal projects
+     that led me to begin my involvement with &Cons;
+     by creating the <command>cons-test</command> regression suite.
+
+     </para>
+   </listitem>
+  </varlistentry>
+
+  <varlistentry>
+   <term>Stuart Stanley</term>
+   <listitem>
+     <para>
+
+     An experienced Python programmer,
+     Stuart provided valuable advice and insight
+     into some of the more useful Python idioms at my disposal
+     during the original <literal>ScCons</literal>; design
+     for the Software Carpentry contest.
+
+     </para>
+   </listitem>
+  </varlistentry>
+
+  <varlistentry>
+   <term>Gary Holt</term>
+   <listitem>
+     <para>
+
+     I don't know which came first,
+     the first-round Software Carpentry contest entry
+     or the tool itself,
+     but Gary's design for &Makepp;
+     showed me that it is possible to marry
+     the strengths of &Cons;-like dependency management
+     with backwards compatibility for &Makefile;s.
+     Striving to support both
+     &Makefile; compatibility and
+     a native Python interface
+     cleaned up the &SCons; design immeasurably
+     by factoring out the common elements
+     into the Build Engine.
+
+     </para>
+   </listitem>
+  </varlistentry>
+ </variablelist>
+

doc/design/bground.sgml

+<!--
+
+  Copyright 2001 Steven Knight
+
+-->
+
+ <para>
+
+  Most of the ideas in &SCons; originate with &Cons;, a Perl-based
+  software construction utility that has been in use by a small but
+  growing community since its development by Bob Sidebotham at FORE
+  Systems in 1996.  The &Cons; copyright was transferred in 2000 from
+  Marconi (who purchased FORE Systems) to the Free Software Foundation.
+  I've been a principal implementer and maintainer of &Cons; for several
+  years.
+
+ </para>
+
+ <para>
+
+  &Cons; was originally designed to handle complicated software build
+  problems (multiple directories, variant builds) while keeping the
+  input files simple and maintainable. The general philosophy is that
+  the build tool should ``do the right thing'' with minimal input
+  from an unsophisticated user, while still providing a rich set of
+  underlying functionality for more complicated software construction
+  tasks needed by experts.
+
+ </para>
+
+ <para>
+
+  In 2000, the Software Carpentry sought entries in a contest for a
+  new, Python-based build tool that would provide an improvement
+  over Make for physical scientists and other non-programmers
+  struggling to use their computers more effectively.  Prior to that,
+  the idea of combining the superior build architecture of &Cons;
+  with the easier syntax of Python had come up several times on
+  the <literal>cons-discuss</literal> mailing list.  The Software
+  Carpentry contest provided the right motivation to spend some
+  actual time working on a design document.
+
+ </para>
+
+ <para>
+
+  After two rounds of competition, the submitted design, named
+  <application>ScCons</application>, won the competition.  Software
+  Carpentry, however, did not immediately fund implementation of the
+  build tool, instead contracting for additional, more detailed draft(s)
+  of the design document.  This proved to be not as strong motivation as
+  actual coding, and after several months of inactivity, I essentially
+  resigned from the Software Carpentry effort in early 2001 to start
+  working on the tool independently.
+
+ </para>
+
+ <para>
+
+  After half a year of prototyping some of the important infrastructure,
+  I accumulated enough code to take the project public at SourceForge,
+  renaming it &SCons; to distinguish it slightly from the version of the
+  design that won the Software Carpentry contest while still honoring
+  its roots there and in the original &Cons; utility.  And also because
+  it would be a teensy bit easier to type.
+
+ </para>

doc/design/engine.fig

+#FIG 3.2
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 2100 8700 3600 9300
+2 2 0 1 0 7 100 0 -1 4.000 0 0 -1 0 0 5
+	 2100 8700 3600 8700 3600 9300 2100 9300 2100 8700
+4 0 0 100 0 18 14 0.0000 4 165 900 2400 9075 Node.FS\001
+-6
+6 7050 6900 9000 7500
+2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+	 7050 6900 9000 6900 9000 7500 7050 7500 7050 6900
+4 0 0 100 0 18 14 0.0000 4 165 1530 7200 7275 Intercessor.FS\001
+-6
+6 9450 6900 11400 7500
+2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+	 9450 6900 11400 6900 11400 7500 9450 7500 9450 6900
+4 0 0 100 0 18 14 0.0000 4 165 1560 9600 7275 Intercessor.DB\001
+-6
+6 1200 4200 2400 4800
+2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+	 1200 4200 2400 4200 2400 4800 1200 4800 1200 4200
+4 0 0 100 0 18 14 0.0000 4 165 870 1350 4575 Scanner\001
+-6
+6 2400 3300 3600 3900
+2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+	 2400 3300 3600 3300 3600 3900 2400 3900 2400 3300
+4 0 0 100 0 18 14 0.0000 4 165 750 2625 3675 Builder\001
+-6
+6 8700 1650 10500 2250
+2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+	 8700 1650 10500 1650 10500 2250 8700 2250 8700 1650
+4 0 0 100 0 18 14 0.0000 4 165 1185 9000 2025 Intercessor\001
+-6
+6 1500 1650 3300 2250
+2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+	 1500 1650 3300 1650 3300 2250 1500 2250 1500 1650
+4 0 0 100 0 18 14 0.0000 4 165 1320 1725 2025 Environment\001
+-6
+6 7800 8700 9300 9300
+2 2 0 1 0 7 100 0 -1 4.000 0 0 -1 0 0 5
+	 7800 8700 9300 8700 9300 9300 7800 9300 7800 8700
+4 0 0 100 0 18 14 0.0000 4 165 930 8100 9075 Node.DB\001
+-6
+6 1500 10200 2400 10800
+2 2 0 1 0 7 100 0 -1 4.000 0 0 -1 0 0 5
+	 1500 10200 2400 10200 2400 10800 1500 10800 1500 10200
+4 0 0 100 0 18 14 0.0000 4 165 315 1800 10575 Dir\001
+-6
+6 3300 10200 4200 10800
+2 2 0 1 0 7 100 0 -1 4.000 0 0 -1 0 0 5
+	 3300 10200 4200 10200 4200 10800 3300 10800 3300 10200
+4 0 0 100 0 18 14 0.0000 4 165 375 3600 10575 File\001
+-6
+6 6000 10200 7200 10800
+2 2 0 1 0 7 100 0 -1 4.000 0 0 -1 0 0 5
+	 6000 10200 7200 10200 7200 10800 6000 10800 6000 10200
+4 0 0 100 0 18 14 0.0000 4 165 555 6300 10575 Table\001
+-6
+6 7800 10200 9300 10800
+2 2 0 1 0 7 100 0 -1 4.000 0 0 -1 0 0 5
+	 7800 10200 9300 10200 9300 10800 7800 10800 7800 10200
+4 0 0 100 0 18 14 0.0000 4 165 765 8100 10575 Record\001
+-6
+6 9900 10200 11100 10800
+2 2 0 1 0 7 100 0 -1 4.000 0 0 -1 0 0 5
+	 9900 10200 11100 10200 11100 10800 9900 10800 9900 10200
+4 0 0 100 0 18 14 0.0000 4 165 510 10200 10575 Field\001
+-6
+2 3 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+	 6900 5250 6825 5175 6900 5100 6975 5175 6900 5250
+2 3 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+	 6300 5250 6225 5175 6300 5100 6375 5175 6300 5250
+2 3 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+	 5700 5250 5625 5175 5700 5100 5775 5175 5700 5250
+2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+	 4800 2700 7200 2700 7200 5100 4800 5100 4800 2700
+2 3 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 4
+	 5100 5100 5025 5250 5175 5250 5100 5100
+2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 5
+	0 0 1.00 60.00 120.00
+	 6300 5250 6300 5700 8400 5700 8400 4200 7200 4200
+2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 5
+	0 0 1.00 60.00 120.00
+	 5700 5250 5700 6000 9000 6000 9000 3600 7200 3600
+2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 2
+	 5100 5250 5100 8100
+2 3 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+	 4725 3675 4650 3600 4725 3525 4800 3600 4725 3675
+2 3 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+	 4725 4575 4650 4500 4725 4425 4800 4500 4725 4575
+2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
+	0 0 1.00 60.00 120.00
+	 4650 3600 3600 3600
+2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
+	0 0 1.00 60.00 120.00
+	 4650 4500 2400 4500
+2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
+	0 0 1.00 60.00 120.00
+	 1800 2400 1800 4200
+2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
+	0 0 1.00 60.00 120.00
+	 3000 2400 3000 3300
+2 1 1 1 0 7 100 0 -1 4.000 0 0 7 0 0 2
+	 5850 1950 5850 2700
+2 3 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+	 3000 2400 2925 2325 3000 2250 3075 2325 3000 2400
+2 3 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+	 1800 2400 1725 2325 1800 2250 1875 2325 1800 2400
+2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 2
+	 3300 1950 8700 1950
+2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 2
+	 9600 2400 9600 6600
+2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 4
+	 7950 6900 7950 6600 10350 6600 10350 6900
+2 3 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 4
+	 9600 2250 9525 2400 9675 2400 9600 2250
+2 1 0 1 0 7 100 0 -1 4.000 0 0 7 0 0 2
+	 4800 3000 7200 3000
+2 1 0 1 0 7 100 0 -1 4.000 0 0 -1 0 0 2
+	 4800 3300 7200 3300
+2 3 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 4
+	 2850 9300 2775 9450 2925 9450 2850 9300
+2 1 0 1 0 7 100 0 -1 4.000 0 0 -1 0 0 4
+	 2100 10200 2100 9900 3750 9900 3750 10200
+2 1 0 1 0 7 100 0 -1 4.000 0 0 -1 0 0 5
+	 6600 10200 6600 9900 10500 9900 10500 10200 10500 10125
+2 1 0 1 0 7 100 0 -1 4.000 0 0 -1 0 0 2
+	 2850 9450 2850 9900
+2 1 0 1 0 7 100 0 -1 4.000 0 0 -1 0 0 2
+	 8475 9450 8475 10200
+2 3 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 4
+	 8475 9300 8400 9450 8550 9450 8475 9300
+2 1 0 1 0 7 100 0 -1 4.000 0 0 -1 0 0 1
+	 2775 6825
+2 1 0 1 0 7 100 0 -1 4.000 0 0 -1 1 0 3
+	0 0 1.00 60.00 120.00
+	 1800 10200 1800 9000 2100 9000
+2 1 0 1 0 7 100 0 -1 4.000 0 0 -1 1 0 2
+	0 0 1.00 60.00 120.00
+	 9900 10500 9300 10500
+2 1 0 1 0 7 100 0 -1 4.000 0 0 -1 1 0 2
+	0 0 1.00 60.00 120.00
+	 7800 10500 7200 10500
+2 1 0 1 0 7 100 0 -1 4.000 0 0 7 0 0 4
+	 2850 8700 2850 8100 8550 8100 8550 8700
+2 1 1 1 0 7 100 0 -1 4.000 0 0 -1 1 0 3
+	0 0 1.00 60.00 120.00
+	 10350 7500 10350 9000 9300 9000
+2 1 1 1 0 7 100 0 -1 4.000 0 0 -1 1 0 3
+	0 0 1.00 60.00 120.00
+	 7050 7200 2400 7200 2400 8700
+2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 5
+	0 0 1.00 60.00 120.00
+	 6900 5250 6900 5400 7800 5400 7800 4800 7200 4800
+4 0 0 100 0 18 14 0.0000 4 165 555 4950 2925 Node\001
+4 0 0 100 0 16 10 0.0000 4 150 825 7350 3525 dependency\001
+4 0 0 100 0 16 10 0.0000 4 45 60 7425 3825 *\001
+4 0 0 100 0 16 10 0.0000 4 120 555 7350 4125 srcnode\001
+4 0 0 100 0 16 10 0.0000 4 120 90 7425 4425 1\001
+4 0 0 100 0 16 10 0.0000 4 150 570 7350 4725 repnode\001
+4 0 0 100 0 16 10 0.0000 4 120 90 7425 5025 1\001
+4 0 0 100 0 16 10 0.0000 4 120 270 2550 4725 0..1\001
+4 0 0 100 0 16 10 0.0000 4 120 270 3750 3825 0..1\001
+4 0 0 100 0 0 12 0.0000 4 75 90 1875 4050 *\001
+4 0 0 100 0 0 12 0.0000 4 75 90 3075 3150 *\001
+4 0 0 100 0 16 14 0.0000 4 210 600 5100 3750 build()\001
+4 0 0 100 0 16 14 0.0000 4 210 630 5100 4260 scan()\001
+4 0 0 100 0 0 12 0.0000 4 135 90 9750 10725 1\001
+4 0 0 100 0 16 10 0.0000 4 120 90 1650 10125 1\001
+4 0 0 100 0 16 10 0.0000 4 45 60 1875 9225 *\001
+4 0 0 100 0 16 10 0.0000 4 120 90 7650 10725 1\001
+4 0 0 100 0 16 10 0.0000 4 45 60 7275 10725 *\001
+4 0 0 100 0 16 10 0.0000 4 45 60 9375 10725 *\001
Added
New image

doc/design/engine.sgml

+<!--
+
+  Copyright 2001 Steven Knight
+
+-->
+
+<section id="sect-principles">
+ <title>General Principles</title>
+
+ <section>
+  <title>Keyword arguments</title>
+  
+  <para>
+
+   All methods and functions in this API will support the use of keyword
+   arguments in calls, for the sake of explicitness and readability.
+   For brevity in the hands of experts, most methods and functions
+   will also support positional arguments for their most-commonly-used
+   arguments.  As an explicit example, the following two lines will each
+   arrange for an executable program named <filename>foo</filename> (or
+   <filename>foo.exe</filename> on a Win32 system) to be compiled from
+   the <filename>foo.c</filename> source file:
+
+  </para>
+
+	<programlisting>
+	env.Program(target = 'foo', source = 'foo.c')
+
+	env.Program('foo', 'foo.c')
+	</programlisting>
+
+ </section>
+
+ <section>
+  <title>Internal object representation</title>
+
+  <para>
+
+   All methods and functions use internal (Python) objects that
+   represent the external objects (files, for example) for which they
+   perform dependency analysis.
+
+  </para>
+
+  <para>
+
+   All methods and functions in this API that accept an external object
+   as an argument will accept <emphasis>either</emphasis> a string
+   description or an object reference.  For example, the two following
+   two-line examples are equivalent:
+
+  </para>
+
+	<programlisting>
+	env.Object(target = 'foo.o', source = 'foo.c')
+	env.Program(target = 'foo', 'foo.o')    # builds foo from foo.o
+
+	foo_obj = env.Object(target = 'foo.o', source = 'foo.c')
+	env.Program(target = 'foo', foo_obj)    # builds foo from foo.o
+	</programlisting>
+
+ </section>
+
+</section>
+
+
+
+<section id="sect-envs">
+ <title>&ConsEnvs</title>
+
+ <para>
+
+  A &consenv; is the basic means by which a software system interacts
+  with the &SCons; Python API to control a build process.
+
+ </para>
+
+ <para>
+
+  A &consenv; is an object with associated methods for generating target
+  files of various types (&Builder; objects), other associated object
+  methods for automatically determining dependencies from the contents
+  of various types of source files (&Scanner; objects), and a dictionary
+  of values used by these methods.
+
+ </para>
+
+ <para>
+
+  Passing no arguments to the &Environment; instantiation creates a
+  &consenv; with default values for the current platform:
+
+ </para>
+
+	<programlisting>
+	env = Environment()
+	</programlisting>
+
+ <section>
+  <title>&Consvars;</title>
+
+  <para>
+
+   A &consenv; has an associated dictionary of &consvars; that control how
+   the build is performed.  By default, the &Environment; method creates
+   a &consenv; with values that make most software build "out of the box"
+   on the host system.  These default values will be generated at the
+   time &SCons; is installed using functionality similar to that provided
+   by GNU &Autoconf;.
+   <footnote>
+    <para>
+     It would be nice if we could avoid re-inventing the wheel here by
+     using some other Python-based tool &Autoconf replacement--like what
+     was supposed to come out of the Software Carpentry configuration
+     tool contest.  It will probably be most efficient to roll our own
+     logic initially and convert if something better does come along.
+    </para>
+   </footnote>
+   At a minimum, there will be pre-configured sets of default values
+   that will provide reasonable defaults for UNIX and Windows NT.
+
+  </para>
+
+  <para>
+
+   The default &consenv; values may be overridden when a new &consenv; is
+   created by specifying keyword arguments:
+
+  </para>
+
+	<programlisting>
+	env = Environment(CC =          'gcc',
+	                  CCFLAGS =    '-g',
+	                  CPPPATH =    ['.', 'src', '/usr/include'],
+	                  LIBPATH =    ['/usr/lib', '.'])
+	</programlisting>
+
+ </section>
+
+ <section>
+  <title>Fetching &consvars;</title>
+
+  <para>
+
+   A copy of the dictionary of &consvars; can be returned using
+   the &Dictionary; method:
+
+  </para>
+
+	<programlisting>
+	env = Environment()
+	dict = env.Dictionary()
+	</programlisting>
+
+<REMARK>
+In the current source code, I implemented this as a dictionary attribute
+named <literal>Dictionary</literal>.  While reasonably Pythonic, this
+is ultimately Not Good.  We don't want people using a reference to the
+dictionary to change construction variables out from under an existing
+environment.  We should use an internal <literal>_dict</literal>
+attribute and control access to it through a method, as specified above.
+</REMARK>
+
+  <para>
+
+   If any arguments are supplied, then just the corresponding value(s)
+   are returned:
+
+  </para>
+
+	<programlisting>
+	ccflags = env.Dictionary('CCFLAGS')
+	cc, ld = env.Dictionary('CC', 'LD')
+	</programlisting>
+
+ </section>
+
+ <section>
+  <title>Copying a &consenv;</title>
+
+  <para>
+
+   A method exists to return a copy of an existing environment, with
+   any overridden values specified as keyword arguments to the method:
+
+  </para>
+
+	<programlisting>
+	env = Environment()
+	debug = env.Copy(CCFLAGS = '-g')
+	</programlisting>
+
+ </section>
+
+ <section>
+  <title>Multiple &consenvs;</title>
+
+  <para>
+
+   Different external objects often require different build
+   characteristics.  Multiple &consenvs; may be defined, each with
+   different values:
+
+  </para>
+
+	<programlisting>
+	env = Environment(CCFLAGS = '')
+	debug = Environment(CCFLAGS = '-g')
+	env.Make(target = 'hello', source = 'hello.c')
+	debug.Make(target = 'hello-debug', source = 'hello.c')
+	</programlisting>
+
+  <para>
+
+   Dictionaries of values from multiple &consenvs; may be passed to the
+   &Environment; instantiation or the &Copy; method, in which case the
+   last-specified dictionary value wins:
+
+  </para>
+
+	<programlisting>
+	env1 = Environment(CCFLAGS = '-O', LDFLAGS = '-d')
+	env2 = Environment(CCFLAGS = '-g')
+	new = Environment(env1.Dictionary(), env2.Dictionary())
+	</programlisting>
+
+  <para>
+
+   The <varname>new</varname> environment in the above example retains
+   <literal>LDFLAGS = '-d'</literal> from the <varname>env1</varname>
+   environment, and <literal>CCFLAGS = '-g'</literal> from the
+   <varname>env2</varname> environment.
+
+  </para>
+
+  <!--
+
+	hardware details
+	current directory
+	OS environment variables
+	compilers and options,
+	aliases for commands,
+	versions of tools
+
+	environment overrides a la Cons
+
+	compilation options
+
+	cross compilation via selection of tool+options
+
+	paths for header files (specify alternate path)
+
+	accomodate smart compilers that can tell you
+	"I know how to turn .c or .ccp into .o",
+	"I know how to turn .f into .o"
+
+   -->
+
+ </section>
+
+ <section>
+  <title>Variable substitution</title>
+
+  <para>
+
+   Within a construction command, any variable from the &consenv; may
+   be interpolated by prefixing the name of the construction with
+   <symbol>$</symbol>:
+
+  </para>
+
+	<programlisting>
+	MyBuilder = Builder(command = "$XX $XXFLAGS -c $_INPUTS -o $target")
+
+	env.Command(targets = 'bar.out', sources = 'bar.in',
+	            command = "sed '1d' < $source > $target")
+	</programlisting>
+
+  <para>
+
+   Variable substitution is recursive:  the command line is expanded
+   until no more substitutions can be made.
+
+  </para>
+
+  <para>
+
+   Variable names following the <symbol>$</symbol> may be enclosed in
+   braces.  This can be used to concatenate an interpolated value with an
+   alphanumeric character:
+
+  </para>
+
+	<programlisting>
+	VerboseBuilder = Builder(command = "$XX -${XXFLAGS}v > $target")
+	</programlisting>
+
+  <para>
+
+   The variable within braces may contain a pair of parentheses
+   after a Python function name to be evaluated (for example,
+   <literal>${map()}</literal>).  &SCons; will interpolate the return
+   value from the function (presumably a string):
+
+  </para>
+
+	<programlisting>
+	env = Environment(FUNC = myfunc)
+	env.Command(target = 'foo.out', source = 'foo.in',
+	            command = "${FUNC($<)}")
+	</programlisting>
+
+  <para>
+
+   If a referenced variable is not defined in the &consenv;,
+   the null string is interpolated.
+
+  </para>
+
+  <para>
+
+   The following special variables can also be used:
+
+  </para>
+
+  <variablelist>
+
+   <varlistentry>
+    <term><literal>$targets</literal></term>
+    <listitem>
+     <para>
+
+      All target file names.  If multiple targets are specified in an
+      array, <literal>$targets</literal> expands to the entire list of
+      targets, separated by a single space.
+
+    </para>
+
+    <para>
+
+      Individual targets from a list may be extracted by enclosing
+      the <literal>targets</literal> keyword in braces and using the
+      appropriate Python array index or slice:
+
+    </para>
+
+	<programlisting>
+	${targets[0]}     # expands to the first target
+
+	${targets[1:]}    # expands to all but the first target
+
+	${targets[1:-1]}  # expands to all but the first and last targets
+	</programlisting>
+
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>$target</literal></term>
+    <listitem>
+     <para>
+
+      A synonym for <literal>${targets[0]}</literal>, the first target
+      specified.
+
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>$sources</literal></term>
+    <listitem>
+     <para>
+
+      All input file names.  Any input file names that
+      are used anywhere else on the current command
+      line (via <literal>${sources[0]}</literal>,
+      <literal>${sources{[1]}</literal>, etc.) are removed from the
+      expanded list.
+
+     </para>
+    </listitem>
+   </varlistentry>
+
+  </variablelist>
+
+  <para>
+
+   Any of the above special variables may be enclosed in braces and
+   followed immediately by one of the following attributes to select just
+   a portion of the expanded path name:
+
+  </para>
+
+  <variablelist>
+
+   <varlistentry>
+    <term><literal>.base</literal></term>
+    <listitem>
+     <para>
+
+      Basename: the directory plus the file name, minus any file suffix.
+
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>.dir</literal></term>
+    <listitem>
+     <para>
+
+      The directory in which the file lives.  This is a relative path,
+      where appropriate.
+
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>.file</literal></term>
+    <listitem>
+     <para>
+
+      The file name, minus any directory portion.
+
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>.suffix</literal></term>
+    <listitem>
+     <para>
+
+      The file name suffix (that is, the right-most dot in the file name,
+      and all characters to the right of that).
+
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>.filebase</literal></term>
+    <listitem>
+     <para>
+
+      The file name (no directory portion), minus any file suffix.
+
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>.abspath</literal></term>
+    <listitem>
+     <para>
+
+      The absolute path to the file.
+
+     </para>
+    </listitem>
+   </varlistentry>
+
+  </variablelist>
+
+ </section>
+
+</section>
+
+
+
+<section id="sect-builders">
+ <title>&Builder; Objects</title>
+
+ <para>
+
+  By default, &SCons; supplies (and uses) a number of pre-defined
+  &Builder; objects:
+
+ </para>
+
+ <informaltable>
+  <tgroup cols="2">
+  <tbody>
+
+   <row>
+    <entry>&Object;</entry>
+    <entry>compile or assemble an object file</entry>
+   </row>
+
+   <row>
+    <entry>&Library;</entry>
+    <entry>archive files into a library</entry>
+   </row>
+
+   <row>
+    <entry>&SharedLibrary;</entry>
+    <entry>archive files into a shared library</entry>
+   </row>
+
+   <row>
+    <entry>&Program;</entry>
+    <entry>link objects and/or libraries into an executable</entry>
+   </row>
+
+   <row>
+    <entry>&MakeBuilder;</entry>
+    <entry>build according to file suffixes; see below</entry>
+   </row>
+
+  </tbody>
+  </tgroup>
+ </informaltable>
+
+<REMARK>
+&Library; and &SharedLibrary; have nearly identical
+semantics, just different
+tools and &consenvs (paths, etc.) that they use.
+In other words, you can construct a shared library
+using just the &Library; &Builder; object
+with a different environment.
+I think that's a better way to do it.
+Feedback?
+</REMARK>
+
+ <para>
+
+  A &consenv; can be explicitly initialized with associated &Builder;
+  objects that will be bound to the &consenv; object:
+
+ </para>
+
+	<programlisting>
+	env = Environment(BUILDERS = ['Object', 'Program'])
+	</programlisting>
+
+ <para>
+
+  &Builder; objects bound to a &consenv; can be called directly as
+  methods.  When invoked, a &Builder; object returns a (list of) objects
+  that it will build:
+
+ </para>
+
+	<programlisting>
+	obj = env.Object(target ='hello.o', source = 'hello.c')
+	lib = env.Library(target ='libfoo.a',
+	                  source = ['aaa.c', 'bbb.c'])
+	slib = env.SharedLibrary(target ='libbar.so',
+	                         source = ['xxx.c', 'yyy.c'])
+	prog = env.Program(target ='hello',
+	                   source = ['hello.o', 'libfoo.a', 'libbar.so'])
+	</programlisting>
+
+ <section>
+  <title>Specifying multiple inputs</title>
+
+  <para>
+
+   Multiple input files that go into creating a target file may be passed
+   in as a single string, with the individual file names separated by
+   white space:
+
+  </para>
+
+	<programlisting>
+	env.Library(target = 'foo.a', source = 'aaa.c bbb.c ccc.c')
+	env.Object(target = 'yyy.o', source = 'yyy.c')
+	env.Program(target = 'bar', source = 'xxx.c yyy.o foo.a')
+	</programlisting>
+
+  <para>
+
+   Alternatively, multiple input files that go into creating a target
+   file may be passed in as an array.  This allows input files to be
+   specified using their object representation:
+
+  </para>
+
+	<programlisting>
+	env.Library(target = 'foo.a', source = ['aaa.c', 'bbb.c', 'ccc.c'])
+	yyy_obj = env.Object(target = 'yyy.o', source = 'yyy.c')
+	env.Program(target = 'bar', source = ['xxx.c', yyy_obj, 'foo.a'])
+	</programlisting>
+
+   <para>
+
+    Individual string elements within an array of input files are
+    <emphasis>not</emphasis> further split into white-space separated
+    file names.  This allows file names that contain white space to
+    be specified by putting the value into an array:
+
+	<programlisting>
+	env.Program(target = 'foo', source = ['an input file.c'])
+	</programlisting>
+
+   </para>
+
+ </section>
+
+ <section>
+  <title>Specifying multiple targets</title>
+
+  <para>
+
+   Conversely, the generated target may be a string listing multiple
+   files separated by white space:
+
+  </para>
+
+	<programlisting>
+	env.Object(target = 'grammar.o y.tab.h', source = 'grammar.y')
+	</programlisting>
+
+  <para>
+
+   An array of multiple target files can be used to mix string and object
+   representations, or to accomodate file names that contain white space:
+
+  </para>
+
+	<programlisting>
+	env.Program(target = ['my program'], source = 'input.c')
+	</programlisting>
+
+ </section>
+
+ <section>
+  <title>File prefixes and suffixes</title>
+
+  <para>
+
+   For portability, if the target file name does not already have an
+   appropriate file prefix or suffix, the &Builder; objects will
+   append one appropriate for the file type on the current system:
+
+  </para>
+
+	<programlisting>
+	# builds 'hello.o' on UNIX, 'hello.obj' on Windows NT:
+	obj = env.Object(target ='hello', source = 'hello.c')
+
+	# builds 'libfoo.a' on UNIX, 'foo.lib' on Windows NT:
+	lib = env.Library(target ='foo', source = ['aaa.c', 'bbb.c'])
+
+	# builds 'libbar.so' on UNIX, 'bar.dll' on Windows NT:
+	slib = env.SharedLibrary(target ='bar', source = ['xxx.c', 'yyy.c'])
+
+	# builds 'hello' on UNIX, 'hello.exe' on Windows NT:
+	prog = env.Program(target ='hello',
+	                   source = ['hello.o', 'libfoo.a', 'libbar.so'])
+	</programlisting>
+
+ </section>
+
+ <section>
+  <title>&Builder; object exceptions</title>
+
+  <para>
+
+   &Builder; objects raise the following exceptions on error:
+
+ <REMARK>
+ LIST THESE ONCE WE FIGURE OUT WHAT THEY ARE FROM CODING THEM.
+ </REMARK>
+
+  </para>
+ </section>
+
+ <section>
+  <title>User-defined &Builder; objects</title>
+
+  <para>
+
+   Users can define additional &Builder; objects for specific external
+   object types unknown to &SCons;.  A &Builder; object may build its
+   target by executing an external command:
+
+  </para>
+
+	<programlisting>
+	WebPage = Builder(command = 'htmlgen $HTMLGENFLAGS $sources > $target',
+	                input_suffix = '.in',
+	                output_suffix = '.html')
+	</programlisting>
+
+  <para>
+
+   Alternatively, a &Builder; object may also build its target by
+   executing a Python function:
+
+   </para>
+
+	<programlisting>
+	def update(dest):
+	        # [code to update the object]
+	        return 1
+
+	OtherBuilder1 = Builder(function = update,
+	                input_suffix = ['.in', '.input'])
+	</programlisting>
+
+   <para>
+   
+   An optional argument to pass to the function may be specified:
+
+  </para>
+
+	<programlisting>
+	def update_arg(dest, arg):
+	        # [code to update the object]
+	        return 1
+
+	OtherBuilder2 = Builder(function = update_arg,
+	                function_arg = 'xyzzy',
+	                input_suffix = ['.in', '.input'])
+	</programlisting>
+
+  <para>
+
+   Both an external command and an internal function may be specified,
+   in which case the function will be called to build the object first,
+   followed by the command line.
+
+  </para>
+
+ <REMARK>
+ NEED AN EXAMPLE HERE.
+ </REMARK>
+
+  <para>
+
+   User-defined &Builder; objects can be used like the default &Builder;
+   objects to initialize &consenvs;.
+
+  </para>
+
+	<programlisting>
+	WebPage = Builder(command = 'htmlgen $HTMLGENFLAGS $sources > $target',
+	                input_suffix = '.in',
+	                output_suffix = '.html')
+	env = Environment(BUILDERS = ['WebPage'])
+	env.WebPage(target = 'foo.html', source = 'foo.in')
+	# Builds 'bar.html' on UNIX, 'bar.htm' on Windows NT:
+	env.WebPage(target = 'bar', source = 'bar.in')
+	</programlisting>
+
+  <para>
+
+   The command-line specification can interpolate variables from the
+   &consenv;; see "Variable substitution," above.
+
+  </para>
+
+  <para>
+
+   A &Builder; object may optionally be initialized with a list of
+   the expected suffixes of input files for this object.  It may also
+   be initialized with an output suffix for the files that this
+   &Builder; object builds.  These arguments are used in automatic
+   dependency analysis and in generating output file names that don't
+   have suffixes supplied explicitly.
+
+  </para>
+ </section>
+
+ <section>
+  <title>Copying &Builder; Objects</title>
+
+  <para>
+
+   A &Copy; method exists to return a copy of an existing &Builder;
+   object, with any overridden values specified as keyword arguments to
+   the method:
+
+  </para>
+
+	<programlisting>
+	build = Builder(function = my_build)
+	build_out = build.Copy(output_suffix = '.out')
+	</programlisting>
+
+  <para>
+
+   Typically, &Builder; objects will be supplied by a tool-master or
+   administrator through a shared &consenv;.
+
+  </para>
+ </section>
+
+ <section>
+  <title>Special-purpose build rules</title>
+
+  <para>
+
+   A pre-defined &Command; builder exists to associate a target file with
+   a specific command or list of commands for building the file:
+
+  </para>
+
+	<programlisting>
+	env.Command(target = 'foo.out', source = 
+	            command = 'foo.in', "foo.process $sources > $target")
+
+	commands = [    "bar.process -o .tmpfile $sources",
+	                "mv .tmpfile $target" ]
+	env.Command(target = 'bar.out', source = 'bar.in', command = commands)
+	</programlisting>
+
+  <para>
+   This is useful when it's too cumbersome to create a &Builder;
+   object just to build a single file in a special way.
+
+  </para>
+ </section>
+
+ <section>
+  <title>The &MakeBuilder; &Builder;</title>
+
+  <para>
+
+   A pre-defined &Builder; object named &MakeBuilder; exists to make
+   simple builds as easy as possible for users, at the expense of
+   sacrificing some build portability.
+
+  </para>
+
+  <para>
+
+   The following minimal example builds the 'hello' program from the
+   'hello.c' source file:
+
+  </para>
+
+	<programlisting>
+	Environment().Make('hello', 'hello.c')
+	</programlisting>
+
+  <para>
+
+   Users of the &MakeBuilder; &Builder; object are not required to
+   understand intermediate steps involved in generating a file--for
+   example, the distinction between compiling source code into an object
+   file, and then linking object files into an executable.  The details
+   of intermediate steps are handled by the invoked method.  Users that
+   need to, however, can specify intermediate steps explicitly:
+
+  </para>
+
+	<programlisting>
+	env = Environment()
+	env.Make(target = 'hello.o', source = 'hello.c')
+	env.Make(target = 'hello', source = 'hello.o')
+	</programlisting>
+
+  <para>
+
+   The &MakeBuilder; method understands the file suffixes specified and
+   "does the right thing" to generate the target object and program
+   files, respectively.  It does this by examining the specified output
+   suffixes for the &Builder; objects bound to the environment.
+
+  </para>
+
+  <para>
+
+   Because file name suffixes in the target and source file names
+   must be specified, the &MakeBuilder; method can't be used
+   portably across operating systems.  In other words, for the
+   example above, the &MakeBuilder; builder will not generate
+   <filename>hello.exe</filename> on Windows NT.
+
+  </para>
+
+ </section>
+
+ <section>
+  <title>&Builder; maps</title>
+
+<REMARK>
+Do we even need this anymore?
+Now that the individual builders
+have specified <literal>input_suffix</literal>
+and <literal>output_suffix</literal> values,
+all of the information we need to support
+the &MakeBuilder; builder is right there in the environment.
+I think this is a holdover from before I
+added the <literal>suffix</literal> arguments.
+If you want &MakeBuilder; to do something different,
+you set it up with another environment...
+</REMARK>
+
+  <para>
+
+   The <function>env.Make</function> method "does the right thing" to
+   build different file types because it uses a dictionary from the
+   &consenv; that maps file suffixes to the appropriate &Builder; object.
+   This &BUILDERMAP; can be initialized at instantiation:
+
+  </para>
+
+	<programlisting>
+	env = Environment(BUILDERMAP = {
+	                        '.o' : Object,
+	                        '.a' : Library,
+	                        '.html' : WebPage,
+	                        '' : Program,
+	                })
+	</programlisting>
+
+  <para>
+
+   With the &BUILDERMAP; properly initialized, the
+   <function>env.Make</function> method can be used to build additional
+   file types:
+
+  </para>
+
+	<programlisting>
+	env.Make(target = 'index.html', source = 'index.input')
+	</programlisting>
+
+  <para>
+
+   &Builder; objects referenced in the &BUILDERMAP; do not need to be
+   listed separately in the &BUILDERS; variable.  The &consenv; will
+   bind the union of the &Builder; objects listed in both variables.
+
+  </para>
+
+ <!--
+
+   YYY support scanners which detect files which haven't been generated yet
+
+ -->
+
+ </section>
+
+</section>
+
+
+
+<section id="sect-deps">
+ <title>Dependencies</title>
+
+ <section>
+  <title>Automatic dependencies</title>
+
+  <para>
+
+   By default, &SCons; assumes that a target file has <literal>automatic
+   dependencies</literal> on the:
+
+  </para>
+
+  <blockquote>
+   <simplelist>
+
+    <member>tool used to build the target file</member>
+
+    <member>contents of the input files</member>
+
+    <member>command line used to build the target file</member>
+
+   </simplelist>
+  </blockquote>
+
+  <para>
+
+   If any of these changes, the target file will be rebuilt.
+
+  </para>
+ </section>
+
+ <section>
+  <title>Implicit dependencies</title>
+
+  <para>
+
+   Additionally, &SCons; can scan the contents of files for
+   <literal>implicit dependencies</literal> on other files.  For
+   example, &SCons; will scan the contents of a <filename>.c</filename>
+   file and determine that any object created from it is
+   dependent on any <filename>.h</filename> files specified via
+   <literal>#include</literal>.  &SCons;, therefore, "does the right
+   thing" without needing to have these dependencies listed explicitly:
+
+  </para>
+
+	<programlisting>
+	% cat Construct
+	env = Environment()
+	env.Program('hello', 'hello.c')
+	% cat hello.c
+	#include "hello_string.h"
+	main()
+	{
+	        printf("%s\n", STRING);
+	}
+	% cat > hello_string.h
+	#define STRING  "Hello, world!\n"
+	% scons .
+	gcc -c hello.c -o hello.o
+	gcc -o hello hello.c
+	% ./hello
+	Hello, world!
+	% cat > hello_string.h
+	#define STRING  "Hello, world, hello!\n"
+	% scons .
+	gcc -c hello.c -o hello.o
+	gcc -o hello hello.c
+	% ./hello
+	Hello, world, hello!
+	%
+	</programlisting>
+
+ </section>
+
+ <section>
+  <title>Ignoring dependencies</title>
+
+  <para>
+
+   Undesirable <literal>automatic dependencies</literal> or
+   <literal>implicit dependencies</literal> may be ignored:
+
+  </para>
+
+	<programlisting>
+	env.Program(target = 'bar', source = 'bar.c')
+	env.Ignore('bar', '/usr/bin/gcc', 'version.h')
+	</programlisting>
+
+  <para>
+
+   In the above example, the <filename>bar</filename> program will not
+   be rebuilt if the <filename>/usr/bin/gcc</filename> compiler or the
+   <filename>version.h</filename> file change.
+
+  </para>
+ </section>
+
+ <section>
+  <title>Explicit dependencies</title>
+
+  <para>
+
+   Dependencies that are unknown to &SCons; may be specified explicitly
+   in an &SCons; configuration file:
+
+  </para>
+
+	<programlisting>
+	env.Dependency(target = 'output1', dependency = 'input_1 input_2')
+	env.Dependency(target = 'output2', dependency = ['input_1', 'input_2'])
+	env.Dependency(target = 'output3', dependency = ['white space input'])
+
+	env.Dependency(target = 'output_a output_b', dependency = 'input_3')
+	env.Dependency(target = ['output_c', 'output_d'], dependency = 'input_4')
+	env.Dependency(target = ['white space output'], dependency = 'input_5')
+	</programlisting>
+
+  <para>
+
+   Just like the <literal>target</literal> keyword argument, the
+   <literal>dependency</literal> keyword argument may be specified as a
+   string of white-space separated file names, or as an array.
+
+  </para>
+
+  <para>
+
+   A dependency on an &SCons; configuration file itself may be specified
+   explicitly to force a rebuild whenever the configuration file changes:
+
+  </para>
+
+	<programlisting>
+	env.Dependency(target = 'archive.tar.gz', dependency = 'SConstruct')
+	</programlisting>
+
+ </section>
+
+</section>
+
+
+
+<section id="sect-scanners">
+ <title>&Scanner; Objects</title>
+
+ <para>
+
+  Analagous to the previously-described &Builder; objects, &SCons;
+  supplies (and uses) &Scanner; objects to search the contents of
+  a file for implicit dependency files:
+
+ </para>
+
+ <informaltable>
+  <tgroup cols="2">
+  <tbody>
+
+   <row>
+    <entry>CScan</entry>
+    <entry>scan .{c,C,cc,cxx,cpp} files for #include dependencies</entry>
+   </row>
+
+  </tbody>
+  </tgroup>
+ </informaltable>
+
+ <para>
+
+  A &consenv; can be explicitly initialized with
+  associated &Scanner; objects:
+
+ </para>
+
+	<programlisting>
+	env = Environment(SCANNERS = ['CScan', 'M4Scan'])
+	</programlisting>
+
+ <para>
+
+  &Scanner; objects bound to a &consenv; can be
+  associated directly with specified files:
+
+ </para>
+
+	<programlisting>
+	env.CScan('foo.c', 'bar.c')
+	env.M4Scan('input.m4')
+	</programlisting>
+
+ <section>
+  <title>User-defined &Scanner; objects</title>
+
+  <para>
+
+   A user may define a &Scanner; object to scan a type of file for
+   implicit dependencies:
+
+  </para>
+
+	<programlisting>
+	def scanner1(file_contents):
+	        # search for dependencies
+	        return dependency_list
+
+	FirstScan = Scanner(function = scanner1)
+	</programlisting>
+
+  <para>
+
+   The scanner function must return a list of dependencies that its finds
+   based on analyzing the file contents it is passed as an argument.
+
+  </para>
+
+  <para>
+
+   The scanner function, when invoked, will be passed the calling
+   environment.  The scanner function can use &consenvs; from the passed
+   environment to affect how it performs its dependency scan--the
+   canonical example being to use some sort of search-path construction
+   variable to look for dependency files in other directories:
+
+  </para>
+
+	<programlisting>
+	def scanner2(file_contents, env):
+	        path = env.{'SCANNERPATH'}	# XXX
+	        # search for dependencies using 'path'
+	        return dependency_list
+
+	SecondScan = Scanner(function = scanner2)
+	</programlisting>
+
+  <para>
+
+   The user may specify an additional argument when the &Scanner; object
+   is created.  When the scanner is invoked, the additional argument
+   will be passed to the scanner funciton, which can be used in any way
+   the scanner function sees fit:
+
+  </para>
+
+	<programlisting>
+	def scanner3(file_contents, env, arg):
+	        # skip 'arg' lines, then search for dependencies
+	        return dependency_list
+
+	Skip_3_Lines_Scan = Scanner(function = scanner2, argument = 3)
+	Skip_6_Lines_Scan = Scanner(function = scanner2, argument = 6)
+	</programlisting>
+
+ </section>
+
+ <section>
+  <title>Copying &Scanner; Objects</title>
+
+  <para>
+
+   A method exists to return a copy of an existing &Scanner; object,
+   with any overridden values specified as keyword arguments to the
+   method:
+
+  </para>
+
+	<programlisting>
+	scan = Scanner(function = my_scan)
+	scan_path = scan.Copy(path = '%SCANNERPATH')
+	</programlisting>
+
+  <para>
+
+   Typically, &Scanner; objects will be supplied by a tool-master or
+   administrator through a shared &consenv;.
+
+  </para>
+ </section>
+
+ <section>
+  <title>&Scanner; maps</title>
+
+<REMARK>
+If the &BUILDERMAP; proves unnecessary,
+we could/should get rid of this one, too,
+by adding a parallel <literal>input_suffix</literal>
+argument to the &Scanner; factory...
+Comments?
+</REMARK>
+
+  <para>
+
+   Each &consenv; has a &SCANNERMAP;, a dictionary that associates
+   different file suffixes with a scanner object that can be used to
+   generate a list of dependencies from the contents of that file.  This
+   &SCANNERMAP; can be initialized at instantiation:
+
+  </para>
+
+	<programlisting>
+	env = Environment(SCANNERMAP = {
+	                        '.c' : CScan,
+	                        '.cc' : CScan,
+	                        '.m4' : M4Scan,
+	                })
+	</programlisting>
+
+  <para>
+
+   &Scanner; objects referenced in the &SCANNERMAP; do not need to
+   be listed separately in the &SCANNERS; variable.  The &consenv;
+   will bind the union of the &Scanner; objects listed
+   in both variables.
+
+  </para>
+
+ </section>
+
+</section>
+
+
+
+<section id="sect-targets">
+ <title>Targets</title>
+
+ <para>
+
+  The methods in the build engine API described so far merely
+  establish associations that describe file dependencies, how a
+  file should be scanned, etc.  Since the real point is to actually
+  <emphasis>build</emphasis> files, &SCons; also has methods that
+  actually direct the build engine to build, or otherwise manipulate,
+  target files.
+
+ </para>
+
+ <section>
+  <title>Building targets</title>
+  <para>
+
+   One or more targets may be built as follows:
+
+  </para>
+
+	<programlisting>
+	env.Build(target = ['foo', 'bar'])
+	</programlisting>
+
+  <para>
+
+   Note that specifying a directory (or other collective object) will
+   cause all subsidiary/dependent objects to be built as well:
+
+  </para>
+
+	<programlisting>
+	env.Build(target = '.')
+
+	env.Build(target = 'builddir')
+	</programlisting>
+
+  <para>
+
+   By default, &SCons; explicitly removes a target file before
+   invoking the underlying function or command(s) to build it.
+
+  </para>
+ </section>
+
+ <section>
+  <title>Removing targets</title>
+
+  <para>
+
+   A "cleanup" operation of removing generated (target) files is
+   performed as follows:
+
+  </para>
+
+	<programlisting>
+	env.Clean(target = ['foo', 'bar'])
+	</programlisting>
+
+  <para>
+
+   Like the &Build; method, the &Clean; method may be passed a
+   directory or other collective object, in which case the subsidiary
+   target objects under the directory will be removed:
+
+  </para>
+
+	<programlisting>
+	env.Clean(target = '.')
+
+	env.Clean(target = 'builddir')
+	</programlisting>
+
+  <para>
+
+   (The directories themselves are not removed.)
+
+  </para>
+ </section>
+
+ <section>
+  <title>Suppressing build-target removal</title>
+
+  <para>
+
+   As mentioned, by default, &SCons; explicitly removes a target
+   file before invoking the underlying function or command(s) to build
+   it.  Files that should not be removed before rebuilding can be
+   specified via the &Precious; method:
+
+  </para>
+
+	<programlisting>
+	env.Library(target = 'libfoo.a', source = ['aaa.c', 'bbb.c', 'ccc.c'])
+	env.Precious('libfoo.a')
+	</programlisting>
+
+ </section>
+
+ <section>
+  <title>Default targets</title>
+
+  <para>
+
+   The user may specify default targets that will be built if there are no
+   targets supplied on the command line:
+
+  </para>
+
+	<programlisting>
+	env.Default('install', 'src')
+	</programlisting>
+
+  <para>
+
+   Multiple calls to the &Default; method (typically one per &SConscript;
+   file) append their arguments to the list of default targets.
+
+  </para>
+ </section>
+
+ <section>
+  <title>File installation</title>
+
+  <para>
+
+   Files may be installed in a destination directory:
+
+  </para>
+
+	<programlisting>
+	env.Install('/usr/bin', 'program1', 'program2')
+	</programlisting>
+
+  <para>
+
+   Files may be renamed on installation:
+
+  </para>
+
+	<programlisting>
+	env.InstallAs('/usr/bin/xyzzy', 'xyzzy.in')
+	</programlisting>
+
+  <para>
+
+   Multiple files may be renamed on installation by specifying
+   equal-length lists of target and source files:
+
+  </para>
+
+	<programlisting>
+	env.InstallAs(['/usr/bin/foo', '/usr/bin/bar'],
+	                ['foo.in', 'bar.in'])
+	</programlisting>
+
+ </section>
+
+ <section>
+  <title>Target aliases</title>
+
+  <para>
+
+   In order to provide convenient "shortcut" target names that expand to
+   a specified list of targets, aliases may be established:
+
+  </para>
+
+	<programlisting>
+	env.Alias(alias = 'install',
+	          targets = ['/sbin', '/usr/lib', '/usr/share/man'])
+	</programlisting>
+
+  <para>
+
+   In this example, specifying a target of <literal>install</literal>
+   will cause all the files in the associated directories to be built
+   (that is, installed).
+
+  </para>
+
+  <para>
+
+   An &Alias; may include one or more other &Aliases; in its list:
+
+  </para>
+
+	<programlisting>
+	env.Alias(alias = 'libraries', targets = ['lib'])
+	env.Alias(alias = 'programs', targets = ['libraries', 'src'])
+	</programlisting>
+
+ </section>
+
+</section>
+
+
+
+<section id="sect-custom">
+ <title>Customizing output</title>
+
+<REMARK>
+Take this whole section with a grain of salt.
+I whipped it up without a great deal of thought
+to try to add a "competitive advantage"
+for the second round of the Software Carpentry contest.
+In particular, hard-coding the
+analysis points and the keywords that specify them
+feels inflexible,
+but I can't think of another way it would be
+done effectively.
+I dunno, maybe this is fine as it is...
+</REMARK>
+
+ <para>
+
+  The &SCons; API supports the ability to customize, redirect, or
+  suppress its printed output through user-defined functions.
+  &SCons; has several pre-defined points in its build process at
+  which it calls a function to (potentially) print output.  User-defined
+  functions can be specified for these call-back points when &Build;
+  or &Clean;is invoked:
+
+ </para>
+
+	<programlisting>
+	env.Build(target = '.',
+	       on_analysis = dump_dependency,
+	       pre_update = my_print_command,
+	       post_update = my_error_handler)
+	       on_error = my_error_handler)
+	</programlisting>
+
+ <para>
+
+  The specific call-back points are:
+
+ </para>
+
+ <variablelist>
+
+  <varlistentry>
+   <term><literal>on_analysis</literal></term>
+   <listitem>
+    <para>
+
+     Called for every object, immediately after the object has been
+     analyzed to see if it's out-of-date.  Typically used to print a
+     trace of considered objects for debugging of unexpected dependencies.
+
+    </para>
+   </listitem>
+  </varlistentry>
+
+  <varlistentry>
+   <term><literal>pre_update</literal></term>
+   <listitem>
+    <para>
+
+     Called for every object that has been determined to be out-of-date
+     before its update function or command is executed.  Typically used
+     to print the command being called to update a target.
+
+    </para>
+   </listitem>
+  </varlistentry>
+
+  <varlistentry>
+   <term><literal>post_update</literal></term>
+   <listitem>
+    <para>
+
+     Called for every object after its update function or command has
+     been executed.  Typically used to report that a top-level specified
+     target is up-to-date or was not remade.
+
+    </para>
+   </listitem>
+  </varlistentry>
+
+  <varlistentry>
+   <term><literal>on_error</literal></term>
+   <listitem>
+    <para>
+
+     Called for every error returned by an update function or command.
+     Typically used to report errors with some string that will be
+     identifiable to build-analysis tools.
+
+    </para>
+   </listitem>
+  </varlistentry>
+
+ </variablelist>
+
+ <para>
+
+  Functions for each of these call-back points all take the same
+  arguments:
+
+ </para>
+
+	<programlisting>
+	my_dump_dependency(target, level, status, update, dependencies)
+	</programlisting>
+
+ <para>
+
+  where the arguments are:
+
+ </para>
+
+ <variablelist>
+
+  <varlistentry>
+   <term><literal>target</literal></term>
+   <listitem>
+    <para>
+
+     The target object being considered.
+
+    </para>
+   </listitem>
+  </varlistentry>
+
+  <varlistentry>
+   <term><literal>level</literal></term>
+   <listitem>
+    <para>
+
+     Specifies how many levels the dependency analysis has
+     recursed in order to consider the <literal>target</literal>.
+     A value of <literal>0</literal> specifies a top-level
+     <literal>target</literal> (that is, one passed to the
+     &Build; or &Clean; method).  Objects which a top-level
+     <literal>target</literal> is directly dependent upon have a
+     <literal>level</literal> of <1>, their direct dependencies have a
+     <literal>level</literal> of <2>, etc.  Typically used to indent
+     output to reflect the recursive levels.
+
+    </para>
+   </listitem>
+  </varlistentry>
+
+  <varlistentry>
+   <term><literal>status</literal></term>
+   <listitem>
+    <para>
+
+     A string specifying the current status of the target
+     (<literal>"unknown"</literal>, <literal>"built"</literal>,
+     <literal>"error"</literal>, <literal>"analyzed"</literal>, etc.).  A
+     complete list will be enumerated and described during implementation.
+
+    </para>
+   </listitem>
+  </varlistentry>
+
+  <varlistentry>
+   <term><literal>update</literal></term>
+   <listitem>
+    <para>
+
+     The command line or function name that will be (or has been) executed
+     to update the <literal>target</literal>.
+
+    </para>
+   </listitem>
+  </varlistentry>
+
+  <varlistentry>
+   <term><literal>dependencies</literal></term>
+   <listitem>
+    <para>
+
+     A list of direct dependencies of the target.
+
+    </para>
+   </listitem>
+  </varlistentry>
+
+ </variablelist>
+
+</section>
+
+
+
+<section id="separate">
+ <title>Separate source and build trees</title>
+
+<REMARK>
+I've never liked Cons' use of the name <literal>Link</literal>
+for this functionality,
+mainly because the term is overloaded
+with linking object files into an executable.
+Yet I've never come up with anything better.
+Any suggestions?
+</REMARK>
+
+<REMARK>
+Also, I made this an &Environment; method because
+it logically belongs in the API reference
+(the build engine needs to know about it),
+and I thought it was clean to have
+everything in the build-engine API
+be called through an &Environment; object.
+But <literal>&Link</literal> isn't really
+associated with a specific environment
+(the &Cons; classic implementation just
+leaves it as a bare function call),
+so maybe we should just follow that example
+and not call it through an environment...
+</REMARK>
+
+ <para>
+
+  &SCons; allows target files to be built completely separately from
+  the source files by "linking" a build directory to an underlying
+  source directory:
+
+ </para>
+
+	<programlisting>
+	env.Link('build', 'src')
+
+	SConscript('build/SConscript')
+	</programlisting>
+
+ <para>
+
+  &SCons; will copy (or hard link) necessary files (including the
+  &SConscript; file) into the build directory hierarchy.  This allows the
+  source directory to remain uncluttered by derived files.
+
+ </para>
+
+</section>
+
+