From 8d95338eb2088c3d36a1dbd981b72833067e34bd Mon Sep 17 00:00:00 2001 From: stevenknight Date: Fri, 10 Aug 2001 09:55:19 +0000 Subject: [PATCH] Add design documentation. git-svn-id: http://scons.tigris.org/svn/scons/trunk@20 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- Construct | 9 + doc/.aeignore | 4 + doc/Conscript | 77 ++ doc/copyright.sgml | 20 + doc/design/.aeignore | 3 + doc/design/acks.sgml | 160 ++++ doc/design/bground.sgml | 67 ++ doc/design/engine.fig | 179 ++++ doc/design/engine.jpg | Bin 0 -> 41222 bytes doc/design/engine.sgml | 1888 ++++++++++++++++++++++++++++++++++++++ doc/design/goals.sgml | 189 ++++ doc/design/install.sgml | 9 + doc/design/intro.sgml | 92 ++ doc/design/issues.sgml | 176 ++++ doc/design/main.sgml | 117 +++ doc/design/native.sgml | 343 +++++++ doc/design/overview.sgml | 479 ++++++++++ doc/scons.mod | 129 +++ 18 files changed, 3941 insertions(+) create mode 100644 doc/.aeignore create mode 100644 doc/Conscript create mode 100644 doc/copyright.sgml create mode 100644 doc/design/.aeignore create mode 100644 doc/design/acks.sgml create mode 100644 doc/design/bground.sgml create mode 100644 doc/design/engine.fig create mode 100644 doc/design/engine.jpg create mode 100644 doc/design/engine.sgml create mode 100644 doc/design/goals.sgml create mode 100644 doc/design/install.sgml create mode 100644 doc/design/intro.sgml create mode 100644 doc/design/issues.sgml create mode 100644 doc/design/main.sgml create mode 100644 doc/design/native.sgml create mode 100644 doc/design/overview.sgml create mode 100644 doc/scons.mod diff --git a/Construct b/Construct index 06dd833f..6fe36338 100644 --- a/Construct +++ b/Construct @@ -90,6 +90,15 @@ Export qw( env test_dir ); 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, diff --git a/doc/.aeignore b/doc/.aeignore new file mode 100644 index 00000000..103da1c0 --- /dev/null +++ b/doc/.aeignore @@ -0,0 +1,4 @@ +*,D +.*.swp +.consign +version.sgml diff --git a/doc/Conscript b/doc/Conscript new file mode 100644 index 00000000..28418157 --- /dev/null +++ b/doc/Conscript @@ -0,0 +1,77 @@ +# +# +# + +Import qw( + date + env + revision + version +); + +# +$verfile = SourcePath("version.sgml"); +open(FILE, ">$verfile") || die "Cannot open '$verfile': $!"; +print FILE <<_EOF_; + + + + +_EOF_ +close(FILE); + +Ignore("#$verfile"); + +# +# +# + +@doc_dirs = qw( + design +); + +# Find internal dependencies in .sgml files: +# +# +# +# +# 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 (//i) { + push(@includes, $1); + } elsif (/]*\sfileref="([^"]*)"/) { + push(@includes, "design/$1"); + } + } while (); + @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), + ]); +} diff --git a/doc/copyright.sgml b/doc/copyright.sgml new file mode 100644 index 00000000..a4583aeb --- /dev/null +++ b/doc/copyright.sgml @@ -0,0 +1,20 @@ + + +
+ + + 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 + + http://www.software-carpentry.com/openpub-license.html + . + + +
diff --git a/doc/design/.aeignore b/doc/design/.aeignore new file mode 100644 index 00000000..872e8be6 --- /dev/null +++ b/doc/design/.aeignore @@ -0,0 +1,3 @@ +*,D +.*.swp +.consign diff --git a/doc/design/acks.sgml b/doc/design/acks.sgml new file mode 100644 index 00000000..75f0cbf8 --- /dev/null +++ b/doc/design/acks.sgml @@ -0,0 +1,160 @@ + + + + + I'm grateful to the following people + for their influence, knowing or not, + on the design of &SCons;: + + + + + + Bob Sidebotham + + + + 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. + + + + + + + The &SCons; Development Team + + + + 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. + + + + + + + The &Cons; Community + + + + The real-world build problems that the users of &Cons; + share on the cons-discuss 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. + + + + + + + Peter Miller + + + + + Peter has indirectly + influenced two aspects of the &SCons; design: + + + + + + Miller's influential paper + Recursive Make Considered Harmful + was what led me, indirectly, to my involvement with &Cons; + in the first place. + Experimenting with the single-Makefile approach he describes in + RMCH 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. + + + + + + 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 cons-test regression suite. + + + + + + + Stuart Stanley + + + + An experienced Python programmer, + Stuart provided valuable advice and insight + into some of the more useful Python idioms at my disposal + during the original ScCons; design + for the Software Carpentry contest. + + + + + + + Gary Holt + + + + 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. + + + + + + diff --git a/doc/design/bground.sgml b/doc/design/bground.sgml new file mode 100644 index 00000000..dfdb6c8e --- /dev/null +++ b/doc/design/bground.sgml @@ -0,0 +1,67 @@ + + + + + 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. + + + + + + &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. + + + + + + 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 cons-discuss mailing list. The Software + Carpentry contest provided the right motivation to spend some + actual time working on a design document. + + + + + + After two rounds of competition, the submitted design, named + ScCons, 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. + + + + + + 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. + + diff --git a/doc/design/engine.fig b/doc/design/engine.fig new file mode 100644 index 00000000..90f3d4f8 --- /dev/null +++ b/doc/design/engine.fig @@ -0,0 +1,179 @@ +#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 diff --git a/doc/design/engine.jpg b/doc/design/engine.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1e0112a286fd1bb26a0217ca5ef4a462d8cbbf55 GIT binary patch literal 41222 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 + +

+ General Principles + +
+ Keyword arguments + + + + 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 foo (or + foo.exe on a Win32 system) to be compiled from + the foo.c source file: + + + + + env.Program(target = 'foo', source = 'foo.c') + + env.Program('foo', 'foo.c') + + +
+ +
+ Internal object representation + + + + All methods and functions use internal (Python) objects that + represent the external objects (files, for example) for which they + perform dependency analysis. + + + + + + All methods and functions in this API that accept an external object + as an argument will accept either a string + description or an object reference. For example, the two following + two-line examples are equivalent: + + + + + 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 + + +
+ +
+ + + +
+ &ConsEnvs + + + + A &consenv; is the basic means by which a software system interacts + with the &SCons; Python API to control a build process. + + + + + + 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. + + + + + + Passing no arguments to the &Environment; instantiation creates a + &consenv; with default values for the current platform: + + + + + env = Environment() + + +
+ &Consvars; + + + + 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;. + + + 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. + + + At a minimum, there will be pre-configured sets of default values + that will provide reasonable defaults for UNIX and Windows NT. + + + + + + The default &consenv; values may be overridden when a new &consenv; is + created by specifying keyword arguments: + + + + + env = Environment(CC = 'gcc', + CCFLAGS = '-g', + CPPPATH = ['.', 'src', '/usr/include'], + LIBPATH = ['/usr/lib', '.']) + + +
+ +
+ Fetching &consvars; + + + + A copy of the dictionary of &consvars; can be returned using + the &Dictionary; method: + + + + + env = Environment() + dict = env.Dictionary() + + + +In the current source code, I implemented this as a dictionary attribute +named Dictionary. 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 _dict +attribute and control access to it through a method, as specified above. + + + + + If any arguments are supplied, then just the corresponding value(s) + are returned: + + + + + ccflags = env.Dictionary('CCFLAGS') + cc, ld = env.Dictionary('CC', 'LD') + + +
+ +
+ Copying a &consenv; + + + + A method exists to return a copy of an existing environment, with + any overridden values specified as keyword arguments to the method: + + + + + env = Environment() + debug = env.Copy(CCFLAGS = '-g') + + +
+ +
+ Multiple &consenvs; + + + + Different external objects often require different build + characteristics. Multiple &consenvs; may be defined, each with + different values: + + + + + env = Environment(CCFLAGS = '') + debug = Environment(CCFLAGS = '-g') + env.Make(target = 'hello', source = 'hello.c') + debug.Make(target = 'hello-debug', source = 'hello.c') + + + + + 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: + + + + + env1 = Environment(CCFLAGS = '-O', LDFLAGS = '-d') + env2 = Environment(CCFLAGS = '-g') + new = Environment(env1.Dictionary(), env2.Dictionary()) + + + + + The new environment in the above example retains + LDFLAGS = '-d' from the env1 + environment, and CCFLAGS = '-g' from the + env2 environment. + + + + + +
+ +
+ Variable substitution + + + + Within a construction command, any variable from the &consenv; may + be interpolated by prefixing the name of the construction with + $: + + + + + MyBuilder = Builder(command = "$XX $XXFLAGS -c $_INPUTS -o $target") + + env.Command(targets = 'bar.out', sources = 'bar.in', + command = "sed '1d' < $source > $target") + + + + + Variable substitution is recursive: the command line is expanded + until no more substitutions can be made. + + + + + + Variable names following the $ may be enclosed in + braces. This can be used to concatenate an interpolated value with an + alphanumeric character: + + + + + VerboseBuilder = Builder(command = "$XX -${XXFLAGS}v > $target") + + + + + The variable within braces may contain a pair of parentheses + after a Python function name to be evaluated (for example, + ${map()}). &SCons; will interpolate the return + value from the function (presumably a string): + + + + + env = Environment(FUNC = myfunc) + env.Command(target = 'foo.out', source = 'foo.in', + command = "${FUNC($<)}") + + + + + If a referenced variable is not defined in the &consenv;, + the null string is interpolated. + + + + + + The following special variables can also be used: + + + + + + + $targets + + + + All target file names. If multiple targets are specified in an + array, $targets expands to the entire list of + targets, separated by a single space. + + + + + + Individual targets from a list may be extracted by enclosing + the targets keyword in braces and using the + appropriate Python array index or slice: + + + + + ${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 + + + + + + + $target + + + + A synonym for ${targets[0]}, the first target + specified. + + + + + + + $sources + + + + All input file names. Any input file names that + are used anywhere else on the current command + line (via ${sources[0]}, + ${sources{[1]}, etc.) are removed from the + expanded list. + + + + + + + + + + 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: + + + + + + + .base + + + + Basename: the directory plus the file name, minus any file suffix. + + + + + + + .dir + + + + The directory in which the file lives. This is a relative path, + where appropriate. + + + + + + + .file + + + + The file name, minus any directory portion. + + + + + + + .suffix + + + + The file name suffix (that is, the right-most dot in the file name, + and all characters to the right of that). + + + + + + + .filebase + + + + The file name (no directory portion), minus any file suffix. + + + + + + + .abspath + + + + The absolute path to the file. + + + + + + + +
+ +
+ + + +
+ &Builder; Objects + + + + By default, &SCons; supplies (and uses) a number of pre-defined + &Builder; objects: + + + + + + + + + &Object; + compile or assemble an object file + + + + &Library; + archive files into a library + + + + &SharedLibrary; + archive files into a shared library + + + + &Program; + link objects and/or libraries into an executable + + + + &MakeBuilder; + build according to file suffixes; see below + + + + + + + +&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? + + + + + A &consenv; can be explicitly initialized with associated &Builder; + objects that will be bound to the &consenv; object: + + + + + env = Environment(BUILDERS = ['Object', 'Program']) + + + + + &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: + + + + + 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']) + + +
+ Specifying multiple inputs + + + + 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: + + + + + 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') + + + + + 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: + + + + + 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']) + + + + + Individual string elements within an array of input files are + not 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: + + + env.Program(target = 'foo', source = ['an input file.c']) + + + + +
+ +
+ Specifying multiple targets + + + + Conversely, the generated target may be a string listing multiple + files separated by white space: + + + + + env.Object(target = 'grammar.o y.tab.h', source = 'grammar.y') + + + + + An array of multiple target files can be used to mix string and object + representations, or to accomodate file names that contain white space: + + + + + env.Program(target = ['my program'], source = 'input.c') + + +
+ +
+ File prefixes and suffixes + + + + 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: + + + + + # 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']) + + +
+ +
+ &Builder; object exceptions + + + + &Builder; objects raise the following exceptions on error: + + + LIST THESE ONCE WE FIGURE OUT WHAT THEY ARE FROM CODING THEM. + + + +
+ +
+ User-defined &Builder; objects + + + + 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: + + + + + WebPage = Builder(command = 'htmlgen $HTMLGENFLAGS $sources > $target', + input_suffix = '.in', + output_suffix = '.html') + + + + + Alternatively, a &Builder; object may also build its target by + executing a Python function: + + + + + def update(dest): + # [code to update the object] + return 1 + + OtherBuilder1 = Builder(function = update, + input_suffix = ['.in', '.input']) + + + + + An optional argument to pass to the function may be specified: + + + + + def update_arg(dest, arg): + # [code to update the object] + return 1 + + OtherBuilder2 = Builder(function = update_arg, + function_arg = 'xyzzy', + input_suffix = ['.in', '.input']) + + + + + 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. + + + + + NEED AN EXAMPLE HERE. + + + + + User-defined &Builder; objects can be used like the default &Builder; + objects to initialize &consenvs;. + + + + + 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') + + + + + The command-line specification can interpolate variables from the + &consenv;; see "Variable substitution," above. + + + + + + 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. + + +
+ +
+ Copying &Builder; Objects + + + + A &Copy; method exists to return a copy of an existing &Builder; + object, with any overridden values specified as keyword arguments to + the method: + + + + + build = Builder(function = my_build) + build_out = build.Copy(output_suffix = '.out') + + + + + Typically, &Builder; objects will be supplied by a tool-master or + administrator through a shared &consenv;. + + +
+ +
+ Special-purpose build rules + + + + A pre-defined &Command; builder exists to associate a target file with + a specific command or list of commands for building the file: + + + + + 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) + + + + This is useful when it's too cumbersome to create a &Builder; + object just to build a single file in a special way. + + +
+ +
+ The &MakeBuilder; &Builder; + + + + 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. + + + + + + The following minimal example builds the 'hello' program from the + 'hello.c' source file: + + + + + Environment().Make('hello', 'hello.c') + + + + + 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: + + + + + env = Environment() + env.Make(target = 'hello.o', source = 'hello.c') + env.Make(target = 'hello', source = 'hello.o') + + + + + 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. + + + + + + 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 + hello.exe on Windows NT. + + + +
+ +
+ &Builder; maps + + +Do we even need this anymore? +Now that the individual builders +have specified input_suffix +and output_suffix 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 suffix arguments. +If you want &MakeBuilder; to do something different, +you set it up with another environment... + + + + + The env.Make 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: + + + + + env = Environment(BUILDERMAP = { + '.o' : Object, + '.a' : Library, + '.html' : WebPage, + '' : Program, + }) + + + + + With the &BUILDERMAP; properly initialized, the + env.Make method can be used to build additional + file types: + + + + + env.Make(target = 'index.html', source = 'index.input') + + + + + &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. + + + + + +
+ +
+ + + +
+ Dependencies + +
+ Automatic dependencies + + + + By default, &SCons; assumes that a target file has automatic + dependencies on the: + + + +
+ + + tool used to build the target file + + contents of the input files + + command line used to build the target file + + +
+ + + + If any of these changes, the target file will be rebuilt. + + +
+ +
+ Implicit dependencies + + + + Additionally, &SCons; can scan the contents of files for + implicit dependencies on other files. For + example, &SCons; will scan the contents of a .c + file and determine that any object created from it is + dependent on any .h files specified via + #include. &SCons;, therefore, "does the right + thing" without needing to have these dependencies listed explicitly: + + + + + % 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! + % + + +
+ +
+ Ignoring dependencies + + + + Undesirable automatic dependencies or + implicit dependencies may be ignored: + + + + + env.Program(target = 'bar', source = 'bar.c') + env.Ignore('bar', '/usr/bin/gcc', 'version.h') + + + + + In the above example, the bar program will not + be rebuilt if the /usr/bin/gcc compiler or the + version.h file change. + + +
+ +
+ Explicit dependencies + + + + Dependencies that are unknown to &SCons; may be specified explicitly + in an &SCons; configuration file: + + + + + 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') + + + + + Just like the target keyword argument, the + dependency keyword argument may be specified as a + string of white-space separated file names, or as an array. + + + + + + A dependency on an &SCons; configuration file itself may be specified + explicitly to force a rebuild whenever the configuration file changes: + + + + + env.Dependency(target = 'archive.tar.gz', dependency = 'SConstruct') + + +
+ +
+ + + +
+ &Scanner; Objects + + + + Analagous to the previously-described &Builder; objects, &SCons; + supplies (and uses) &Scanner; objects to search the contents of + a file for implicit dependency files: + + + + + + + + + CScan + scan .{c,C,cc,cxx,cpp} files for #include dependencies + + + + + + + + + A &consenv; can be explicitly initialized with + associated &Scanner; objects: + + + + + env = Environment(SCANNERS = ['CScan', 'M4Scan']) + + + + + &Scanner; objects bound to a &consenv; can be + associated directly with specified files: + + + + + env.CScan('foo.c', 'bar.c') + env.M4Scan('input.m4') + + +
+ User-defined &Scanner; objects + + + + A user may define a &Scanner; object to scan a type of file for + implicit dependencies: + + + + + def scanner1(file_contents): + # search for dependencies + return dependency_list + + FirstScan = Scanner(function = scanner1) + + + + + The scanner function must return a list of dependencies that its finds + based on analyzing the file contents it is passed as an argument. + + + + + + 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: + + + + + def scanner2(file_contents, env): + path = env.{'SCANNERPATH'} # XXX + # search for dependencies using 'path' + return dependency_list + + SecondScan = Scanner(function = scanner2) + + + + + 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: + + + + + 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) + + +
+ +
+ Copying &Scanner; Objects + + + + A method exists to return a copy of an existing &Scanner; object, + with any overridden values specified as keyword arguments to the + method: + + + + + scan = Scanner(function = my_scan) + scan_path = scan.Copy(path = '%SCANNERPATH') + + + + + Typically, &Scanner; objects will be supplied by a tool-master or + administrator through a shared &consenv;. + + +
+ +
+ &Scanner; maps + + +If the &BUILDERMAP; proves unnecessary, +we could/should get rid of this one, too, +by adding a parallel input_suffix +argument to the &Scanner; factory... +Comments? + + + + + 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: + + + + + env = Environment(SCANNERMAP = { + '.c' : CScan, + '.cc' : CScan, + '.m4' : M4Scan, + }) + + + + + &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. + + + +
+ +
+ + + +
+ Targets + + + + 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 + build files, &SCons; also has methods that + actually direct the build engine to build, or otherwise manipulate, + target files. + + + +
+ Building targets + + + One or more targets may be built as follows: + + + + + env.Build(target = ['foo', 'bar']) + + + + + Note that specifying a directory (or other collective object) will + cause all subsidiary/dependent objects to be built as well: + + + + + env.Build(target = '.') + + env.Build(target = 'builddir') + + + + + By default, &SCons; explicitly removes a target file before + invoking the underlying function or command(s) to build it. + + +
+ +
+ Removing targets + + + + A "cleanup" operation of removing generated (target) files is + performed as follows: + + + + + env.Clean(target = ['foo', 'bar']) + + + + + 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: + + + + + env.Clean(target = '.') + + env.Clean(target = 'builddir') + + + + + (The directories themselves are not removed.) + + +
+ +
+ Suppressing build-target removal + + + + 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: + + + + + env.Library(target = 'libfoo.a', source = ['aaa.c', 'bbb.c', 'ccc.c']) + env.Precious('libfoo.a') + + +
+ +
+ Default targets + + + + The user may specify default targets that will be built if there are no + targets supplied on the command line: + + + + + env.Default('install', 'src') + + + + + Multiple calls to the &Default; method (typically one per &SConscript; + file) append their arguments to the list of default targets. + + +
+ +
+ File installation + + + + Files may be installed in a destination directory: + + + + + env.Install('/usr/bin', 'program1', 'program2') + + + + + Files may be renamed on installation: + + + + + env.InstallAs('/usr/bin/xyzzy', 'xyzzy.in') + + + + + Multiple files may be renamed on installation by specifying + equal-length lists of target and source files: + + + + + env.InstallAs(['/usr/bin/foo', '/usr/bin/bar'], + ['foo.in', 'bar.in']) + + +
+ +
+ Target aliases + + + + In order to provide convenient "shortcut" target names that expand to + a specified list of targets, aliases may be established: + + + + + env.Alias(alias = 'install', + targets = ['/sbin', '/usr/lib', '/usr/share/man']) + + + + + In this example, specifying a target of install + will cause all the files in the associated directories to be built + (that is, installed). + + + + + + An &Alias; may include one or more other &Aliases; in its list: + + + + + env.Alias(alias = 'libraries', targets = ['lib']) + env.Alias(alias = 'programs', targets = ['libraries', 'src']) + + +
+ +
+ + + +
+ Customizing output + + +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... + + + + + 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: + + + + + env.Build(target = '.', + on_analysis = dump_dependency, + pre_update = my_print_command, + post_update = my_error_handler) + on_error = my_error_handler) + + + + + The specific call-back points are: + + + + + + + on_analysis + + + + 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. + + + + + + + pre_update + + + + 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. + + + + + + + post_update + + + + 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. + + + + + + + on_error + + + + 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. + + + + + + + + + + Functions for each of these call-back points all take the same + arguments: + + + + + my_dump_dependency(target, level, status, update, dependencies) + + + + + where the arguments are: + + + + + + + target + + + + The target object being considered. + + + + + + + level + + + + Specifies how many levels the dependency analysis has + recursed in order to consider the target. + A value of 0 specifies a top-level + target (that is, one passed to the + &Build; or &Clean; method). Objects which a top-level + target is directly dependent upon have a + level of <1>, their direct dependencies have a + level of <2>, etc. Typically used to indent + output to reflect the recursive levels. + + + + + + + status + + + + A string specifying the current status of the target + ("unknown", "built", + "error", "analyzed", etc.). A + complete list will be enumerated and described during implementation. + + + + + + + update + + + + The command line or function name that will be (or has been) executed + to update the target. + + + + + + + dependencies + + + + A list of direct dependencies of the target. + + + + + + + +
+ + + +
+ Separate source and build trees + + +I've never liked Cons' use of the name Link +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? + + + +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 &Link 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... + + + + + &SCons; allows target files to be built completely separately from + the source files by "linking" a build directory to an underlying + source directory: + + + + + env.Link('build', 'src') + + SConscript('build/SConscript') + + + + + &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. + + + +
+ + + +
+ Variant builds + + + + The &Link; method may be used in conjunction with multiple + &consenvs; to support variant builds. The following + &SConstruct; and &SConscript; files would build separate debug and + production versions of the same program side-by-side: + + + + + % cat SConstruct + env = Environment() + env.Link('build/debug', 'src') + env.Link('build/production', 'src') + flags = '-g' + SConscript('build/debug/SConscript', Export(env)) + flags = '-O' + SConscript('build/production/SConscript', Export(env)) + % cat src/SConscript + env = Environment(CCFLAGS = flags) + env.Program('hello', 'hello.c') + + + + + The following example would build the appropriate program for the current + compilation platform, without having to clean any directories of object + or executable files for other architectures: + + + + + % cat SConstruct + build_platform = os.path.join('build', sys.platform) + Link(build_platform, 'src') + SConscript(os.path.join(build_platform, 'SConscript')) + % cat src/SConscript + env = Environment + env.Program('hello', 'hello.c') + + +
+ + + +
+ Code repositories + + +Like &Link;, &Repository; and &Local; are part of the +API reference, but not really tied to any specific environment. +Is it better to be consistent about calling +everything in the API through an environment, +or to leave these independent so as +not to complicate their calling interface? + + + + + &SCons; may use files from one or more shared code repositories in order + to build local copies of changed target files. A repository would + typically be a central directory tree, maintained by an integrator, + with known good libraries and executables. + + + + + Repository('/home/source/1.1', '/home/source/1.0') + + + + + Specified repositories will be searched in-order for any file + (configuration file, input file, target file) that does not exist + in the local directory tree. When building a local target file, + &SCons; will rewrite path names in the build command to use the + necessary repository files. This includes modifying lists of + or flags to specify an + appropriate set of include paths for dependency analysis. + + + + + &SCons; will modify the Python sys.path variable to + reflect the addition of repositories to the search path, so that any + imported modules or packages necessary for the build can be found in a + repository, as well. + + + + + If an up-to-date target file is found in a code repository, the file + will not be rebuilt or copied locally. Files that must exist locally + (for example, to run tests) may be specified: + + + + + Local('program', 'libfoo.a') + + + + + in which case &SCons; will copy or link an up-to-date copy of the + file from the appropriate repository. + + + +
+ + + +
+ Derived-file caching + + +There should be extensions to this part of the API for +auxiliary functions like cleaning the cache. + + + + + &SCons; can maintain a cache directory of target files which may be + shared among multiple builds. This reduces build times by allowing + developers working on a project together to share common target + files: + + + + + Cache('/var/tmp/build.cache/i386') + + + + + When a target file is generated, a copy is added to the cache. + When generating a target file, if &SCons; determines that a file + that has been built with the exact same dependencies already exists + in the specified cache, &SCons; will copy the cached file rather + than re-building the target. + + + + + Command-line options exist to modify the &SCons; caching behavior + for a specific build, including disabling caching, building + dependencies in random order, and displaying commands as if cached + files were built. + + + +
+ + + +
+ Job management + + +This has been completely superseded by +the more sophisticated &Task; manager +that Anthony Roach has contributed. +I need to write that up... + + + + + A simple API exists to inform the Build Engine how many jobs may + be run simultaneously: + + + + + Jobs(limit = 4) + + +
diff --git a/doc/design/goals.sgml b/doc/design/goals.sgml new file mode 100644 index 00000000..d894fe75 --- /dev/null +++ b/doc/design/goals.sgml @@ -0,0 +1,189 @@ + + + + + As a next-generation build tool, + &SCons should fundamentally + improve on its predecessors. + Rather than simply being driven by trying to + not be like previous tools, + &SCons; aims to satisfy the following goals: + + + + + + + Practicality + + + + The &SCons; design emphasizes + an implementable feature set + that lets users get practical, useful work done. + &SCons; is helped in this regard by its roots in &Cons;, + which has had its feature set honed by + several years of input + from a dedicated band of users. + + + + + + + Portability + + + + &SCons; is intended as a portable build tool, + able to handle software construction tasks + on a variety of operating systems. + It should be possible (although not mandatory) + to use &SCons; so that the same configuration file + builds the same software correctly on, + for example, both Linux and Windows NT. + Consequently, &SCons; should hide from users + operating-system-dependent details + such as filename extensions + (for example, .o + vs. .obj). + + + + + + + + + + + Usability + + + + Novice users should be able to grasp quickly + the rudiments of using &SCons; to build their software. + This extends to installing &SCons;, too. + Installation should be painless, + and the installed &SCons; + should work "out of the box" + to build most software. + + + + + + This goal should be kept in mind during implementation, + when there is always a tendency to try to optimize too early. + Speed is nice, but not as important as clarity + and ease of use. + + + + + + + Utility + + + + &SCons; should also provide a rich enough set of features + to accommodate building more complicated software projects. + However, the features required for + building complicated software projects + should not get in the way of novice users. + (See the previous goal.) + In other words, complexity should be available + when it's needed + but not required to get work done. + Practically, this implies that &SCons; + shouldn't be dumbed down to the point it + excludes complicated software builds. + + + + + + + Sharability + + + + As a key element in balancing the conflicting + needs of Usability and Utility, + &SCons; should provide mechanisms to + allow &SCons; users to share build rules, + dependency scanners, and other objects and recipes + for constructing software. + A good sharing mechanism should support + the model wherein most developers on a project + use rules and templates + that are created + and maintained by a local integrator or build-master, + + + + + + + Extensibility + + + + &SCons; should provide mechanisms for + easily extending its capabilities, + including building new types of files, + adding new types of dependency scanning, + being able to accomodate dependencies + between objects other than files, + etc. + + + + + + + Flexibility + + + + In addition to providing a useful command-line interface, + &SCons; should provide the right architectural + framework for embedding its dependency management + in other interfaces. + &SCons; would help strengthen other GUIs or IDEs + and the additional requirements of the + other interfaces would help broaden and solidify + the core &SCons; dependency management. + + + + + + + +
+ Fixing &Make;'s problems + + +To be written. + + +
+ +
+ Fixing &Cons;'s problems + + +To be written. + + +
diff --git a/doc/design/install.sgml b/doc/design/install.sgml new file mode 100644 index 00000000..4d03d11b --- /dev/null +++ b/doc/design/install.sgml @@ -0,0 +1,9 @@ + + + +THIS CHAPTER NEEDS TO BE DISCUSSED AND WRITTEN. + diff --git a/doc/design/intro.sgml b/doc/design/intro.sgml new file mode 100644 index 00000000..1d808499 --- /dev/null +++ b/doc/design/intro.sgml @@ -0,0 +1,92 @@ + + + + + The &SCons; tool provides an easy-to-use, feature-rich interface + for constructing software. Architecturally, &SCons; separates + its dependency analysis and external object management into an + interface-independent Build Engine that could be embedded in any + software system that can run Python. + + + + + + At the command line, &SCons; presents an easily-grasped tool + where configuration files are Python scripts, reducing the need + to learn new build-tool syntax. Inexperienced users can use + intelligent methods that ``do the right thing'' to build software + with a minimum of fuss. Sophisticated users can use a rich set + of underlying features for finer control of the build process, + including mechanisms for easily extending the build process to new + file types. + + + + + + Dependencies are tracked using digital signatures, + which provide more robust dependency analysis than file time + stamps. Implicit dependencies are determined automatically by + scanning the contents of source files, avoiding the need for + laborious and fragile maintenance of static lists of dependencies in + configuration files. + + + + + + The &SCons; tool supports use of files from one or more central code + repositories, a mechanism for caching derived files, and parallel + builds. The tool also includes a framework for sharing build + environments, which allows system administrators or integrators to + define appropriate build parameters for use by other users. + + + +
+ About This Document + + + + This document is an ongoing work-in-progress to write down the ideas + and tradeoffs that have gone, and will go into, the &SCons; design. + As such, this is intended primarily for use by developers and others + working on &SCons;, although it is also intended to serve as a + detailed overview of &SCons; for other interested parties. It will + be continually updated and evolve, and will likely overlap with other + documentation produced by the project. Sections of this document + that deal with syntax, for example, may move or be copied into a user + guide or reference manual. + + + + + + So please don't assume that everything mentioned here has been + decided and carved in stone. If you have ideas for improvements, or + questions about things that don't seem to make any sense, please help + improve the design by speaking up about them. + + + + +Sections marked like this +(prefixed with RATIONALE: in the HTML, +surrounded by BEGIN RATIONALE: +and END RATIONALE: +in the printed documentatio) +are DocBook REMARKs, +comments about the document +rather than actual document. +I've used these to mark sections that need work, +but also to cite some open design issues. +If you have input on any of these marked issues, +I'm especially eager to hear it. + + +
diff --git a/doc/design/issues.sgml b/doc/design/issues.sgml new file mode 100644 index 00000000..6772c834 --- /dev/null +++ b/doc/design/issues.sgml @@ -0,0 +1,176 @@ + + + + No build tools is perfect. + Here are some &SCons; issues that + do not yet have solutions. + + + +
+ Interaction with SC-config + + + + The SC-config tool will be used in the &SCons; installation + process to generate an appropriate default construction environment + so that building most software works "out of the box" on the + installed platform. The SC-config tool will find reasonable default + compilers (C, C++, Fortran), linkers/loaders, library archive tools, + etc. for specification in the default &SCons; construction + environment. + + + +
+ +
+ Interaction with test infrastructures + + + + &SCons; can be configured to use SC-test (or some other test tool) + to provide controlled, automated testing of software. The &Link; + method could link a test subdirectory to a build + subdirectory: + + + + + Link('test', 'build') + SConscript('test/SConscript') + + + + Any test cases checked in with the source code will be linked + into the test subdirectory and executed. If + &SConscript; files and test cases are written with this in mind, then + invoking: + + + + + % sccons test + + + + Would run all the automated test cases that depend on any changed + software. + + + + + + +
+ +
+ Java dependencies + + + + Java dependencies are difficult for an external dependency-based + construction tool to accomodate. Determining Java class dependencies + is more complicated than the simple pattern-matching of C or C++ + #include files. From the point of view of an + external build tool, the Java compiler behaves "unpredictably" + because it may create or update multiple output class files and + directories as a result of its internal class dependencies. + + + + + + An obvious &SCons; implementation would be to have the &Scanner; + object parse output from Java -depend -verbose to + calculate dependencies, but this has the distinct disadvantage of + requiring two separate compiler invocations, thereby slowing down + builds. + + + +
+ +
+ Limitations of digital signature calculation + + + + In practice, calculating digital signatures of a file's contents is a + more robust mechanism than time stamps for determining what needs + building. However: + + + + + + + + + Developers used to the time stamp model of &Make; can initially + find digital signatures counter-intuitive. The assumption that: + + + % touch file.c + + will cause a rebuild of file is strong... + + + + + + + + Abstracting dependency calculation into a single digital signature + loses a little information: It is no longer possible to tell + (without laborious additional calculation) which input file dependency + caused a rebuild of a given target file. A feature that could + report, "I'm rebuilding file X because it's out-of-date with respect + to file Y," would be good, but an digital-signature implementation of + such a feature is non-obvious. + + + + + + +
+ +
+ Remote execution + + + + The ability to use multiple build systems through remote execution + of tools would be good. This should be implementable through the + &Job; class. Construction environments would need modification + to specify build systems. + + + +
+ +
+ Conditional builds + + + + The ability to check run-time conditions as suggested on the + sc-discuss mailing list ("build X only if: the machine is idle / + the file system has Y megabytes free space") would also be good, + but is not part of the current design. + + + +
diff --git a/doc/design/main.sgml b/doc/design/main.sgml new file mode 100644 index 00000000..745d4730 --- /dev/null +++ b/doc/design/main.sgml @@ -0,0 +1,117 @@ + + + + %version; + + + %scons; + + + + + + + + + + + +]> + + + + SCons Design version &build_version; + + + Steven + Knight + + + Revision &build_revision; (&build_date;) + + 2001 + + + 2001 + Steven Knight + + + + ©right; + + + version &build_version; + + + + + Introduction + &intro; + + + + Goals + &goals; + + + + Overview + &overview; + + + + Build Engine API + &engine; + + + + Native Python Interface + &native; + + + + Installation + &install; + + + + Other Issues + &issues; + + + + Background + &bground; + + + + Summary + + + &SCons; offers a robust and feature-rich design for an SC-build + tool. With a Build Engine based on the proven design of + the &Cons; utility, it offers increased simplification of the + user interface for unsophisticated users with the addition + of the "do-the-right-thing" env.Make + method, increased flexibility for sophisticated users with the + addition of &Builder; and &Scanner; objects, a mechanism to + allow tool-masters (and users) to share working construction + environments, and embeddability to provide reliable dependency + management in a variety of environments and interfaces. + + + + + + Acknowledgements + &acks; + + + diff --git a/doc/design/native.sgml b/doc/design/native.sgml new file mode 100644 index 00000000..c9fd4bf6 --- /dev/null +++ b/doc/design/native.sgml @@ -0,0 +1,343 @@ + + + + + The "Native Python" interface is the interface + that the actual &SCons; utility will present to users. + Because it exposes the Python Build Engine API, + &SCons; users will have direct access to the complete + functionality of the Build Engine. + In contrast, a different user interface such as a GUI + may choose to only use, and present to the end-user, + a subset of the Build Engine functionality. + + + +
+ Configuration files + + + + &SCons; configuration files are simply Python scripts that invoke + methods to specify target files to be built, rules for building the + target files, and dependencies. Common build rules are available by + default and need not be explicitly specified in the configuration + files. + + + + + + By default, the &SCons; utility reads a configuration file named + &SConstruct; in the current directory. A + command-line option exists to read a different file name. + + + +
+ + + +
+ Python syntax + + + + Because &SCons; configuration files are Python scripts, normal Python + syntax can be used to generate or manipulate lists of targets or + dependencies: + + + + + sources = ['aaa.c', 'bbb.c', 'ccc.c'] + env.Make('bar', sources) + + + + + Python flow-control can be used to iterate through invocations of + build rules: + + + + + objects = ['aaa.o', 'bbb.o', 'ccc.o'] + for obj in objects: + src = replace(obj, '.o', '.c') + env.Make(obj, src) + + + + + or to handle more complicated conditional invocations: + + + + + # only build 'foo' on Linux systems + if sys.platform == 'linux1': + env.Make('foo', 'foo.c') + + + + + Because &SCons; configuration files are Python scripts, syntax errors + will be caught by the Python parser. Target-building does not begin + until after all configuration files are read, so a syntax error will + not cause a build to fail half-way. + + + +
+ + + +
+ Subsidiary configuration Files + + + + A configuration file can instruct &SCons; to read up subsidiary + configuration files. Subsidiary files are specified explicitly in a + configuration file via the &SConscript; method. As usual, multiple + file names may be specified with white space separation, or in an + array: + + + + + SConscript('other_file') + SConscript('file1 file2') + SConscript(['file3', 'file4']) + SConscript(['file name with white space']) + + + + + An explicit sconscript keyword may be used: + + + + + SConscript(sconscript = 'other_file') + + + + + Including subsidiary configuration files is recursive: a configuration + file included via &SConscript; may in turn &SConscript; other + configuration files. + + + +
+ + + +
+ Variable scoping in subsidiary files + + + + When a subsidiary configuration file is read, it is given its own + namespace; it does not have automatic access to variables from the parent + configuration file. + + + + + + Any variables (not just &SCons; objects) that are to be shared between configuration files must be + explicitly passed in the &SConscript; call + using the &Export method: + + + + + env = Environment() + debug = Environment(CCFLAGS = '-g') + installdir = '/usr/bin' + SConscript('src/SConscript', Export(env=env, debug=debug, installdir=installdir)) + + + +The env=env stuff bugs me +because it imposes extra work on the normal +case where you don't rename +the variables. +Can we simplify the &Export; method +so that a string +without a keyword assignment +is split into variables that are passed +through transparently? +Equivalent to the above example: +SConscript('src/SConscript', Export('env debug installdir')) + + + + + Which may be specified explicitly using a keyword argument: + + + + + env = Environment() + debug = Environment(CCFLAGS = '-g') + installdir = '/usr/bin' + SConscript(sconscript = 'src/SConscript', + export = Export(env=env, debug=debug, installdir=installdir)) + + + + + Explicit variable-passing provides control over exactly what is available + to a subsidiary file, and avoids unintended side effects of changes in + one configuration file affecting other far-removed configuration files + (a very hard-to-debug class of build problem). + + + +
+ + + +
+ Hierarchical builds + + + + The &SConscript; method is so named because, by convention, subsidiary + configuration files in subdirectories are named &SConscript;: + + + + + SConscript('src/SConscript') + SConscript('lib/build_me') + + + + + When a subsidiary configuration file is read from a subdirectory, all + of that configuration file's targets and build rules are interpreted + relative to that directory (as if &SCons; had changed its working + directory to that subdirectory). This allows for easy support of + hierarchical builds of directory trees for large projects. + + + +
+ + + +
+ Sharing &consenvs; + + + + &SCons; will allow users to share &consenvs, as well as other &SCons; + objects and Python variables, by importing them from a central, shared + repository using normal Python syntax: + + + + + from LocalEnvironments import optimized, debug + + optimized.Make('foo', 'foo.c') + debug.Make('foo-d', 'foo.c') + + + + + The expectation is that some local tool-master, integrator or + administrator will be responsible for assembling environments (creating + the &Builder; objects that specify the tools, options, etc.) and make + these available for sharing by all users. + + + + + + The modules containing shared &consenvs; + (LocalEnvironments in the above example) can be + checked in and controlled with the rest of the source files. This + allows a project to track the combinations of tools and command-line + options that work on different platforms, at different times, and with + different tool versions, by using already-familiar revision control + tools. + + + +
+ + + +
+ Help + + + + The &SCons; utility provides a &Help; function to allow the writer + of a &SConstruct; file to provide help text that is specific to + the local build tree: + + + + + Help(""" + Type: + scons . build and test everything + scons test build the software + scons src run the tests + scons web build the web pages + """) + + + + + This help text is displayed in response to the + command-line option. Calling the &Help; function more than once is an + error. + + + +
+ + + +
+ Debug + + + + &SCons; supports several command-line options for printing extra + information with which to debug build problems. + + + + +These need to be specified and explained +beyond what the man page will have. + + + + + + + See the -d, -p, -pa, and -pw options + in the , below. + All of these options make use of call-back functions to + + printed by the Build Engine. + + + + + +
diff --git a/doc/design/overview.sgml b/doc/design/overview.sgml new file mode 100644 index 00000000..51b473ea --- /dev/null +++ b/doc/design/overview.sgml @@ -0,0 +1,479 @@ + + +
+ Architecture + + + + The heart of &SCons; is its Build Engine. + The &SCons; Build Engine is a Python module + that manages dependencies between + external objects + such as files or database records. + The Build Engine is designed to + be interface-neutral + and easily embeddable in any + software system that needs dependency + analysis between updatable objects. + + + + + + The key parts of the Build Engine architecture + are captured in the following quasi-UML diagram: + + + + +Including this figure makes our PDF build blow up. +The figure, however, +is left over from the Software Carpentry contest +and is therefore old, out-of-date, and needs to be redone anyway. +This is where it will go, anyway... + + + + + + + The point of &SCons; is to manage + dependencies between arbitrary external objects. + Consequently, the Build Engine does not restrict or specify + the nature of the external objects it manages, + but instead relies on subclass of the &Node; + class to interact with the external system or systems + (file systems, database management systems) + that maintain the objects being examined or updated. + + + + + + The Build Engine presents to the software system in + which it is embedded + a Python API for specifying source (input) and target (output) objects, + rules for building/updating objects, + rules for scanning objects for dependencies, etc. + Above its Python API, + the Build Engine is completely + interface-independent, + and can be encapsulated by any other software + that supports embedded Python. + + + + + + Software that chooses to use the Build Engine + for dependency management + interacts with it + through Construction Environments. + A Construction Environment consists + of a dictionary of environment variables, + and one or more associated + &Scanner; objects + and &Builder; objects. + The Python API is used to + form these associations. + + + + + + A &Scanner; object specifies + how to examine a type of source object + (C source file, database record) + for dependency information. + A &Scanner; object may use + variables from the associated + Construction Environment + to modify how it scans an object: + specifying a search path for included files, + which field in a database record to consult, + etc. + + + + + + A &Builder; object specifies + how to update a type of target object: + executable program, object file, database field, etc. + Like a &Scanner; object, + a &Builder; object may use + variables from the associated + Construction Environment + to modify how it builds an object: + specifying flags to a compiler, + using a different update function, + etc. + + + + + + &Scanner; and &Builder; objects will return one or more + &Node; objects that represent external objects. + &Node; objects are the means by which the + Build Engine tracks dependencies: + A &Node; may represent a source (input) object that + should already exist, + or a target (output) object which may be built, + or both. + The &Node; class is sub-classed to + represent external objects of specific type: + files, directories, database fields or records, etc. + Because dependency information, however, + is tracked by the top-level &Node; methods and attributes, + dependencies can exist + between nodes representing different external object types. + For example, + building a file could be made + dependent on the value of a given + field in a database record, + or a database table could depend + on the contents of an external file. + + + + + + The Build Engine uses a &Job; class (not displayed) + to manage the actual work of updating external target objects: + spawning commands to build files, + submitting the necessary commands to update a database record, + etc. + The &Job; class has sub-classes + to handle differences between spawning + jobs in parallel and serially. + + + + + + The Build Engine also uses a + &Signature; class (not displayed) + to maintain information about whether + an external object is up-to-date. + Target objects with out-of-date signatures + are updated using the appropriate + &Builder; object. + + + + + + + + + +
+ + + +
+ Build Engine + + + + More detailed discussion of some of the + Build Engine's characteristics: + + + +
+ Python API + + + + The Build Engine can be embedded in any other software + that supports embedding Python: + in a GUI, + in a wrapper script that + interprets classic Makefile syntax, + or in any other software that + can translate its dependency representation + into the appropriate calls to the Build Engine API. + describes in detail + the specification for a "Native Python" interface + that will drive the &SCons; implementation effort. + + + +
+ +
+ Single-image execution + + + + When building/updating the objects, + the Build Engine operates as a single executable + with a complete Directed Acyclic Graph (DAG) + of the dependencies in the entire build tree. + This is in stark contrast to the + commonplace recursive use of Make + to handle hierarchical directory-tree builds. + + + +
+ +
+ Dependency analysis + + + + Dependency analysis is carried out via digital signatures + (a.k.a. "fingerprints"). + Contents of object are examined and reduced + to a number that can be stored and compared to + see if the object has changed. + Additionally, &SCons; uses the same + signature technique on the command-lines that + are executed to update an object. + If the command-line has changed since the last time, + then the object must be rebuilt. + + + +
+ +
+ Customized output + + + + The output of Build Engine is customizable + through user-defined functions. + This could be used to print additional desired + information about what &SCons; is doing, + or tailor output to a specific build analyzer, + GUI, or IDE. + + + +
+ +
+ Build failures + + + + &SCons; detects build failures via the exit status from the tools + used to build the target files. By default, a failed exit status + (non-zero on UNIX systems) terminates the build with an appropriate + error message. An appropriate class from the Python library will + interpret build-tool failures via an OS-independent API. + + + + + + If multiple tasks are executing in a parallel build, and one tool + returns failure, &SCons; will not initiate any further build tasks, + but allow the other build tasks to complete before terminating. + + + + + + A command-line option may be used to ignore + errors and continue building other targets. In no case will a target + that depends on a failed build be rebuilt. + + + +
+ +
+ + + +
+ Interfaces + + + + As previously described, + the &SCons; Build Engine + is interface-independent above its Python API, + and can be embedded in any software system + that can translate its dependency requirements + into the necessary Python calls. + + + + + + The "main" &SCons; interface + for implementation purposes, + uses Python scripts as configuration files. + Because this exposes the Build Engine's Python API to the user, + it is current called the "Native Python" interface. + + + + + + This section will also discuss + how &SCons; will function in the context + of two other interfaces: + the &Makefile; interface of the classic &Make; utility, + and a hypothetical graphical user interface (GUI). + + + +
+ Native Python interface + + + + The Native Python interface is intended to be the primary interface + by which users will know &SCons;--that is, + it is the interface they will use + if they actually type &SCons; at a command-line prompt. + + + + + + In the Native Python interface, &SCons; configuration files are simply + Python scripts that directly invoke methods from the Build Engine's + Python API to specify target files to be built, rules for building + the target files, and dependencies. Additional methods, specific to + this interface, are added to handle functionality that is specific to + the Native Python interface: reading a subsidiary configuration file; + copying target files to an installation directory; etc. + + + + + + Because configuration files are Python scripts, Python flow control + can be used to provide very flexible manipulation of objects and + dependencies. For example, a function could be used to invoke a common + set of methods on a file, and called iteratively over an array of + files. + + + + + + As an additional advantage, syntax errors in &SCons; Native Python + configuration files will be caught by the Python parser. Target-building + does not begin until after all configuration files are read, so a syntax + error will not cause a build to fail half-way. + + + +
+ +
+ Makefile interface + + + + An alternate &SCons; interface would provide backwards + compatibility with the classic &Make utility. + This would be done by embedding the &SCons; Build Engine + in a Python script that can translate existing + &Makefile;s into the underlying calls to the + Build Engine's Python API + for building and tracking dependencies. + Here are approaches to solving some of the issues + that arise from marrying these two pieces: + + + + + + + + &Makefile; suffix rules can be translated + into an appropriate &Builder; object + with suffix maps from the Construction Environment. + + + + + + Long lists of static dependences + appended to a &Makefile; by + various "make depend" schemes + can be preserved + but supplemented by + the more accurate dependency information + provided by &Scanner; objects. + + + + + + Recursive invocations of &Make; + can be avoided by reading up + the subsidiary &Makefile; instead. + + + + + + + + Lest this seem like too outlandish an undertaking, + there is a working example of this approach: + Gary Holt's &Makepp; utility + is a Perl script that provides + admirably complete parsing of complicated &Makefile;s + around an internal build engine inspired, + in part, by the classic Cons utility. + + + +
+ +
+ Graphical interfaces + + + + The &SCons; Build Engine + is designed from the ground up to be embedded + into multiple interfaces. + Consequently, embedding the dependency capabilities + of &SCons; into graphical interface + would be a matter of mapping the + GUI's dependency representation + (either implicit or explicit) + into corresponding calls to the Python API + of the &SCons; Build Engine. + + + + + + Note, however, that this proposal leaves the problem of + designed a good graphical interface + for representing software build dependencies + to people with actual GUI design experience... + + + +
+ +
diff --git a/doc/scons.mod b/doc/scons.mod new file mode 100644 index 00000000..902149bf --- /dev/null +++ b/doc/scons.mod @@ -0,0 +1,129 @@ + + + + + + + + + + +Autoconf"> +Cons"> +Make"> +Make++"> +SCons"> + + + + + +Builder"> +Job"> +Node"> +Scanner"> +Signature"> + + + + + +Makefile"> +SConscript"> +SConstruct"> +.consign"> + + + + + +Alias"> +Aliases"> +Build"> +Clean"> +Command"> +Copy"> +Default"> +Environment"> +Export"> +Help"> +Link"> +Local"> +Precious"> +Repository"> +Task"> + + + + + +BUILDERMAP"> +BUILDERMAP"> +SCANNERMAP"> +SCANNERMAP"> + + + + + +Object"> +Library"> +SharedLibrary"> +Program"> +Make"> + + + + + +Construction Environment"> +Construction Environments"> +Construction environment"> +Construction environments"> +construction environment"> +construction environments"> + +Construction Variable"> +Construction Variables"> +Construction variable"> +Construction variables"> +construction variable"> +construction variables"> + +Dictionary"> -- 2.26.2