diff options
author | Steven Knight <knight@baldmt.com> | 2003-02-06 05:17:25 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2003-02-06 05:17:25 (GMT) |
commit | 4f6a2c926304ee3ea444b6854991489702252c0e (patch) | |
tree | a00f3bdda7160f30f6b0838a9ebca57b8ad0c49f /doc | |
parent | c07047f3cfdb2eb3c7f29a96afb2accdfed69184 (diff) | |
download | SCons-4f6a2c926304ee3ea444b6854991489702252c0e.zip SCons-4f6a2c926304ee3ea444b6854991489702252c0e.tar.gz SCons-4f6a2c926304ee3ea444b6854991489702252c0e.tar.bz2 |
Checkin of in-progress work on the User Guide.
Diffstat (limited to 'doc')
33 files changed, 4048 insertions, 120 deletions
diff --git a/doc/scons.mod b/doc/scons.mod index b156e4c..642f979 100644 --- a/doc/scons.mod +++ b/doc/scons.mod @@ -170,3 +170,14 @@ <!ENTITY consvars "<literal>construction variables</literal>"> <!ENTITY Dictionary "<literal>Dictionary</literal>"> + +<!-- + + File and program names used in examples. + +--> + +<!ENTITY hello "<application>hello</application>"> +<!ENTITY hello_c "<filename>hello.c</filename>"> +<!ENTITY hello_h "<filename>hello.h</filename>"> +<!ENTITY stdio_h "<filename>stdio.h</filename>"> diff --git a/doc/user/actions.sgml b/doc/user/actions.sgml new file mode 100644 index 0000000..447b331 --- /dev/null +++ b/doc/user/actions.sgml @@ -0,0 +1,240 @@ +<!-- + + Copyright (c) 2001, 2002, 2003 Steven Knight + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + +<!-- + +=head1 Build actions + +Cons supports several types of B<build actions> that can be performed +to construct one or more target files. Usually, a build action is +a construction command, that is, a command-line string that invokes +an external command. Cons can also execute Perl code embedded in a +command-line string, and even supports an experimental ability to build +a target file by executing a Perl code reference directly. + +A build action is usually specified as the value of a construction +variable: + + $env = new cons( + CCCOM => '%CC %CFLAGS %_IFLAGS -c %< -o %>', + LINKCOM => '[perl] &link_executable("%>", "%<")', + ARCOM => sub { my($env, $target, @sources) = @_; + # code to create an archive + } + ); + +A build action may be associated directly with one or more target files +via the C<Command> method; see below. + +=head2 Construction commands + +A construction command goes through expansion of construction variables +and C<%-> pseudo-variables, as described above, to create the actual +command line that Cons will execute to generate the target file or +files. + +After substitution occurs, strings of white space are converted into +single blanks, and leading and trailing white space is eliminated. It +is therefore currently not possible to introduce variable length white +space in strings passed into a command. + +If a multi-line command string is provided, the commands are executed +sequentially. If any of the commands fails, then none of the rest are +executed, and the target is not marked as updated, i.e. a new signature is +not stored for the target. + +Normally, if all the commands succeed, and return a zero status (or whatever +platform-specific indication of success is required), then a new signature +is stored for the target. If a command erroneously reports success even +after a failure, then Cons will assume that the target file created by that +command is accurate and up-to-date. + +The first word of each command string, after expansion, is assumed to be an +executable command looked up on the C<PATH> environment variable (which is, +in turn, specified by the C<ENV> construction variable). If this command is +found on the path, then the target will depend upon it: the command will +therefore be automatically built, as necessary. It's possible to write +multi-part commands to some shells, separated by semi-colons. Only the first +command word will be depended upon, however, so if you write your command +strings this way, you must either explicitly set up a dependency (with the +C<Depends> method), or be sure that the command you are using is a system +command which is expected to be available. If it isn't available, you will, +of course, get an error. + +Cons normally prints a command before executing it. This behavior is +suppressed if the first character of the command is C<@>. Note that +you may need to separate the C<@> from the command name or escape it to +prevent C<@cmd> from looking like an array to Perl quote operators that +perform interpolation: + + # The first command line is incorrect, + # because "@cp" looks like an array + # to the Perl qq// function. + # Use the second form instead. + Command $env 'foo', 'foo.in', qq( + @cp %< tempfile + @ cp tempfile %> + ); + +If there are shell meta characters anywhere in the expanded command line, +such as C<E<lt>>, C<E<gt>>, quotes, or semi-colon, then the command +will actually be executed by invoking a shell. This means that a command +such as: + + cd foo + +alone will typically fail, since there is no command C<cd> on the path. But +the command string: + + cd $<:d; tar cf $>:f $<:f + +when expanded will still contain the shell meta character semi-colon, and a +shell will be invoked to interpret the command. Since C<cd> is interpreted +by this sub-shell, the command will execute as expected. + +=head2 Perl expressions + +If any command (even one within a multi-line command) begins with +C<[perl]>, the remainder of that command line will be evaluated by the +running Perl instead of being forked by the shell. If an error occurs +in parsing the Perl code, or if the Perl expression returns 0 or undef, +the command will be considered to have failed. For example, here is a +simple command which creates a file C<foo> directly from Perl: + + $env = new cons(); + Command $env 'foo', + qq([perl] open(FOO,'>foo');print FOO "hi\\n"; close(FOO); 1); + +Note that when the command is executed, you are in the same package as +when the F<Construct> or F<Conscript> file was read, so you can call +Perl functions you've defined in the same F<Construct> or F<Conscript> +file in which the C<Command> appears: + + $env = new cons(); + sub create_file { + my $file = shift; + open(FILE, ">$file"); + print FILE "hi\n"; + close(FILE); + return 1; + } + Command $env 'foo', "[perl] &create_file('%>')"; + +The Perl string will be used to generate the signature for the derived +file, so if you change the string, the file will be rebuilt. The contents +of any subroutines you call, however, are not part of the signature, +so if you modify a called subroutine such as C<create_file> above, +the target will I<not> be rebuilt. Caveat user. + +=head2 Perl code references [EXPERIMENTAL] + +Cons supports the ability to create a derived file by directly executing +a Perl code reference. This feature is considered EXPERIMENTAL and +subject to change in the future. + +A code reference may either be a named subroutine referenced by the +usual C<\&> syntax: + + sub build_output { + my($env, $target, @sources) = @_; + print "build_output building $target\n"; + open(OUT, ">$target"); + foreach $src (@sources) { + if (! open(IN, "<$src")) { + print STDERR "cannot open '$src': $!\n"; + return undef; + } + print OUT, <IN>; + } + close(OUT); + return 1; + } + Command $env 'output', \&build_output; + +or the code reference may be an anonymous subroutine: + + Command $env 'output', sub { + my($env, $target, @sources) = @_; + print "building $target\n"; + open(FILE, ">$target"); + print FILE "hello\n"; + close(FILE); + return 1; + }; + +To build the target file, the referenced subroutine is passed, in order: +the construction environment used to generate the target; the path +name of the target itself; and the path names of all the source files +necessary to build the target file. + +The code reference is expected to generate the target file, of course, +but may manipulate the source and target files in any way it chooses. +The code reference must return a false value (C<undef> or C<0>) if +the build of the file failed. Any true value indicates a successful +build of the target. + +Building target files using code references is considered EXPERIMENTAL +due to the following current limitations: + +=over 4 + +Cons does I<not> print anything to indicate the code reference is being +called to build the file. The only way to give the user any indication +is to have the code reference explicitly print some sort of "building" +message, as in the above examples. + +Cons does not generate any signatures for code references, so if the +code in the reference changes, the target will I<not> be rebuilt. + +Cons has no public method to allow a code reference to extract +construction variables. This would be good to allow generalization of +code references based on the current construction environment, but would +also complicate the problem of generating meaningful signatures for code +references. + +=back + +Support for building targets via code references has been released in +this version to encourage experimentation and the seeking of possible +solutions to the above limitations. + +--> + + <para> + + X + + </para> + + <section> + <title>X</title> + + <para> + + X + + </para> + + </section> diff --git a/doc/user/alias.sgml b/doc/user/alias.sgml new file mode 100644 index 0000000..33c236a --- /dev/null +++ b/doc/user/alias.sgml @@ -0,0 +1,45 @@ +<!-- + + Copyright (c) 2001, 2002, 2003 Steven Knight + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + +<!-- + +--> + + <para> + + X + + </para> + + <section> + <title>Alias Targets</title> + + <para> + + X + + </para> + + </section> diff --git a/doc/user/builders.sgml b/doc/user/builders.sgml index 2cba10e..ac5f193 100644 --- a/doc/user/builders.sgml +++ b/doc/user/builders.sgml @@ -22,6 +22,79 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + +<!-- + +=head2 Adding new methods + +For slightly more demanding changes, you may wish to add new methods to the +C<cons> package. Here's an example of a very simple extension, +C<InstallScript>, which installs a tcl script in a requested location, but +edits the script first to reflect a platform-dependent path that needs to be +installed in the script: + + # cons::InstallScript - Create a platform dependent version of a shell + # script by replacing string ``#!your-path-here'' with platform specific + # path $BIN_DIR. + + sub cons::InstallScript { + my ($env, $dst, $src) = @_; + Command $env $dst, $src, qq( + sed s+your-path-here+$BIN_DIR+ %< > %> + chmod oug+x %> + ); + } + +Notice that this method is defined directly in the C<cons> package (by +prefixing the name with C<cons::>). A change made in this manner will be +globally visible to all environments, and could be called as in the +following example: + + InstallScript $env "$BIN/foo", "foo.tcl"; + +For a small improvement in generality, the C<BINDIR> variable could be +passed in as an argument or taken from the construction environment-,-as +C<%BINDIR>. + + +=head2 Overriding methods + +Instead of adding the method to the C<cons> name space, you could define a +new package which inherits existing methods from the C<cons> package and +overrides or adds others. This can be done using Perl's inheritance +mechanisms. + +The following example defines a new package C<cons::switch> which +overrides the standard C<Library> method. The overridden method builds +linked library modules, rather than library archives. A new +constructor is provided. Environments created with this constructor +will have the new library method; others won't. + + package cons::switch; + BEGIN {@ISA = 'cons'} + + sub new { + shift; + bless new cons(@_); + } + + sub Library { + my($env) = shift; + my($lib) = shift; + my(@objs) = Objects $env @_; + Command $env $lib, @objs, q( + %LD -r %LDFLAGS %< -o %> + ); + } + +This functionality could be invoked as in the following example: + + $env = new cons::switch(@overrides); + ... + Library $env 'lib.o', 'foo.c', 'bar.c'; + +--> + <para> X diff --git a/doc/user/caching.sgml b/doc/user/caching.sgml index 3ddfd32..5403c43 100644 --- a/doc/user/caching.sgml +++ b/doc/user/caching.sgml @@ -23,6 +23,17 @@ --> +<!-- + +=head2 The C<UseCache> method + +The C<UseCache> method instructs Cons to maintain a cache of derived +files, to be shared among separate build trees of the same project. + + UseCache("cache/<buildname>") || warn("cache directory not found"); + +--> + <para> X diff --git a/doc/user/command.sgml b/doc/user/command.sgml new file mode 100644 index 0000000..abb3a58 --- /dev/null +++ b/doc/user/command.sgml @@ -0,0 +1,73 @@ +<!-- + + Copyright (c) 2001, 2002, 2003 Steven Knight + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + +<!-- + +=head2 The C<Command> method + +The C<Command> method is a catchall method which can be used to arrange for +any build action to be executed to update the target. For this command, a +target file and list of inputs is provided. In addition, a build action +is specified as the last argument. The build action is typically a +command line or lines, but may also contain Perl code to be executed; +see the section above on build actions for details. + +The C<Command> method is called as follows: + + Command $env <target>, <inputs>, <build action>; + +The target is made dependent upon the list of input files specified, and the +inputs must be built successfully or Cons will not attempt to build the +target. + +To specify a command with multiple targets, you can specify a reference to a +list of targets. In Perl, a list reference can be created by enclosing a +list in square brackets. Hence the following command: + + Command $env ['foo.h', 'foo.c'], 'foo.template', q( + gen %1 + ); + +could be used in a case where the command C<gen> creates two files, both +F<foo.h> and F<foo.c>. + +--> + + <para> + + X + + </para> + + <section> + <title>The &Command; Method</title> + + <para> + + X + + </para> + + </section> diff --git a/doc/user/cons.pl b/doc/user/cons.pl new file mode 100644 index 0000000..8afbfec --- /dev/null +++ b/doc/user/cons.pl @@ -0,0 +1,720 @@ +=head1 Introduction + +B<Cons> is a system for constructing, primarily, software, but is quite +different from previous software construction systems. Cons was designed +from the ground up to deal easily with the construction of software spread +over multiple source directories. Cons makes it easy to create build scripts +that are simple, understandable and maintainable. Cons ensures that complex +software is easily and accurately reproducible. + +Cons uses a number of techniques to accomplish all of this. Construction +scripts are just Perl scripts, making them both easy to comprehend and very +flexible. Global scoping of variables is replaced with an import/export +mechanism for sharing information between scripts, significantly improving +the readability and maintainability of each script. B<Construction +environments> are introduced: these are Perl objects that capture the +information required for controlling the build process. Multiple +environments are used when different semantics are required for generating +products in the build tree. Cons implements automatic dependency analysis +and uses this to globally sequence the entire build. Variant builds are +easily produced from a single source tree. Intelligent build subsetting is +possible, when working on localized changes. Overrides can be setup to +easily override build instructions without modifying any scripts. MD5 +cryptographic B<signatures> are associated with derived files, and are used +to accurately determine whether a given file needs to be rebuilt. + +While offering all of the above, and more, Cons remains simple and easy to +use. This will, hopefully, become clear as you read the remainder of this +document. + + + +=head2 Automatic global build sequencing + +Because Cons does full and accurate dependency analysis, and does this +globally, for the entire build, Cons is able to use this information to take +full control of the B<sequencing> of the build. This sequencing is evident +in the above examples, and is equivalent to what you would expect for make, +given a full set of dependencies. With Cons, this extends trivially to +larger, multi-directory builds. As a result, all of the complexity involved +in making sure that a build is organized correctly--including multi-pass +hierarchical builds--is eliminated. We'll discuss this further in the next +sections. + + + +=head1 A Model for sharing files + + +=head2 Some simple conventions + +In any complex software system, a method for sharing build products needs to +be established. We propose a simple set of conventions which are trivial to +implement with Cons, but very effective. + +The basic rule is to require that all build products which need to be shared +between directories are shared via an intermediate directory. We have +typically called this F<export>, and, in a C environment, provided +conventional sub-directories of this directory, such as F<include>, F<lib>, +F<bin>, etc. + +These directories are defined by the top-level F<Construct> file. A simple +F<Construct> file for a B<Hello, World!> application, organized using +multiple directories, might look like this: + + # Construct file for Hello, World! + + # Where to put all our shared products. + $EXPORT = '#export'; + + Export qw( CONS INCLUDE LIB BIN ); + + # Standard directories for sharing products. + $INCLUDE = "$EXPORT/include"; + $LIB = "$EXPORT/lib"; + $BIN = "$EXPORT/bin"; + + # A standard construction environment. + $CONS = new cons ( + CPPPATH => $INCLUDE, # Include path for C Compilations + LIBPATH => $LIB, # Library path for linking programs + LIBS => '-lworld', # List of standard libraries + ); + + Build qw( + hello/Conscript + world/Conscript + ); + +The F<world> directory's F<Conscript> file looks like this: + + # Conscript file for directory world + Import qw( CONS INCLUDE LIB ); + + # Install the products of this directory + Install $CONS $LIB, 'libworld.a'; + Install $CONS $INCLUDE, 'world.h'; + + # Internal products + Library $CONS 'libworld.a', 'world.c'; + +and the F<hello> directory's F<Conscript> file looks like this: + + # Conscript file for directory hello + Import qw( CONS BIN ); + + # Exported products + Install $CONS $BIN, 'hello'; + + # Internal products + Program $CONS 'hello', 'hello.c'; + +To construct a B<Hello, World!> program with this directory structure, go to +the top-level directory, and invoke C<cons> with the appropriate +arguments. In the following example, we tell Cons to build the directory +F<export>. To build a directory, Cons recursively builds all known products +within that directory (only if they need rebuilding, of course). If any of +those products depend upon other products in other directories, then those +will be built, too. + + % cons export + Install world/world.h as export/include/world.h + cc -Iexport/include -c hello/hello.c -o hello/hello.o + cc -Iexport/include -c world/world.c -o world/world.o + ar r world/libworld.a world/world.o + ar: creating world/libworld.a + ranlib world/libworld.a + Install world/libworld.a as export/lib/libworld.a + cc -o hello/hello hello/hello.o -Lexport/lib -lworld + Install hello/hello as export/bin/hello + + +=head2 Clean, understandable, location-independent scripts + +You'll note that the two F<Conscript> files are very clean and +to-the-point. They simply specify products of the directory and how to build +those products. The build instructions are minimal: they specify which +construction environment to use, the name of the product, and the name of +the inputs. Note also that the scripts are location-independent: if you wish +to reorganize your source tree, you are free to do so: you only have to +change the F<Construct> file (in this example), to specify the new locations +of the F<Conscript> files. The use of an export tree makes this goal easy. + +Note, too, how Cons takes care of little details for you. All the F<export> +directories, for example, were made automatically. And the installed files +were really hard-linked into the respective export directories, to save +space and time. This attention to detail saves considerable work, and makes +it even easier to produce simple, maintainable scripts. + + + +=head1 Signatures + +Cons uses file B<signatures> to decide if a derived file is out-of-date +and needs rebuilding. In essence, if the contents of a file change, +or the manner in which the file is built changes, the file's signature +changes as well. This allows Cons to decide with certainty when a file +needs rebuilding, because Cons can detect, quickly and reliably, whether +any of its dependency files have been changed. + + +=head2 MD5 content and build signatures + +Cons uses the B<MD5> (B<Message Digest 5>) algorithm to compute file +signatures. The MD5 algorithm computes a strong cryptographic checksum +for any given input string. Cons can, based on configuration, use two +different MD5 signatures for a given file: + +The B<content signature> of a file is an MD5 checksum of the file's +contents. Consequently, when the contents of a file change, its content +signature changes as well. + +The B<build signature> of a file is a combined MD5 checksum of: + +=over 4 + +the signatures of all the input files used to build the file + +the signatures of all dependency files discovered by source scanners +(for example, C<.h> files) + +the signatures of all dependency files specified explicitly via the +C<Depends> method) + +the command-line string used to build the file + +=back + +The build signature is, in effect, a digest of all the dependency +information for the specified file. Consequently, a file's build +signature changes whenever any part of its dependency information +changes: a new file is added, the contents of a file on which it depends +change, there's a change to the command line used to build the file (or +any of its dependency files), etc. + +For example, in the previous section, the build signature of the +F<world.o> file will include: + +=over 4 + +the signature of the F<world.c> file + +the signatures of any header files that Cons detects are included, +directly or indirectly, by F<world.c> + +the text of the actual command line was used to generate F<world.o> + +=back + +Similarly, the build signature of the F<libworld.a> file will include +all the signatures of its constituents (and hence, transitively, the +signatures of B<their> constituents), as well as the command line that +created the file. + +Note that there is no need for a derived file to depend upon any +particular F<Construct> or F<Conscript> file. If changes to these files +affect a file, then this will be automatically reflected in its build +signature, since relevant parts of the command line are included in the +signature. Unrelated F<Construct> or F<Conscript> changes will have no +effect. + + +=head2 Storing signatures in .consign files + +Before Cons exits, it stores the calculated signatures for all of the +files it built or examined in F<.consign> files, one per directory. +Cons uses this stored information on later invocations to decide if +derived files need to be rebuilt. + +After the previous example was compiled, the F<.consign> file in the +F<build/peach/world> directory looked like this: + + world.h:985533370 - d181712f2fdc07c1f05d97b16bfad904 + world.o:985533372 2a0f71e0766927c0532977b0d2158981 + world.c:985533370 - c712f77189307907f4189b5a7ab62ff3 + libworld.a:985533374 69e568fc5241d7d25be86d581e1fb6aa + +After the file name and colon, the first number is a timestamp of the +file's modification time (on UNIX systems, this is typically the number +of seconds since January 1st, 1970). The second value is the build +signature of the file (or ``-'' in the case of files with no build +signature--that is, source files). The third value, if any, is the +content signature of the file. + + +=head2 Using build signatures to decide when to rebuild files + +When Cons is deciding whether to build or rebuild a derived file, it +first computes the file's current build signature. If the file doesn't +exist, it must obviously be built. + +If, however, the file already exists, Cons next compares the +modification timestamp of the file against the timestamp value in +the F<.consign> file. If the timestamps match, Cons compares the +newly-computed build signature against the build signature in the +F<.consign> file. If the timestamps do not match or the build +signatures do not match, the derived file is rebuilt. + +After the file is built or rebuilt, Cons arranges to store the +newly-computed build signature in the F<.consign> file when it exits. + + +=head2 Signature example + +The use of these signatures is an extremely simple, efficient, and +effective method of improving--dramatically--the reproducibility of a +system. + +We'll demonstrate this with a simple example: + + # Simple "Hello, World!" Construct file + $CFLAGS = '-g' if $ARG{DEBUG} eq 'on'; + $CONS = new cons(CFLAGS => $CFLAGS); + Program $CONS 'hello', 'hello.c'; + +Notice how Cons recompiles at the appropriate times: + + % cons hello + cc -c hello.c -o hello.o + cc -o hello hello.o + % cons hello + cons: "hello" is up-to-date. + % cons DEBUG=on hello + cc -g -c hello.c -o hello.o + cc -o hello hello.o + % cons DEBUG=on hello + cons: "hello" is up-to-date. + % cons hello + cc -c hello.c -o hello.o + cc -o hello hello.o + + +=head2 Source-file signature configuration + +Cons provides a C<SourceSignature> method that allows you to configure +how the signature should be calculated for any source file when its +signature is being used to decide if a dependent file is up-to-date. +The arguments to the C<SourceSignature> method consist of one or more +pairs of strings: + + SourceSignature 'auto/*.c' => 'content', + '*' => 'stored-content'; + +The first string in each pair is a pattern to match against derived file +path names. The pattern is a file-globbing pattern, not a Perl regular +expression; the pattern <*.l> will match all Lex source files. The C<*> +wildcard will match across directory separators; the pattern C<foo/*.c> +would match all C source files in any subdirectory underneath the C<foo> +subdirectory. + +The second string in each pair contains one of the following keywords to +specify how signatures should be calculated for source files that match +the pattern. The available keywords are: + +=over 4 + +=item content + +Use the content signature of the source file when calculating signatures +of files that depend on it. This guarantees correct calculation of the +file's signature for all builds, by telling Cons to read the contents of +a source file to calculate its content signature each time it is run. + +=item stored-content + +Use the source file's content signature as stored in the F<.consign> +file, provided the file's timestamp matches the cached timestamp value +in the F<.consign> file. This optimizes performance, with the slight +risk of an incorrect build if a source file's contents have been changed +so quickly after its previous update that the timestamp still matches +the stored timestamp in the F<.consign> file even though the contents +have changed. + +=back + +The Cons default behavior of always calculating a source file's +signature from the file's contents is equivalent to specifying: + + SourceSignature '*' => 'content'; + +The C<*> will match all source files. The C<content> keyword +specifies that Cons will read the contents of a source file to calculate +its signature each time it is run. + +A useful global performance optimization is: + + SourceSignature '*' => 'stored-content'; + +This specifies that Cons will use pre-computed content signatures +from F<.consign> files, when available, rather than re-calculating a +signature from the the source file's contents each time Cons is run. In +practice, this is safe for most build situations, and only a problem +when source files are changed automatically (by scripts, for example). +The Cons default, however, errs on the side of guaranteeing a correct +build in all situations. + +Cons tries to match source file path names against the patterns in the +order they are specified in the C<SourceSignature> arguments: + + SourceSignature '/usr/repository/objects/*' => 'stored-content', + '/usr/repository/*' => 'content', + '*.y' => 'content', + '*' => 'stored-content'; + +In this example, all source files under the F</usr/repository/objects> +directory will use F<.consign> file content signatures, source files +anywhere else underneath F</usr/repository> will not use F<.consign> +signature values, all Yacc source files (C<*.y>) anywhere else will not +use F<.consign> signature values, and any other source file will use +F<.consign> signature values. + + +=head2 Derived-file signature configuration + +Cons provides a C<SIGNATURE> construction variable that allows you to +configure how signatures are calculated for any derived file when its +signature is being used to decide if a dependent file is up-to-date. +The value of the C<SIGNATURE> construction variable is a Perl array +reference that holds one or more pairs of strings, like the arguments to +the C<SourceSignature> method. + +The first string in each pair is a pattern to match against derived file +path names. The pattern is a file-globbing pattern, not a Perl regular +expression; the pattern `*.obj' will match all (Win32) object files. +The C<*> wildcard will match across directory separators; the pattern +`foo/*.a' would match all (UNIX) library archives in any subdirectory +underneath the foo subdirectory. + +The second string in each pair contains one of the following keywords +to specify how signatures should be calculated for derived files that +match the pattern. The available keywords are the same as for the +C<SourceSignature> method, with an additional keyword: + +=over 4 + +=item build + +Use the build signature of the derived file when calculating signatures +of files that depend on it. This guarantees correct builds by forcing +Cons to rebuild any and all files that depend on the derived file. + +=item content + +Use the content signature of the derived file when calculating signatures +of files that depend on it. This guarantees correct calculation of the +file's signature for all builds, by telling Cons to read the contents of +a derived file to calculate its content signature each time it is run. + +=item stored-content + +Use the derived file's content signature as stored in the F<.consign> +file, provided the file's timestamp matches the cached timestamp value +in the F<.consign> file. This optimizes performance, with the slight +risk of an incorrect build if a derived file's contents have been +changed so quickly after a Cons build that the file's timestamp still +matches the stored timestamp in the F<.consign> file. + +=back + +The Cons default behavior (as previously described) for using +derived-file signatures is equivalent to: + + $env = new cons(SIGNATURE => ['*' => 'build']); + +The C<*> will match all derived files. The C<build> keyword specifies +that all derived files' build signatures will be used when calculating +whether a dependent file is up-to-date. + +A useful alternative default C<SIGNATURE> configuration for many sites: + + $env = new cons(SIGNATURE => ['*' => 'content']); + +In this configuration, derived files have their signatures calculated +from the file contents. This adds slightly to Cons' workload, but has +the useful effect of "stopping" further rebuilds if a derived file is +rebuilt to exactly the same file contents as before, which usually +outweighs the additional computation Cons must perform. + +For example, changing a comment in a C file and recompiling should +generate the exact same object file (assuming the compiler doesn't +insert a timestamp in the object file's header). In that case, +specifying C<content> or C<stored-content> for the signature calculation +will cause Cons to recognize that the object file did not actually +change as a result of being rebuilt, and libraries or programs that +include the object file will not be rebuilt. When C<build> is +specified, however, Cons will only "know" that the object file was +rebuilt, and proceed to rebuild any additional files that include the +object file. + +Note that Cons tries to match derived file path names against the +patterns in the order they are specified in the C<SIGNATURE> array +reference: + + $env = new cons(SIGNATURE => ['foo/*.o' => 'build', + '*.o' => 'content', + '*.a' => 'stored-content', + '*' => 'content']); + +In this example, all object files underneath the F<foo> subdirectory +will use build signatures, all other object files (including object +files underneath other subdirectories!) will use F<.consign> file +content signatures, libraries will use F<.consign> file build +signatures, and all other derived files will use content signatures. + + +=head2 Debugging signature calculation + +Cons provides a C<-S> option that can be used to specify what internal +Perl package Cons should use to calculate signatures. The default Cons +behavior is equivalent to specifying C<-S md5> on the command line. + +The only other package (currently) available is an C<md5::debug> +package that prints out detailed information about the MD5 signature +calculations performed by Cons: + + % cons -S md5::debug hello + sig::md5::srcsig(hello.c) + => |52d891204c62fe93ecb95281e1571938| + sig::md5::collect(52d891204c62fe93ecb95281e1571938) + => |fb0660af4002c40461a2f01fbb5ffd03| + sig::md5::collect(52d891204c62fe93ecb95281e1571938, + fb0660af4002c40461a2f01fbb5ffd03, + cc -c %< -o %>) + => |f7128da6c3fe3c377dc22ade70647b39| + sig::md5::current(|| + eq |f7128da6c3fe3c377dc22ade70647b39|) + cc -c hello.c -o hello.o + sig::md5::collect() + => |d41d8cd98f00b204e9800998ecf8427e| + sig::md5::collect(f7128da6c3fe3c377dc22ade70647b39, + d41d8cd98f00b204e9800998ecf8427e, + cc -o %> %< ) + => |a0bdce7fd09e0350e7efbbdb043a00b0| + sig::md5::current(|| + eq |a0bdce7fd09e0350e7efbbdb043a00b0|) + cc -o hello, hello.o + + + + + + + +=head1 Temporary overrides + +Cons provides a very simple mechanism for overriding aspects of a build. The +essence is that you write an override file containing one or more +C<Override> commands, and you specify this on the command line, when you run +C<cons>: + + % cons -o over export + +will build the F<export> directory, with all derived files subject to the +overrides present in the F<over> file. If you leave out the C<-o> option, +then everything necessary to remove all overrides will be rebuilt. + + +=head2 Overriding environment variables + +The override file can contain two types of overrides. The first is incoming +environment variables. These are normally accessible by the F<Construct> +file from the C<%ENV> hash variable. These can trivially be overridden in +the override file by setting the appropriate elements of C<%ENV> (these +could also be overridden in the user's environment, of course). + + +=head2 The Override command + +The second type of override is accomplished with the C<Override> command, +which looks like this: + + Override <regexp>, <var1> => <value1>, <var2> => <value2>, ...; + +The regular expression I<regexp> is matched against every derived file that +is a candidate for the build. If the derived file matches, then the +variable/value pairs are used to override the values in the construction +environment associated with the derived file. + +Let's suppose that we have a construction environment like this: + + $CONS = new cons( + COPT => '', + CDBG => '-g', + CFLAGS => '%COPT %CDBG', + ); + +Then if we have an override file F<over> containing this command: + + Override '\.o$', COPT => '-O', CDBG => ''; + +then any C<cons> invocation with C<-o over> that creates F<.o> files via +this environment will cause them to be compiled with C<-O >and no C<-g>. The +override could, of course, be restricted to a single directory by the +appropriate selection of a regular expression. + +Here's the original version of the Hello, World! program, built with this +environment. Note that Cons rebuilds the appropriate pieces when the +override is applied or removed: + + % cons hello + cc -g -c hello.c -o hello.o + cc -o hello hello.o + % cons -o over hello + cc -O -c hello.c -o hello.o + cc -o hello hello.o + % cons -o over hello + cons: "hello" is up-to-date. + % cons hello + cc -g -c hello.c -o hello.o + cc -o hello hello.o + +It's important that the C<Override> command only be used for temporary, +on-the-fly overrides necessary for development because the overrides are not +platform independent and because they rely too much on intimate knowledge of +the workings of the scripts. For temporary use, however, they are exactly +what you want. + +Note that it is still useful to provide, say, the ability to create a fully +optimized version of a system for production use--from the F<Construct> and +F<Conscript> files. This way you can tailor the optimized system to the +platform. Where optimizer trade-offs need to be made (particular files may +not be compiled with full optimization, for example), then these can be +recorded for posterity (and reproducibility) directly in the scripts. + + + +=head2 The C<Module> method + +The C<Module> method is a combination of the C<Program> and C<Command> +methods. Rather than generating an executable program directly, this command +allows you to specify your own command to actually generate a module. The +method is invoked as follows: + + Module $env <module name>, <source or object files>, <construction command>; + +This command is useful in instances where you wish to create, for example, +dynamically loaded modules, or statically linked code libraries. + + + + +=head2 The C<RuleSet> method + +The C<RuleSet> method returns the construction variables for building +various components with one of the rule sets supported by Cons. The +currently supported rule sets are: + +=over 4 + +=item msvc + +Rules for the Microsoft Visual C++ compiler suite. + +=item unix + +Generic rules for most UNIX-like compiler suites. + +=back + +On systems with more than one available compiler suite, this allows you +to easily create side-by-side environments for building software with +multiple tools: + + $msvcenv = new cons(RuleSet("msvc")); + $cygnusenv = new cons(RuleSet("unix")); + +In the future, this could also be extended to other platforms that +have different default rule sets. + + +=head2 The C<DefaultRules> method + +The C<DefaultRules> method sets the default construction variables that +will be returned by the C<new> method to the specified arguments: + + DefaultRules(CC => 'gcc', + CFLAGS => '', + CCCOM => '%CC %CFLAGS %_IFLAGS -c %< -o %>'); + $env = new cons(); + # $env now contains *only* the CC, CFLAGS, + # and CCCOM construction variables + +Combined with the C<RuleSet> method, this also provides an easy way +to set explicitly the default build environment to use some supported +toolset other than the Cons defaults: + + # use a UNIX-like tool suite (like cygwin) on Win32 + DefaultRules(RuleSet('unix')); + $env = new cons(); + +Note that the C<DefaultRules> method completely replaces the default +construction environment with the specified arguments, it does not +simply override the existing defaults. To override one or more +variables in a supported C<RuleSet>, append the variables and values: + + DefaultRules(RuleSet('unix'), CFLAGS => '-O3'); + $env1 = new cons(); + $env2 = new cons(); + # both $env1 and $env2 have 'unix' defaults + # with CFLAGS set to '-O3' + + + + + + + + +=head2 The C<SourcePath> method + +The C<SourcePath> mathod returns the real source path name of a file, +as opposed to the path name within a build directory. It is invoked +as follows: + + $path = SourcePath <buildpath>; + + +=head2 The C<ConsPath> method + +The C<ConsPath> method returns true if the supplied path is a derivable +file, and returns undef (false) otherwise. +It is invoked as follows: + + $result = ConsPath <path>; + + +=head2 The C<SplitPath> method + +The C<SplitPath> method looks up multiple path names in a string separated +by the default path separator for the operating system (':' on UNIX +systems, ';' on Windows NT), and returns the fully-qualified names. +It is invoked as follows: + + @paths = SplitPath <pathlist>; + +The C<SplitPath> method will convert names prefixed '#' to the +appropriate top-level build name (without the '#') and will convert +relative names to top-level names. + + +=head2 The C<DirPath> method + +The C<DirPath> method returns the build path name(s) of a directory or +list of directories. It is invoked as follows: + + $cwd = DirPath <paths>; + +The most common use for the C<DirPath> method is: + + $cwd = DirPath '.'; + +to fetch the path to the current directory of a subsidiary F<Conscript> +file. + + +=head2 The C<FilePath> method + +The C<FilePath> method returns the build path name(s) of a file or +list of files. It is invoked as follows: + + $file = FilePath <path>; diff --git a/doc/user/cons.sgml b/doc/user/cons.sgml index 3024c02..448777f 100644 --- a/doc/user/cons.sgml +++ b/doc/user/cons.sgml @@ -22,6 +22,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + <para> X diff --git a/doc/user/copyright.sgml b/doc/user/copyright.sgml index 500b81c..7f6059c 100644 --- a/doc/user/copyright.sgml +++ b/doc/user/copyright.sgml @@ -26,7 +26,7 @@ <blockquote> <para> - Copyright (c) 2002, 2003 Steven Knight + SCons User's Guide Copyright (c) 2003 Steven Knight </para> </blockquote> diff --git a/doc/user/default.sgml b/doc/user/default.sgml new file mode 100644 index 0000000..bb81a3a --- /dev/null +++ b/doc/user/default.sgml @@ -0,0 +1,78 @@ +<!-- + + Copyright (c) 2001, 2002, 2003 Steven Knight + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + +<!-- + +=head1 Default targets + +Until now, we've demonstrated invoking Cons with an explicit target +to build: + + % cons hello + +Normally, Cons does not build anything unless a target is specified, +but specifying '.' (the current directory) will build everything: + + % cons # does not build anything + + % cons . # builds everything under the top-level directory + +Adding the C<Default> method to any F<Construct> or F<Conscript> file will add +the specified targets to a list of default targets. Cons will build +these defaults if there are no targets specified on the command line. +So adding the following line to the top-level F<Construct> file will mimic +Make's typical behavior of building everything by default: + + Default '.'; + +The following would add the F<hello> and F<goodbye> commands (in the +same directory as the F<Construct> or F<Conscript> file) to the default list: + + Default qw( + hello + goodbye + ); + +The C<Default> method may be used more than once to add targets to the +default list. + +--> + + <para> + + X + + </para> + + <section> + <title>The &Default; Method</title> + + <para> + + X + + </para> + + </section> diff --git a/doc/user/depends.sgml b/doc/user/depends.sgml index d95ae79..c94ac0d 100644 --- a/doc/user/depends.sgml +++ b/doc/user/depends.sgml @@ -22,9 +22,76 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + +<!-- + + + +=head2 The C<Salt> method + +The C<Salt> method adds a constant value to the signature calculation +for every derived file. It is invoked as follows: + + Salt $string; + +Changing the Salt value will force a complete rebuild of every derived +file. This can be used to force rebuilds in certain desired +circumstances. For example, + + Salt `uname -s`; + +Would force a complete rebuild of every derived file whenever the +operating system on which the build is performed (as reported by C<uname +-s>) changes. + +--> + <para> - X + So far we've seen how &SCons; handles one-time builds. + But the real point of a build tool like &SCons; + is to rebuild the necessary things when source files change. + The other side of rebuilding all the necessary things + is that &SCons; should <emphasis>not</emphasis> + unnecessarily rebuild things that have already + been built. + You can see this at work simply be re-invoking &SCons; + after building our simple &hello; example: + + </para> + + <literallayout> + % <userinput>scons .</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons .</userinput> + % + </literallayout> + + <para> + + &SCons; has remembered that the &hello; program + is up-to-date with respect to the current &hello_c; source file, + and avoids rebuilding it. + You can see this more clearly by naming + the &hello; program explicitly on the command line: + + </para> + + <literallayout> + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons hello</userinput> + scons: `hello' is up to date. + % + </literallayout> + + <para> + + (&SCons; only reports "...is up to date" + for target files named explicitly on the command line, + to avoid cluttering the output.) </para> @@ -33,14 +100,75 @@ <para> + &SCons; keeps track of whether a file has changed + based on the file's contents, + not the modification time. + This means that you may be surprised by the + behavior of &SCons; if you are used to the + &Make; convention of forcing + a rebuild by updating the file's + modification time like so: + + </para> + + <literallayout> + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>touch hello.c</userinput> + % <userinput>scons hello</userinput> + scons: `hello' is up to date. + % + </literallayout> + + <para> + + This saves time by avoiding unnecessary rebuilds when, + for example, someone rewrites the + contents of a file without making a change. + But if the contents of the file change, + then &SCons; detects the change + and rebuilds the program as required: + + </para> + + <literallayout> + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>edit hello.c</userinput> + [CHANGE THE CONTENTS OF hello.c] + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % + </literallayout> + + <para> + X </para> </section> +<!-- + +Now it turns out that F<hello.c> also includes the interface definition +file, F<world.h>: + +How does Cons know that F<hello.c> includes F<world.h>, and that F<hello.o> +must therefore be recompiled? For now, suffice it to say that when +considering whether or not F<hello.o> is up-to-date, Cons invokes a scanner +for its dependency, F<hello.c>. This scanner enumerates the files included +by F<hello.c> to come up with a list of further dependencies, beyond those +made explicit by the Cons script. This process is recursive: any files +included by included files will also be scanned. + +--> + <section> - <title>Time Stamps</title> + <title>Implicit Dependencies</title> <para> @@ -48,6 +176,135 @@ </para> + <programlisting> + #define string "world" + </programlisting> + + <programlisting> + #include "hello.h" + int + main() + { + printf("Hello, %s!\n", string); + } + </programlisting> + + <programlisting> + env = Environment(CPPPATH = '.') XXX IS CPPPATH NECESSARY? + hello = env.Program('hello.c') + </programlisting> + + <literallayout> + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons hello</userinput> + scons: `hello' is up to date. + % <userinput>edit hello.h</userinput> + [CHANGE THE CONTENTS OF hello.h] + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % + </literallayout> + + <para> + + &SCons; knows that the &hello; + program must be rebuilt + because it scans the contents of + the &hello_c; + for the #include lines that indicate + another file is being included in the compilation. + &SCons; records these as + <emphasis>implicit dependencies</emphasis> + of the target file, + Consequently, + when the &hello_h; file changes, + &SCons; realizes that the &hello_c; file includes it, + and rebuilds the resulting &hello; program + that depends on both the &hello_c; and &hello_h; files. + + </para> + + <para> + + X + +<!-- +Isn't this expensive? The answer is, it depends. If you do a full build of a +large system, the scanning time is insignificant. If you do a rebuild of a +large system, then Cons will spend a fair amount of time thinking about it +before it decides that nothing has to be done (although not necessarily more +time than make!). The good news is that Cons makes it very easy to +intelligently subset your build, when you are working on localized changes. +--> + + </para> + + </section> + + <section> + <title>The &Ignore; Method</title> + + <para> + + Sometimes it makes sense + to not rebuild a program, + even if a dependency file changes. + In this case, + you would tell &SCons; specifically + to ignore a dependency as follows: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.Ignore(hello, 'hello.h') + </programlisting> + + <!-- XXX mention that you can use arrays for target and source? --> + + <literallayout> + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons hello</userinput> + scons: `hello' is up to date. + % <userinput>edit hello.h</userinput> + [CHANGE THE CONTENTS OF hello.h] + % <userinput>scons hello</userinput> + scons: `hello' is up to date. + </literallayout> + + <para> + + Now, the above example is a little contrived, + because it's hard to imagine a real-world situation + where you wouldn't to rebuild &hello; + if the &hello_h; file changed. + A more realistic example + might be if the &hello; + program is being built in a + directory that is shared between multiple systems + that have different copies of the + &stdio_h; include file. + In that case, + &SCons; would notice the differences between + the different systems' copies of &stdio_h; + and would rebuild &hello; + each time you change systems. + You could avoid these rebuilds as follows: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.Ignore(hello, '/usr/include/stdio.h') + </programlisting> + </section> <section> @@ -55,14 +312,44 @@ <para> - X + On the other hand, + sometimes a file depends on another + file that the scanner(s) in &SCons; will not detect. + For this situation, + &SCons; allows you to specific that one file explicitly + depends on another file, + and must be rebuilt whenever that file changes, + using the &Depends; method: </para> + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.Depends(hello, 'other_file') + </programlisting> + + <!-- XXX mention that you can use arrays for target and source? --> + + <literallayout> + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons hello</userinput> + scons: `hello' is up to date. + % <userinput>edit other_file</userinput> + [CHANGE THE CONTENTS OF other_file] + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + </literallayout> + </section> + <!--> + <section> - <title>The &Ignore; Method</title> + <title>The &Salt; Method</title> <para> @@ -72,8 +359,10 @@ </section> + --> + <section> - <title>The &Salt; Method</title> + <title>Time Stamps</title> <para> diff --git a/doc/user/environments.sgml b/doc/user/environments.sgml index e0ea8ee..b06ade1 100644 --- a/doc/user/environments.sgml +++ b/doc/user/environments.sgml @@ -22,25 +22,488 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + +<!-- + +=head2 Construction environments + +A key simplification of Cons is the idea of a B<construction environment>. A +construction environment is an B<object> characterized by a set of key/value +pairs and a set of B<methods>. In order to tell Cons how to build something, +you invoke the appropriate method via an appropriate construction +environment. Consider the following example: + + + + $env = new cons( + CC => 'gcc', + LIBS => 'libworld.a' + ); + + Program $env 'hello', 'hello.c'; + +In this case, rather than using the default construction environment, as is, +we have overridden the value of C<CC> so that the GNU C Compiler equivalent +is used, instead. Since this version of B<Hello, World!> requires a library, +F<libworld.a>, we have specified that any program linked in this environment +should be linked with that library. If the library exists already, well and +good, but if not, then we'll also have to include the statement: + + + + Library $env 'libworld', 'world.c'; + +Now if you type C<cons hello>, the library will be built before the program +is linked, and, of course, C<gcc> will be used to compile both modules: + + + + % cons hello + gcc -c hello.c -o hello.o + gcc -c world.c -o world.o + ar r libworld.a world.o + ar: creating libworld.a + ranlib libworld.a + gcc -o hello hello.o libworld.a + +=head1 More on construction environments + +As previously mentioned, a B<construction environment> is an object that +has a set of keyword/value pairs and a set of methods, and which is used +to tell Cons how target files should be built. This section describes +how Cons uses and expands construction environment values to control its +build behavior. + +=head2 Construction variable expansion + +Construction variables from a construction environment are expanded +by preceding the keyword with a C<%> (percent sign): + + Construction variables: + XYZZY => 'abracadabra', + + The string: "The magic word is: %XYZZY!" + expands to: "The magic word is: abracadabra!" + +A construction variable name may be surrounded by C<{> and C<}> (curly +braces), which are stripped as part of the expansion. This can +sometimes be necessary to separate a variable expansion from trailing +alphanumeric characters: + + Construction variables: + OPT => 'value1', + OPTION => 'value2', + + The string: "%OPT %{OPT}ION %OPTION %{OPTION}" + expands to: "value1 value1ION value2 value2" + +Construction variable expansion is recursive, that is, a string +containing C<%->expansions after substitution will be re-expanded until +no further substitutions can be made: + + Construction variables: + STRING => 'The result is: %FOO', + FOO => '%BAR', + BAR => 'final value', + + The string: "The string says: %STRING" + expands to: "The string says: The result is: final value" + +If a construction variable is not defined in an environment, then the +null string is substituted: + + Construction variables: + FOO => 'value1', + BAR => 'value2', + + The string: "%FOO <%NO_VARIABLE> %BAR" + expands to: "value1 <> value2" + +A doubled C<%%> will be replaced by a single C<%>: + + The string: "Here is a percent sign: %%" + expands to: "Here is a percent sign: %" + +=head2 Default construction variables + +When you specify no arguments when creating a new construction +environment: + + $env = new cons(); + +Cons creates a reference to a new, default construction +environment. This contains a number of construction variables and some +methods. At the present writing, the default construction variables on a +UNIX system are: + + CC => 'cc', + CFLAGS => '', + CCCOM => '%CC %CFLAGS %_IFLAGS -c %< -o %>', + CXX => '%CC', + CXXFLAGS => '%CFLAGS', + CXXCOM => '%CXX %CXXFLAGS %_IFLAGS -c %< -o %>', + INCDIRPREFIX => '-I', + INCDIRSUFFIX => '', + LINK => '%CXX', + LINKCOM => '%LINK %LDFLAGS -o %> %< %_LDIRS %LIBS', + LINKMODULECOM => '%LD -r -o %> %<', + LIBDIRPREFIX => '-L', + LIBDIRSUFFIX => '', + AR => 'ar', + ARFLAGS => 'r', + ARCOM => ['%AR %ARFLAGS %> %<', '%RANLIB %>'], + RANLIB => 'ranlib', + AS => 'as', + ASFLAGS => '', + ASCOM => '%AS %ASFLAGS %< -o %>', + LD => 'ld', + LDFLAGS => '', + PREFLIB => 'lib', + SUFLIB => '.a', + SUFLIBS => '.so:.a', + SUFOBJ => '.o', + SIGNATURE => [ '*' => 'build' ], + ENV => { 'PATH' => '/bin:/usr/bin' }, + + +And on a Win32 system (Windows NT), the default construction variables +are (unless the default rule style is set using the B<DefaultRules> +method): + + CC => 'cl', + CFLAGS => '/nologo', + CCCOM => '%CC %CFLAGS %_IFLAGS /c %< /Fo%>', + CXXCOM => '%CXX %CXXFLAGS %_IFLAGS /c %< /Fo%>', + INCDIRPREFIX => '/I', + INCDIRSUFFIX => '', + LINK => 'link', + LINKCOM => '%LINK %LDFLAGS /out:%> %< %_LDIRS %LIBS', + LINKMODULECOM => '%LD /r /o %> %<', + LIBDIRPREFIX => '/LIBPATH:', + LIBDIRSUFFIX => '', + AR => 'lib', + ARFLAGS => '/nologo ', + ARCOM => "%AR %ARFLAGS /out:%> %<", + RANLIB => '', + LD => 'link', + LDFLAGS => '/nologo ', + PREFLIB => '', + SUFEXE => '.exe', + SUFLIB => '.lib', + SUFLIBS => '.dll:.lib', + SUFOBJ => '.obj', + SIGNATURE => [ '*' => 'build' ], + +These variables are used by the various methods associated with the +environment. In particular, any method that ultimately invokes an external +command will substitute these variables into the final command, as +appropriate. For example, the C<Objects> method takes a number of source +files and arranges to derive, if necessary, the corresponding object +files: + + Objects $env 'foo.c', 'bar.c'; + +This will arrange to produce, if necessary, F<foo.o> and F<bar.o>. The +command invoked is simply C<%CCCOM>, which expands, through substitution, +to the appropriate external command required to build each object. The +substitution rules will be discussed in detail in the next section. + +The construction variables are also used for other purposes. For example, +C<CPPPATH> is used to specify a colon-separated path of include +directories. These are intended to be passed to the C preprocessor and are +also used by the C-file scanning machinery to determine the dependencies +involved in a C Compilation. + +Variables beginning with underscore are created by various methods, +and should normally be considered ``internal'' variables. For example, +when a method is called which calls for the creation of an object from +a C source, the variable C<_IFLAGS> is created: this corresponds to the +C<-I> switches required by the C compiler to represent the directories +specified by C<CPPPATH>. + +Note that, for any particular environment, the value of a variable is set +once, and then never reset (to change a variable, you must create a new +environment. Methods are provided for copying existing environments for this +purpose). Some internal variables, such as C<_IFLAGS> are created on demand, +but once set, they remain fixed for the life of the environment. + +The C<CFLAGS>, C<LDFLAGS>, and C<ARFLAGS> variables all supply a place +for passing options to the compiler, loader, and archiver, respectively. + +The C<INCDIRPREFIX> and C<INCDIRSUFFIX> variables specify option +strings to be appended to the beginning and end, respectively, of each +include directory so that the compiler knows where to find F<.h> files. +Similarly, the C<LIBDIRPREFIX> and C<LIBDIRSUFFIX> variables specify the +option string to be appended to the beginning of and end, respectively, +of each directory that the linker should search for libraries. + +Another variable, C<ENV>, is used to determine the system environment during +the execution of an external command. By default, the only environment +variable that is set is C<PATH>, which is the execution path for a UNIX +command. For the utmost reproducibility, you should really arrange to set +your own execution path, in your top-level F<Construct> file (or perhaps by +importing an appropriate construction package with the Perl C<use> +command). The default variables are intended to get you off the ground. + +=head2 Expanding variables in construction commands + +Within a construction command, construction variables will be expanded +according to the rules described above. In addition to normal variable +expansion from the construction environment, construction commands also +expand the following pseudo-variables to insert the specific input and +output files in the command line that will be executed: + +=over 10 + +=item %> + +The target file name. In a multi-target command, this expands to the +first target mentioned.) + +=item %0 + +Same as C<%E<gt>>. + +=item %1, %2, ..., %9 + +These refer to the first through ninth input file, respectively. + +=item %E<lt> + +The full set of input file names. If any of these have been used +anywhere else in the current command line (via C<%1>, C<%2>, etc.), then +those will be deleted from the list provided by C<%E<lt>>. Consider the +following command found in a F<Conscript> file in the F<test> directory: + + Command $env 'tgt', qw(foo bar baz), qq( + echo %< -i %1 > %> + echo %< -i %2 >> %> + echo %< -i %3 >> %> + ); + +If F<tgt> needed to be updated, then this would result in the execution of +the following commands, assuming that no remapping has been established for +the F<test> directory: + + echo test/bar test/baz -i test/foo > test/tgt + echo test/foo test/baz -i test/bar >> test/tgt + echo test/foo test/bar -i test/baz >> test/tgt + +=back + +Any of the above pseudo-variables may be followed immediately by one of +the following suffixes to select a portion of the expanded path name: + + :a the absolute path to the file name + :b the directory plus the file name stripped of any suffix + :d the directory + :f the file name + :s the file name suffix + :F the file name stripped of any suffix + :S the absolute path path to a Linked source file + +Continuing with the above example, C<%E<lt>:f> would expand to C<foo bar baz>, +and C<%E<gt>:d> would expand to C<test>. + +There are additional C<%> elements which affect the command line(s): + +=over 10 + +=item %[ %] + +It is possible to programmatically rewrite part of the command by +enclosing part of it between C<%[> and C<%]>. This will call the +construction variable named as the first word enclosed in the brackets +as a Perl code reference; the results of this call will be used to +replace the contents of the brackets in the command line. For example, +given an existing input file named F<tgt.in>: + + @keywords = qw(foo bar baz); + $env = new cons(X_COMMA => sub { join(",", @_) }); + Command $env 'tgt', 'tgt.in', qq( + echo '# Keywords: %[X_COMMA @keywords %]' > %> + cat %< >> %> + ); + +This will execute: + + echo '# Keywords: foo,bar,baz' > tgt + cat tgt.in >> tgt + +=item %( %) + +Cons includes the text of the command line in the MD5 signature for a +build, so that targets get rebuilt if you change the command line (to +add or remove an option, for example). Command-line text in between +C<%(> and C<%)>, however, will be ignored for MD5 signature calculation. + +Internally, Cons uses C<%(> and C<%)> around include and library +directory options (C<-I> and C<-L> on UNIX systems, C</I> and +C</LIBPATH> on Windows NT) to avoid rebuilds just because the directory +list changes. Rebuilds occur only if the changed directory list causes +any included I<files> to change, and a changed include file is detected +by the MD5 signature calculation on the actual file contents. + +=back + +=head2 Expanding construction variables in file names + +Cons expands construction variables in the source and target file names +passed to the various construction methods according to the expansion +rules described above: + + $env = new cons( + DESTDIR => 'programs', + SRCDIR => 'src', + ); + Program $env '%DESTDIR/hello', '%SRCDIR/hello.c'; + +This allows for flexible configuration, through the construction +environment, of directory names, suffixes, etc. + +=head1 Default construction methods + +The list of default construction methods includes the following: + + +=head2 The C<new> constructor + +The C<new> method is a Perl object constructor. That is, it is not invoked +via a reference to an existing construction environment B<reference>, but, +rather statically, using the name of the Perl B<package> where the +constructor is defined. The method is invoked like this: + + $env = new cons(<overrides>); + +The environment you get back is blessed into the package C<cons>, which +means that it will have associated with it the default methods described +below. Individual construction variables can be overridden by providing +name/value pairs in an override list. Note that to override any command +environment variable (i.e. anything under C<ENV>), you will have to override +all of them. You can get around this difficulty by using the C<copy> method +on an existing construction environment. + + +=head2 The C<clone> method + +The C<clone> method creates a clone of an existing construction environment, +and can be called as in the following example: + + $env2 = $env1->clone(<overrides>); + +You can provide overrides in the usual manner to create a different +environment from the original. If you just want a new name for the same +environment (which may be helpful when exporting environments to existing +components), you can just use simple assignment. + + +=head2 The C<copy> method + +The C<copy> method extracts the externally defined construction variables +from an environment and returns them as a list of name/value +pairs. Overrides can also be provided, in which case, the overridden values +will be returned, as appropriate. The returned list can be assigned to a +hash, as shown in the prototype, below, but it can also be manipulated in +other ways: + + %env = $env1->copy(<overrides>); + +The value of C<ENV>, which is itself a hash, is also copied to a new hash, +so this may be changed without fear of affecting the original +environment. So, for example, if you really want to override just the +C<PATH> variable in the default environment, you could do the following: + + %cons = new cons()->copy(); + $cons{ENV}{PATH} = "<your path here>"; + $cons = new cons(%cons); + +This will leave anything else that might be in the default execution +environment undisturbed. + + + +=head2 Overriding construction variables + +There are several ways of extending Cons, which vary in degree of +difficulty. The simplest method is to define your own construction +environment, based on the default environment, but modified to reflect your +particular needs. This will often suffice for C-based applications. You can +use the C<new> constructor, and the C<clone> and C<copy> methods to create +hybrid environments. These changes can be entirely transparent to the +underlying F<Conscript> files. + +--> + <para> X - </para> +<!-- - <section> - <title>The &Environment; Constructor</title> +A key simplification of Cons is the idea of a B<construction environment>. A +construction environment is an B<object> characterized by a set of key/value +pairs and a set of B<methods>. In order to tell Cons how to build something, +you invoke the appropriate method via an appropriate construction +environment. Consider the following example: - <para> - X - </para> + $env = new cons( + CC => 'gcc', + LIBS => 'libworld.a' + ); - </section> + Program $env 'hello', 'hello.c'; + +In this case, rather than using the default construction environment, as is, +we have overridden the value of C<CC> so that the GNU C Compiler equivalent +is used, instead. Since this version of B<Hello, World!> requires a library, +F<libworld.a>, we have specified that any program linked in this environment +should be linked with that library. If the library exists already, well and +good, but if not, then we'll also have to include the statement: + + + + Library $env 'libworld', 'world.c'; + +Now if you type C<cons hello>, the library will be built before the program +is linked, and, of course, C<gcc> will be used to compile both modules: + + + + % cons hello + gcc -c hello.c -o hello.o + gcc -c world.c -o world.o + ar r libworld.a world.o + ar: creating libworld.a + ranlib libworld.a + gcc -o hello hello.o libworld.a + +--> + + </para> + + <programlisting> + optimize = Environment(CCFLAGS = '-O2') + debug = Environment(CCFLAGS = '-g') + + o = optimize.Object('foo-opt', 'foo.c') + optimize.Program(o) + + d = debug.Object('foo-debug', 'foo.c') + debug.Program(d) + </programlisting> + + <literallayout> + % <userinput>scons .</userinput> + cc -c -g foo.c -o foo-debug.o + cc -o foo-debug foo-debug.o + cc -c -O2 foo.c -o foo-opt.o + cc -o foo-opt foo-opt.o + </literallayout> <section> - <title>The &Clone; Method</title> + <title>The &Environment; Constructor</title> <para> diff --git a/doc/user/errors.sgml b/doc/user/errors.sgml index 3024c02..448777f 100644 --- a/doc/user/errors.sgml +++ b/doc/user/errors.sgml @@ -22,6 +22,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + <para> X diff --git a/doc/user/example.sgml b/doc/user/example.sgml index 3024c02..448777f 100644 --- a/doc/user/example.sgml +++ b/doc/user/example.sgml @@ -22,6 +22,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + <para> X diff --git a/doc/user/help.sgml b/doc/user/help.sgml new file mode 100644 index 0000000..7c1732e --- /dev/null +++ b/doc/user/help.sgml @@ -0,0 +1,88 @@ +<!-- + + Copyright (c) 2001, 2002, 2003 Steven Knight + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + + <para> + + X + + </para> + + <section> + <title>Providing build-specific help instructions</title> + + <para> + + It's often very useful to be able to give + users some help that describes the + specific targets, build options, etc., + that can be used for the build. + &SCons; provides the &Help; function + to allow you to specify this help text: + + </para> + + <programlisting> + Help(""" + Type: 'scons program' to build the production program, + 'scons debug' to build the debug version. + """) + </programlisting> + + <para> + + (Note the above use of the Python triple-quote syntax, + which comes in very handy for + specifying multi-line strings like help text.) + + </para> + + <para> + + When the &SConstruct; or &SConscript; files + contain such a call to the &Help; function, + the specified help text will be displayed in response to + the &SCons; <literal>-h</literal> option: + + </para> + + <literallayout> + % <userinput>scons -h</userinput> + Type: 'scons program' to build the production program, + 'scons debug' to build the debug version. + </literallayout> + + <para> + + If there is no &Help; text in the &SConstruct; or + &SConscript; files, + &SCons; will revert to displaying its + standard list and description of available command-line + options. + This list is also always displayed whenever + the <literal>-H</literal> option is used. + + </para> + + </section> diff --git a/doc/user/hierarchy.sgml b/doc/user/hierarchy.sgml index 3f65aeb..aa56c8d 100644 --- a/doc/user/hierarchy.sgml +++ b/doc/user/hierarchy.sgml @@ -22,6 +22,204 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + +<!-- + +=head2 A hierarchy of build scripts + +A larger build, in Cons, is organized by creating a hierarchy of B<build +scripts>. At the top of the tree is a script called F<Construct>. The rest +of the scripts, by convention, are each called F<Conscript>. These scripts +are connected together, very simply, by the C<Build>, C<Export>, and +C<Import> commands. + + +=head2 The Build command + +The C<Build> command takes a list of F<Conscript> file names, and arranges +for them to be included in the build. For example: + + Build qw( + drivers/display/Conscript + drivers/mouse/Conscript + parser/Conscript + utilities/Conscript + ); + +This is a simple two-level hierarchy of build scripts: all the subsidiary +F<Conscript> files are mentioned in the top-level F<Construct> file. Notice +that not all directories in the tree necessarily have build scripts +associated with them. + +This could also be written as a multi-level script. For example, the +F<Construct> file might contain this command: + + Build qw( + parser/Conscript + drivers/Conscript + utilities/Conscript + ); + +and the F<Conscript> file in the F<drivers> directory might contain this: + + Build qw( + display/Conscript + mouse/Conscript + ); + +Experience has shown that the former model is a little easier to understand, +since the whole construction tree is laid out in front of you, at the +top-level. Hybrid schemes are also possible. A separately maintained +component that needs to be incorporated into a build tree, for example, +might hook into the build tree in one place, but define its own construction +hierarchy. + +By default, Cons does not change its working directory to the directory +containing a subsidiary F<Conscript> file it is including. This behavior +can be enabled for a build by specifying, in the top-level F<Construct> +file: + + Conscript_chdir 1; + +When enabled, Cons will change to the subsidiary F<Conscript> file's +containing directory while reading in that file, and then change back +to the top-level directory once the file has been processed. + +It is expected that this behavior will become the default in some future +version of Cons. To prepare for this transition, builds that expect +Cons to remain at the top of the build while it reads in a subsidiary +F<Conscript> file should explicitly disable this feature as follows: + + Conscript_chdir 0; + +=head2 Relative, top-relative, and absolute file names + +You may have noticed that the file names specified to the Build command are +relative to the location of the script it is invoked from. This is generally +true for other filename arguments to other commands, too, although we might +as well mention here that if you begin a file name with a hash mark, ``#'', +then that file is interpreted relative to the top-level directory (where the +F<Construct> file resides). And, not surprisingly, if you begin it with ``/'', +then it is considered to be an absolute pathname. This is true even on +systems which use a back slash rather than a forward slash to name absolute +paths. + +(There is another file prefix, ``!'', that is interpreted specially by +Cons. See discussion of the C<Link> command, below, for details.) + + +=head2 Using modules in build scripts + +You may pull modules into each F<Conscript> file using the normal Perl +C<use> or C<require> statements: + + use English; + require My::Module; + +Each C<use> or C<require> only affects the one F<Conscript> file in which +it appears. To use a module in multiple F<Conscript> files, you must +put a C<use> or C<require> statement in each one that needs the module. + + +=head2 Scope of variables + +The top-level F<Construct> file and all F<Conscript> files begin life in +a common, separate Perl package. B<Cons> controls the symbol table for +the package so that, the symbol table for each script is empty, except +for the F<Construct> file, which gets some of the command line arguments. +All of the variables that are set or used, therefore, are set by the +script itself, not by some external script. + +Variables can be explicitly B<imported> by a script from its parent +script. To import a variable, it must have been B<exported> by the parent +and initialized (otherwise an error will occur). + + +=head2 The Export command + +The C<Export> command is used as in the following example: + + $env = new cons(); + $INCLUDE = "#export/include"; + $LIB = "#export/lib"; + Export qw( env INCLUDE LIB ); + Build qw( util/Conscript ); + +The values of the simple variables mentioned in the C<Export> list will be +squirreled away by any subsequent C<Build> commands. The C<Export> command +will only export Perl B<scalar> variables, that is, variables whose name +begins with C<$>. Other variables, objects, etc. can be exported by +reference, but all scripts will refer to the same object, and this object +should be considered to be read-only by the subsidiary scripts and by the +original exporting script. It's acceptable, however, to assign a new value +to the exported scalar variable, that won't change the underlying variable +referenced. This sequence, for example, is OK: + + $env = new cons(); + Export qw( env INCLUDE LIB ); + Build qw( util/Conscript ); + $env = new cons(CFLAGS => '-O'); + Build qw( other/Conscript ); + +It doesn't matter whether the variable is set before or after the C<Export> +command. The important thing is the value of the variable at the time the +C<Build> command is executed. This is what gets squirreled away. Any +subsequent C<Export> commands, by the way, invalidate the first: you must +mention all the variables you wish to export on each C<Export> command. + + +=head2 The Import command + +Variables exported by the C<Export> command can be imported into subsidiary +scripts by the C<Import> command. The subsidiary script always imports +variables directly from the superior script. Consider this example: + + Import qw( env INCLUDE ); + +This is only legal if the parent script exported both C<$env> and +C<$INCLUDE>. It also must have given each of these variables values. It is +OK for the subsidiary script to only import a subset of the exported +variables (in this example, C<$LIB>, which was exported by the previous +example, is not imported). + +All the imported variables are automatically re-exported, so the sequence: + + Import qw ( env INCLUDE ); + Build qw ( beneath-me/Conscript ); + +will supply both C<$env> and C<$INCLUDE> to the subsidiary file. If only +C<$env> is to be exported, then the following will suffice: + + Import qw ( env INCLUDE ); + Export qw ( env ); + Build qw ( beneath-me/Conscript ); + +Needless to say, the variables may be modified locally before invoking +C<Build> on the subsidiary script. + + +=head2 Build script evaluation order + +The only constraint on the ordering of build scripts is that superior +scripts are evaluated before their inferior scripts. The top-level +F<Construct> file, for instance, is evaluated first, followed by any +inferior scripts. This is all you really need to know about the evaluation +order, since order is generally irrelevant. Consider the following C<Build> +command: + + Build qw( + drivers/display/Conscript + drivers/mouse/Conscript + parser/Conscript + utilities/Conscript + ); + +We've chosen to put the script names in alphabetical order, simply because +that's the most convenient for maintenance purposes. Changing the order will +make no difference to the build. + +--> + <para> X diff --git a/doc/user/install.sgml b/doc/user/install.sgml new file mode 100644 index 0000000..530fa7a --- /dev/null +++ b/doc/user/install.sgml @@ -0,0 +1,97 @@ +<!-- + + Copyright (c) 2001, 2002, 2003 Steven Knight + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + +<!-- + +=head2 The C<Install> method + +The C<Install> method arranges for the specified files to be installed in +the specified directory. The installation is optimized: the file is not +copied if it can be linked. If this is not the desired behavior, you will +need to use a different method to install the file. It is called as follows: + + Install $env <directory>, <names>; + +Note that, while the files to be installed may be arbitrarily named, +only the last component of each name is used for the installed target +name. So, for example, if you arrange to install F<foo/bar> in F<baz>, +this will create a F<bar> file in the F<baz> directory (not F<foo/bar>). + + +=head2 The C<InstallAs> method + +The C<InstallAs> method arranges for the specified source file(s) to be +installed as the specified target file(s). Multiple files should be +specified as a file list. The installation is optimized: the file is not +copied if it can be linked. If this is not the desired behavior, you will +need to use a different method to install the file. It is called as follows: + +C<InstallAs> works in two ways: + +Single file install: + + InstallAs $env TgtFile, SrcFile; + +Multiple file install: + + InstallAs $env ['tgt1', 'tgt2'], ['src1', 'src2']; + +Or, even as: + + @srcs = qw(src1 src2 src3); + @tgts = qw(tgt1 tgt2 tgt3); + InstallAs $env [@tgts], [@srcs]; + +Both the target and the sources lists should be of the same length. + +--> + + <para> + + X + + </para> + + <section> + <title>The &Install; Builder</title> + + <para> + + X + + </para> + + </section> + + <section> + <title>The &InstallAs; Method</title> + + <para> + + X + + </para> + + </section> diff --git a/doc/user/library.sgml b/doc/user/library.sgml new file mode 100644 index 0000000..0c9292c --- /dev/null +++ b/doc/user/library.sgml @@ -0,0 +1,81 @@ +<!-- + + Copyright (c) 2001, 2002, 2003 Steven Knight + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + +<!-- + +=head2 The C<Library> method + +The C<Library> method arranges to create the specified library from the +specified object files. It is invoked as follows: + + Library $env <library name>, <source or object files>; + +The library name will have the value of the C<SUFLIB> construction +variable appended (by default, C<.lib> on Win32 systems, C<.a> on Unix +systems) if the suffix is not already present. + +Source files may be specified in place of objects files-,-the C<Objects> +method will be invoked to arrange the conversion of all the files into +object files, and hence all the observations about the C<Objects> method, +above, apply to this method also. + +The actual creation of the library will be handled by an external +command which results from expanding the C<ARCOM> construction variable, +with C<%E<lt>> set to the library members (in the order presented), +and C<%E<gt>> to the library to be created. (See the section above +on construction variable expansion for details.) The user may set +variables in the construction environment which will affect the +operation of the command. These include C<AR>, the archive program +to use, C<ARFLAGS>, which can be used to modify the flags given to +the program specified by C<AR>, and C<RANLIB>, the name of a archive +index generation program, if needed (if the particular need does not +require the latter functionality, then C<ARCOM> must be redefined to not +reference C<RANLIB>). + +The C<Library> method allows the same library to be specified in multiple +method invocations. All of the contributing objects from all the invocations +(which may be from different directories) are combined and generated by a +single archive command. Note, however, that if you prune a build so that +only part of a library is specified, then only that part of the library will +be generated (the rest will disappear!). + +--> + + <para> + + X + + </para> + + <section> + <title>The &Library; Builder</title> + + <para> + + X + + </para> + + </section> diff --git a/doc/user/main.sgml b/doc/user/main.sgml index ca07ce4..bb64b72 100644 --- a/doc/user/main.sgml +++ b/doc/user/main.sgml @@ -32,22 +32,33 @@ <!ENTITY % scons SYSTEM "../scons.mod"> %scons; + <!ENTITY actions SYSTEM "actions.sgml"> + <!ENTITY alias SYSTEM "alias.sgml"> <!ENTITY builders SYSTEM "builders.sgml"> <!ENTITY caching SYSTEM "caching.sgml"> + <!ENTITY command SYSTEM "command.sgml"> <!ENTITY cons SYSTEM "cons.sgml"> <!ENTITY copyright SYSTEM "copyright.sgml"> + <!ENTITY default SYSTEM "default.sgml"> <!ENTITY depends SYSTEM "depends.sgml"> <!ENTITY environments SYSTEM "environments.sgml"> <!ENTITY errors SYSTEM "errors.sgml"> <!ENTITY example SYSTEM "example.sgml"> + <!ENTITY help SYSTEM "help.sgml"> <!ENTITY hierarchy SYSTEM "hierarchy.sgml"> + <!ENTITY install SYSTEM "install.sgml"> + <!ENTITY library SYSTEM "library.sgml"> <!ENTITY make SYSTEM "make.sgml"> <!ENTITY more SYSTEM "more.sgml"> + <!ENTITY object SYSTEM "object.sgml"> + <!ENTITY precious SYSTEM "precious.sgml"> <!ENTITY preface SYSTEM "preface.sgml"> + <!ENTITY program SYSTEM "program.sgml"> <!ENTITY reference SYSTEM "reference.sgml"> <!ENTITY repositories SYSTEM "repositories.sgml"> <!ENTITY run SYSTEM "run.sgml"> <!ENTITY scanners SYSTEM "scanners.sgml"> + <!ENTITY separate SYSTEM "separate.sgml"> <!ENTITY simple SYSTEM "simple.sgml"> <!ENTITY troubleshoot SYSTEM "troubleshoot.sgml"> <!ENTITY variants SYSTEM "variants.sgml"> @@ -100,17 +111,64 @@ &depends; </chapter> + + + <chapter id="chap-default"> + <title>Default Targets</title> + &default; + </chapter> + + <chapter id="chap-help"> + <title>Providing Build Help</title> + &help; + </chapter> + + <chapter id="chap-install"> + <title>Installing Files in Other Directories</title> + &install; + </chapter> + + <chapter id="chap-program"> + <title>The Program Builder</title> + &program; + </chapter> + + <chapter id="chap-library"> + <title>The Library Builder</title> + &library; + </chapter> + <chapter id="chap-more"> <title>More Things to Do With Builds</title> &more; </chapter> + <chapter id="chap-command"> + <title>The Command Builder</title> + &command; + </chapter> + + <chapter id="chap-object"> + <title>The Object Builder</title> + &object; + </chapter> + + <chapter id="chap-precious"> + <title>Preventing Removal of Targets</title> + &precious; + </chapter> + <chapter id="chap-hierarchical"> - <title>Hierarchial Builds</title> + <title>Hierarchical Builds</title> &hierarchy; </chapter> - <chapter id="chap-variant"> + <chapter id="chap-separate"> + <title>Separating Source and Build Directories</title> + &separate; + </chapter> + + <chapter id="chap-variants"> <title>Variant Builds</title> &variants; </chapter> @@ -120,6 +178,11 @@ &builders; </chapter> + <chapter id="chap-actions"> + <title>SCons Actions</title> + &actions; + </chapter> + <chapter id="chap-scanners"> <title>Writing Scanners</title> &scanners; @@ -140,6 +203,11 @@ &run; </chapter> + <chapter id="chap-alias"> + <title>Alias Targets</title> + &alias; + </chapter> + <chapter id="chap-troubleshooting"> <title>Troubleshooting</title> &troubleshoot; diff --git a/doc/user/make.sgml b/doc/user/make.sgml index 3024c02..5666ea6 100644 --- a/doc/user/make.sgml +++ b/doc/user/make.sgml @@ -22,6 +22,76 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + +<!-- + +=head1 Why Cons? Why not Make? + +Cons is a B<make> replacement. In the following paragraphs, we look at a few +of the undesirable characteristics of make, and typical build environments +based on make, that motivated the development of Cons. + +=head2 Build complexity + +Traditional make-based systems of any size tend to become quite complex. The +original make utility and its derivatives have contributed to this tendency +in a number of ways. Make is not good at dealing with systems that are +spread over multiple directories. Various work-arounds are used to overcome +this difficulty; the usual choice is for make to invoke itself recursively +for each sub-directory of a build. This leads to complicated code, in which +it is often unclear how a variable is set, or what effect the setting of a +variable will have on the build as a whole. The make scripting language has +gradually been extended to provide more possibilities, but these have +largely served to clutter an already overextended language. Often, builds +are done in multiple passes in order to provide appropriate products from +one directory to another directory. This represents a further increase in +build complexity. + + +=head2 Build reproducibility + +The bane of all makes has always been the correct handling of +dependencies. Most often, an attempt is made to do a reasonable job of +dependencies within a single directory, but no serious attempt is made to do +the job between directories. Even when dependencies are working correctly, +make's reliance on a simple time stamp comparison to determine whether a +file is out of date with respect to its dependents is not, in general, +adequate for determining when a file should be rederived. If an external +library, for example, is rebuilt and then ``snapped'' into place, the +timestamps on its newly created files may well be earlier than the last +local build, since it was built before it became visible. + + +=head2 Variant builds + +Make provides only limited facilities for handling variant builds. With the +proliferation of hardware platforms and the need for debuggable +vs. optimized code, the ability to easily create these variants is +essential. More importantly, if variants are created, it is important to +either be able to separate the variants or to be able to reproduce the +original or variant at will. With make it is very difficult to separate the +builds into multiple build directories, separate from the source. And if +this technique isn't used, it's also virtually impossible to guarantee at +any given time which variant is present in the tree, without resorting to a +complete rebuild. + + +=head2 Repositories + +Make provides only limited support for building software from code that +exists in a central repository directory structure. The VPATH feature of +GNU make (and some other make implementations) is intended to provide this, +but doesn't work as expected: it changes the path of target file to the +VPATH name too early in its analysis, and therefore searches for all +dependencies in the VPATH directory. To ensure correct development builds, +it is important to be able to create a file in a local build directory and +have any files in a code repository (a VPATH directory, in make terms) that +depend on the local file get rebuilt properly. This isn't possible with +VPATH, without coding a lot of complex repository knowledge directly into +the makefiles. + +--> + <para> X diff --git a/doc/user/more.sgml b/doc/user/more.sgml index 1c298a8..7defa41 100644 --- a/doc/user/more.sgml +++ b/doc/user/more.sgml @@ -22,6 +22,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + <para> X @@ -29,72 +30,6 @@ </para> <section> - <title>The &InstallAs; Method</title> - - <para> - - X - - </para> - - </section> - - <section> - <title>The &Precious; Method</title> - - <para> - - X - - </para> - - </section> - - <section> - <title>The &Command; Method</title> - - <para> - - X - - </para> - - </section> - - <section> - <title>The &Objects; Method</title> - - <para> - - X - - </para> - - </section> - - <section> - <title>The &Program; Method</title> - - <para> - - X - - </para> - - </section> - - <section> - <title>The &Library; Method</title> - - <para> - - X - - </para> - - </section> - - <section> <title>The &Module; Method</title> <para> diff --git a/doc/user/object.sgml b/doc/user/object.sgml new file mode 100644 index 0000000..9e887d8 --- /dev/null +++ b/doc/user/object.sgml @@ -0,0 +1,71 @@ +<!-- + + Copyright (c) 2001, 2002, 2003 Steven Knight + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + +<!-- + +=head2 The C<Objects> method + +The C<Objects> method arranges to create the object files that correspond to +the specified source files. It is invoked as shown below: + + @files = Objects $env <source or object files>; + +Under Unix, source files ending in F<.s> and F<.c> are currently +supported, and will be compiled into a name of the same file ending +in F<.o>. By default, all files are created by invoking the external +command which results from expanding the C<CCCOM> construction variable, +with C<%E<lt>> and C<%E<gt>> set to the source and object files, +respectively. (See the section above on construction variable expansion +for details). The variable C<CPPPATH> is also used when scanning source +files for dependencies. This is a colon separated list of pathnames, and +is also used to create the construction variable C<_IFLAGS,> which will +contain the appropriate list of -C<I> options for the compilation. Any +relative pathnames in C<CPPPATH> is interpreted relative to the +directory in which the associated construction environment was created +(absolute and top-relative names may also be used). This variable is +used by C<CCCOM>. The behavior of this command can be modified by +changing any of the variables which are interpolated into C<CCCOM>, such +as C<CC>, C<CFLAGS>, and, indirectly, C<CPPPATH>. It's also possible +to replace the value of C<CCCOM>, itself. As a convenience, this file +returns the list of object filenames. + +--> + + <para> + + X + + </para> + + <section> + <title>The &Object; Method</title> + + <para> + + X + + </para> + + </section> diff --git a/doc/user/precious.sgml b/doc/user/precious.sgml new file mode 100644 index 0000000..9cd2a43 --- /dev/null +++ b/doc/user/precious.sgml @@ -0,0 +1,69 @@ +<!-- + + Copyright (c) 2001, 2002, 2003 Steven Knight + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + +<!-- + +=head2 The C<Precious> method + +The C<Precious> method asks cons not to delete the specified file or +list of files before building them again. It is invoked as: + + Precious <files>; + +This is especially useful for allowing incremental updates to libraries +or debug information files which are updated rather than rebuilt anew each +time. Cons will still delete the files when the C<-r> flag is specified. + +=head2 The C<AfterBuild> method + +The C<AfterBuild> method evaluates the specified perl string after +building the given file or files (or finding that they are up to date). +The eval will happen once per specified file. C<AfterBuild> is called +as follows: + + AfterBuild $env 'foo.o', qq(print "foo.o is up to date!\n"); + +The perl string is evaluated in the C<script> package, and has access +to all variables and subroutines defined in the F<Conscript> file in +which the C<AfterBuild> method is called. + +--> + + <para> + + X + + </para> + + <section> + <title>The &Precious; Method</title> + + <para> + + X + + </para> + + </section> diff --git a/doc/user/preface.sgml b/doc/user/preface.sgml index 3421702..82ea44a 100644 --- a/doc/user/preface.sgml +++ b/doc/user/preface.sgml @@ -22,6 +22,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + <para> X diff --git a/doc/user/program.sgml b/doc/user/program.sgml new file mode 100644 index 0000000..30f90d2 --- /dev/null +++ b/doc/user/program.sgml @@ -0,0 +1,77 @@ +<!-- + + Copyright (c) 2001, 2002, 2003 Steven Knight + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + +<!-- + +=head2 The C<Program> method + +The C<Program> method arranges to link the specified program with the +specified object files. It is invoked in the following manner: + + Program $env <program name>, <source or object files>; + +The program name will have the value of the C<SUFEXE> construction +variable appended (by default, C<.exe> on Win32 systems, nothing on Unix +systems) if the suffix is not already present. + +Source files may be specified in place of objects files-,-the C<Objects> +method will be invoked to arrange the conversion of all the files into +object files, and hence all the observations about the C<Objects> method, +above, apply to this method also. + +The actual linking of the program will be handled by an external command +which results from expanding the C<LINKCOM> construction variable, with +C<%E<lt>> set to the object files to be linked (in the order presented), +and C<%E<gt>> set to the target. (See the section above on construction +variable expansion for details.) The user may set additional variables +in the construction environment, including C<LINK>, to define which +program to use for linking, C<LIBPATH>, a colon-separated list of +library search paths, for use with library specifications of the form +I<-llib>, and C<LIBS>, specifying the list of libraries to link against +(in either I<-llib> form or just as pathnames. Relative pathnames in +both C<LIBPATH> and C<LIBS> are interpreted relative to the directory +in which the associated construction environment is created (absolute +and top-relative names may also be used). Cons automatically sets up +dependencies on any libraries mentioned in C<LIBS>: those libraries will +be built before the command is linked. + +--> + + <para> + + X + + </para> + + <section> + <title>The &Program; Builder</title> + + <para> + + X + + </para> + + </section> diff --git a/doc/user/reference.sgml b/doc/user/reference.sgml index 57f58d8..ef8e5a9 100644 --- a/doc/user/reference.sgml +++ b/doc/user/reference.sgml @@ -22,6 +22,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + <para> X diff --git a/doc/user/repositories.sgml b/doc/user/repositories.sgml index 3f0a597..4acc943 100644 --- a/doc/user/repositories.sgml +++ b/doc/user/repositories.sgml @@ -22,29 +22,426 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + +<!-- + + +=head2 Repository dependency analysis + +Due to its built-in scanning, Cons will search the specified repository +trees for included F<.h> files. Unless the compiler also knows about the +repository trees, though, it will be unable to find F<.h> files that only +exist in a repository. If, for example, the F<hello.c> file includes the +F<hello.h> file in its current directory: + + % cons -R /usr/all/repository hello + gcc -c /usr/all/repository/hello.c -o hello.o + /usr/all/repository/hello.c:1: hello.h: No such file or directory + +Solving this problem forces some requirements onto the way construction +environments are defined and onto the way the C C<#include> preprocessor +directive is used to include files. + +In order to inform the compiler about the repository trees, Cons will add +appropriate C<-I> flags to the compilation commands. This means that the +C<CPPPATH> variable in the construction environment must explicitly specify +all subdirectories which are to be searched for included files, including the +current directory. Consequently, we can fix the above example by changing +the environment creation in the F<Construct> file as follows: + + $env = new cons( + CC => 'gcc', + CPPPATH => '.', + LIBS => 'libworld.a', + ); + +Due to the definition of the C<CPPPATH> variable, this yields, when we +re-execute the command: + + % cons -R /usr/all/repository hello + gcc -c -I. -I/usr/all/repository /usr/all/repository/hello.c -o hello.o + gcc -o hello hello.o /usr/all/repository/libworld.a + +The order of the C<-I> flags replicates, for the C preprocessor, the same +repository-directory search path that Cons uses for its own dependency +analysis. If there are multiple repositories and multiple C<CPPPATH> +directories, Cons will append the repository directories to the beginning of +each C<CPPPATH> directory, rapidly multiplying the number of C<-I> flags. +As an extreme example, a F<Construct> file containing: + + Repository qw( + /u1 + /u2 + ); + + $env = new cons( + CPPPATH => 'a:b:c', + ); + +Would yield a compilation command of: + + cc -Ia -I/u1/a -I/u2/a -Ib -I/u1/b -I/u2/b -Ic -I/u1/c -I/u2/c -c hello.c -o hello.o + +In order to shorten the command lines as much as possible, Cons will +remove C<-I> flags for any directories, locally or in the repositories, +which do not actually exist. (Note that the C<-I> flags are not included +in the MD5 signature calculation for the target file, so the target will +not be recompiled if the compilation command changes due to a directory +coming into existence.) + +Because Cons relies on the compiler's C<-I> flags to communicate the +order in which repository directories must be searched, Cons' handling +of repository directories is fundamentally incompatible with using +double-quotes on the C<#include> directives in any C source code that +you plan to modify: + + #include "file.h" /* DON'T USE DOUBLE-QUOTES LIKE THIS */ + +This is because most C preprocessors, when faced with such a directive, will +always first search the directory containing the source file. This +undermines the elaborate C<-I> options that Cons constructs to make the +preprocessor conform to its preferred search path. + +Consequently, when using repository trees in Cons, B<always> use +angle-brackets for included files in any C source (.c or .h) files that +you plan to modify locally: + + #include <file.h> /* USE ANGLE-BRACKETS INSTEAD */ + +Code that will not change can still safely use double quotes on #include +lines. + + +=head2 Repository_List + +Cons provides a C<Repository_List> command to return a list of all +repository directories in their current search order. This can be used for +debugging, or to do more complex Perl stuff: + + @list = Repository_List; + print join(' ', @list), "\n"; + + +=head2 Repository interaction with other Cons features + +Cons' handling of repository trees interacts correctly with other Cons +features, which is to say, it generally does what you would expect. + +Most notably, repository trees interact correctly, and rather powerfully, +with the 'Link' command. A repository tree may contain one or more +subdirectories for version builds established via C<Link> to a source +subdirectory. Cons will search for derived files in the appropriate build +subdirectories under the repository tree. + +--> + <para> - X + Often, a software project will have + one or more central repositories, + directory trees that contain + source code, or derived files, or both. + You can eliminate additional unnecessary + rebuilds of files by having &SCons;, + use files from one or more code repositories + to build files in your local build tree. </para> <section> <title>The &Repository; Method</title> +<!-- + +The repository directories specified may contain source files, derived files +(objects, libraries and executables), or both. If there is no local file +(source or derived) under the directory in which Cons is executed, then the +first copy of a same-named file found under a repository directory will be +used to build any local derived files. + +--> + + <para> + + You use the &Repository; method + to tell &SCons; to search one or more + central code repositories (in order) + for any source files and derived files + that are not present in the local build tree: + + </para> + + <programlisting> + env = Environment() + env.Program('hello.c') + Repository('/usr/repository1', '/usr/repository2') + </programlisting> + + <para> + + (Note that multiple calls to the &Repository; method + will simply add repositories to the global list + that &SCons; maintains, + with the exception that &SCons; will automatically eliminate + the current directory and any non-existent + directories from the list.) + + </para> + + </section> + + <section> + <title>Finding source files in repositories</title> + + <para> + + The above example + specifies that &SCons; + will first search for files under + the <filename>/usr/repository1</filename> tree + and next under the <filename>/usr/repository2</filename> tree. + &SCons; expects that any files it searches + for will be found in the same position + relative to the top-level directory XXX + In the above example, if the &hello_c; file is not + found in the local build tree, + &SCons; will search first for + a <filename>/usr/repository1/hello.c</filename> file + and then for a <filename>/usr/repository1/hello.c</filename> file + to use in its place. + + </para> + + <para> + + So given the &SConstruct; file above, + if the &hello_c; file exists in the local + build directory, + &SCons; will rebuild the &hello; program + as normal: + + </para> + + <literallayout> + % <userinput>scons .</userinput> + gcc -c hello.c -o hello.o + gcc -o hello hello.o + </literallayout> + + <para> + + If, however, there is no local &hello_c; file, + but one exists in <filename>/usr/repository1</filename>, + &SCons; will recompile the &hello; program + from the source file it finds in the repository: + + </para> + + <literallayout> + % <userinput>scons .</userinput> + gcc -c /usr/repository1/hello.c -o hello.o + gcc -o hello hello.o + </literallayout> + + <para> + + And similarly, if there is no local &hello_c; file + and no <filename>/usr/repository1/hello.c</filename>, + but one exists in <filename>/usr/repository2</filename>: + + </para> + + <literallayout> + % <userinput>scons .</userinput> + gcc -c /usr/repository2/hello.c -o hello.o + gcc -o hello hello.o + </literallayout> + + <para> + + </para> + + </section> + + <section> + <title>Finding the &SConstruct; file in repositories</title> + + <para> + + &SCons; will also search in repositories + for the &SConstruct; file and any specified &SConscript; files. + This poses a problem, though: how can &SCons; search a + repository tree for an &SConstruct; file + if the &SConstruct; file itself contains the information + about the pathname of the repository? + To solve this problem, &SCons; allows you + to specify repository directories + on the command line using the <literal>-Y</literal>: + + </para> + + <literallayout> + % <userinput>scons -Y /usr/repository1 -Y /usr/repository2 .</userinput> + </literallayout> + + <para> + + When looking for source or derived files, + &SCons; will first search the repositories + specified on the command line, + and then search the repositories + specified in the &SConstruct; or &SConscript; files. + + </para> + + </section> + + <section> + <title>Finding derived files in repositories</title> + + <para> + + If a repository contains not only source files, + but also derived files (such as object files, + libraries, or exectuables), &SCons; will perform + its normal MD5 signature calculation to + decide if a derived file in a repository is up-to-date, + or the derived file must be rebuilt in the local build directory. + For the &SCons; signature calculation to work correctly, + a repository tree must contain the &sconsign; files + that &SCons; uses to keep track of signature information. + + </para> + + <para> + + Usually, this would be done by a build integrator + who would run &SCons; in the repository + to create all of its derived files and &sconsign; files, + or who would &SCons; in a separate build directory + and copying the resulting tree to the desired repository: + + </para> + + <literallayout> + % <userinput>cd /usr/repository1</userinput> + % <userinput>scons .</userinput> + gcc -c hello.c -o hello.o + gcc -o hello hello.o + </literallayout> + + <para> + + (Note that this is safe even if the &SConstruct; file + lists <filename>/usr/repository1</filename> as a repository, + because &SCons; will remove the current build directory + from its repository list for that invocation.) + + </para> + + <para> + + Now, with the repository populated, + we only need to create the one local source file + we're interested in working with at the moment, + and use the <literal>-Y</literal> option to + tell &SCons; to fetch any other files it needs + from the repository: + + </para> + + <literallayout> + % <userinput>cd $HOME/build</userinput> + % <userinput>edit hello.c</userinput> + % <userinput>scons -Y /usr/repository1 .</userinput> + gcc -c hello.c -o hello.o + gcc -o hello hello.o + XXXXXXX + </literallayout> + <para> - X + Notice that &SCons; realizes that it does not need to + rebuild a local XXX.o file, + but instead uses the already-compiled XXX.o file + from the repository. </para> </section> <section> - <title>X</title> + <title>Guaranteeing local copies of files</title> + + <para> + + If the repository tree contains the complete results of a build, + and we try to build from the repository + without any files in our local tree, + something moderately surprising happens: + + </para> + + <literallayout> + % <userinput>mkdir $HOME/build2</userinput> + % <userinput>cd $HOME/build2</userinput> + % <userinput>cons -Y /usr/all/repository hello</userinput> + cons: "hello" is up-to-date. + </literallayout> + + <para> + + Why does &SCons; say that the &hello; program + is up-to-date when there is no &hello; program + in the local build directory? + Because the repository (not the local directory) + contains the up-to-date &hello; program, + and &SCons; correctly determines that nothing + needs to be done to rebuild that + up-to-date copy of the file. + + </para> + + <para> + + There are, however, many times when you want to ensure that a + local copy of a file always exists. + A packaging or testing script, for example, + may assume that certain generated files exist locally. + To tell &SCons; to make a copy of any up-to-date repository + file in the local build directory, + use the &Local; function: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + Local(hello) + </programlisting> + + <para> + + If we then run the same command, + &SCons; will make a local copy of the program + from the repository copy, + and tell you that it is doing so: + + </para> + + <literallayout> + % cons -R /usr/all/repository hello + Local copy of hello from /usr/all/repository/hello + scons: `hello' is up-to-date. + XXXXXX DO WE REALLY REPORT up-to-date, TOO? + </literallayout> <para> - X + (Notice that, because the act of making the local copy + is not considered a "build" of the &hello; file, + &SCons; still reports that it is up-to-date.) + XXXXXX DO WE REALLY REPORT up-to-date, TOO? </para> diff --git a/doc/user/run.sgml b/doc/user/run.sgml index ba802ff..30b61ca 100644 --- a/doc/user/run.sgml +++ b/doc/user/run.sgml @@ -22,22 +22,340 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> - <para> - X +<!-- - </para> +=head1 Invoking Cons - <section> - <title>Command-line Target Aliases</title> +The C<cons> command is usually invoked from the root of the build tree. A +F<Construct> file must exist in that directory. If the C<-f> argument is +used, then an alternate F<Construct> file may be used (and, possibly, an +alternate root, since C<cons> will cd to F<Construct> file's containing +directory). - <para> +If C<cons> is invoked from a child of the root of the build tree with +the C<-t> argument, it will walk up the directory hierarchy looking for a +F<Construct> file. (An alternate name may still be specified with C<-f>.) +The targets supplied on the command line will be modified to be relative +to the discovered F<Construct> file. For example, from a directory +containing a top-level F<Construct> file, the following invocation: - X + % cd libfoo/subdir + % cons -t target - </para> +is exactly equivalent to: - </section> + % cons libfoo/subdir/target + +If there are any C<Default> targets specified in the directory hierarchy's +F<Construct> or F<Conscript> files, only the default targets at or below +the directory from which C<cons -t> was invoked will be built. + +The command is invoked as follows: + + cons <arguments> , <construct-args> + +where I<arguments> can be any of the following, in any order: + +=over 10 + +=item I<target> + +Build the specified target. If I<target> is a directory, then recursively +build everything within that directory. + +=item I<+pattern> + +Limit the F<Conscript> files considered to just those that match I<pattern>, +which is a Perl regular expression. Multiple C<+> arguments are accepted. + +=item I<name>=<val> + +Sets I<name> to value I<val> in the C<ARG> hash passed to the top-level +F<Construct> file. + +=item C<-cc> + +Show command that would have been executed, when retrieving from cache. No +indication that the file has been retrieved is given; this is useful for +generating build logs that can be compared with real build logs. + +=item C<-cd> + +Disable all caching. Do not retrieve from cache nor flush to cache. + +=item C<-cr> + +Build dependencies in random order. This is useful when building multiple +similar trees with caching enabled. + +=item C<-cs> + +Synchronize existing build targets that are found to be up-to-date with +cache. This is useful if caching has been disabled with -cc or just recently +enabled with UseCache. + +=item C<-d> + +Enable dependency debugging. + +=item C<-f> <file> + +Use the specified file instead of F<Construct> (but first change to +containing directory of I<file>). + +=item C<-h> + +Show a help message local to the current build if one such is defined, and +exit. + +=item C<-k> + +Keep going as far as possible after errors. + +=item C<-o> <file> + +Read override file I<file>. + +=item C<-p> + +Show construction products in specified trees. No build is attempted. + +=item C<-pa> + +Show construction products and associated actions. No build is attempted. + +=item C<-pw> + +Show products and where they are defined. No build is attempted. + +=item C<-q> + +Make the build quiet. Multiple C<-q> options may be specified. + +A single C<-q> options suppress messages about Installing and Removing +targets. + +Two C<-q> options suppress build command lines and target up-to-date +messages. + +=item C<-r> + +Remove construction products associated with <targets>. No build is +attempted. + +=item C<-R> <repos> + +Search for files in I<repos>. Multiple B<-R> I<repos> directories are +searched in the order specified. + +=item C<-S> <pkg> + +Use the sig::<pkg> package to calculate. Supported <pkg> values +include "md5" for MD5 signature calculation and "md5::debug" for debug +information about MD5 signature calculation. + +If the specified package ends in <::debug>, signature debug information +will be printed to the file name specified in the C<CONS_SIG_DEBUG> +environment variable, or to standard output if the environment variable +is not set. + +=item C<-t> + +Traverse up the directory hierarchy looking for a F<Construct> file, +if none exists in the current directory. Targets will be modified to +be relative to the F<Construct> file. + +Internally, C<cons> will change its working directory to the directory +which contains the top-level F<Construct> file and report: + + cons: Entering directory `top-level-directory' + +This message indicates to an invoking editor (such as emacs) or build +environment that Cons will now report all file names relative to the +top-level directory. This message can not be suppressed with the C<-q> +option. + +=item C<-v> + +Show C<cons> version and continue processing. + +=item C<-V> + +Show C<cons> version and exit. + +=item C<-wf> <file> + +Write all filenames considered into I<file>. + +=item C<-x> + +Show a help message similar to this one, and exit. + +=back + +And I<construct-args> can be any arguments that you wish to process in the +F<Construct> file. Note that there should be a B<-,-> separating the arguments +to cons and the arguments that you wish to process in the F<Construct> file. + +Processing of I<construct-args> can be done by any standard package like +B<Getopt> or its variants, or any user defined package. B<cons> will pass in +the I<construct-args> as B<@ARGV> and will not attempt to interpret anything +after the B<-,->. + + % cons -R /usr/local/repository -d os=solaris +driver -,- -c test -f DEBUG + +would pass the following to cons + + -R /usr/local/repository -d os=solaris +driver + +and the following, to the top level F<Construct> file as B<@ARGV> + + -c test -f DEBUG + +Note that C<cons -r .> is equivalent to a full recursive C<make clean>, +but requires no support in the F<Construct> file or any F<Conscript> +files. This is most useful if you are compiling files into source +directories (if you separate the F<build> and F<export> directories, +then you can just remove the directories). + +The options C<-p>, C<-pa>, and C<-pw> are extremely useful for use as an aid +in reading scripts or debugging them. If you want to know what script +installs F<export/include/foo.h>, for example, just type: + + % cons -pw export/include/foo.h + +=head1 Selective builds + +Cons provides two methods for reducing the size of given build. The first is +by specifying targets on the command line, and the second is a method for +pruning the build tree. We'll consider target specification first. + + +=head2 Selective targeting + +Like make, Cons allows the specification of ``targets'' on the command +line. Cons targets may be either files or directories. When a directory is +specified, this is simply a short-hand notation for every derivable +product-,-that Cons knows about-,-in the specified directory and below. For +example: + + % cons build/hello/hello.o + +means build F<hello.o> and everything that F<hello.o> might need. This is +from a previous version of the B<Hello, World!> program in which F<hello.o> +depended upon F<export/include/world.h>. If that file is not up-to-date +(because someone modified F<src/world/world.h)>, then it will be rebuilt, +even though it is in a directory remote from F<build/hello>. + +In this example: + + % cons build + +Everything in the F<build> directory is built, if necessary. Again, this may +cause more files to be built. In particular, both F<export/include/world.h> +and F<export/lib/libworld.a> are required by the F<build/hello> directory, +and so they will be built if they are out-of-date. + +If we do, instead: + + % cons export + +then only the files that should be installed in the export directory will be +rebuilt, if necessary, and then installed there. Note that C<cons build> +might build files that C<cons export> doesn't build, and vice-versa. + + +=head2 No ``special'' targets + +With Cons, make-style ``special'' targets are not required. The simplest +analog with Cons is to use special F<export> directories, instead. Let's +suppose, for example, that you have a whole series of unit tests that are +associated with your code. The tests live in the source directory near the +code. Normally, however, you don't want to build these tests. One solution +is to provide all the build instructions for creating the tests, and then to +install the tests into a separate part of the tree. If we install the tests +in a top-level directory called F<tests>, then: + + % cons tests + +will build all the tests. + + % cons export + +will build the production version of the system (but not the tests), and: + + % cons build + +should probably be avoided (since it will compile tests unnecessarily). + +If you want to build just a single test, then you could explicitly name the +test (in either the F<tests> directory or the F<build> directory). You could +also aggregate the tests into a convenient hierarchy within the tests +directory. This hierarchy need not necessarily match the source hierarchy, +in much the same manner that the include hierarchy probably doesn't match +the source hierarchy (the include hierarchy is unlikely to be more than two +levels deep, for C programs). + +If you want to build absolutely everything in the tree (subject to whatever +options you select), you can use: + + % cons . + +This is not particularly efficient, since it will redundantly walk all the +trees, including the source tree. The source tree, of course, may have +buildable objects in it-,-nothing stops you from doing this, even if you +normally build in a separate build tree. + + +=head1 Build Pruning + +In conjunction with target selection, B<build pruning> can be used to reduce +the scope of the build. In the previous peAcH and baNaNa example, we have +already seen how script-driven build pruning can be used to make only half +of the potential build available for any given invocation of C<cons>. Cons +also provides, as a convenience, a command line convention that allows you +to specify which F<Conscript> files actually get ``built''-,-that is, +incorporated into the build tree. For example: + + % cons build +world + +The C<+> argument introduces a Perl regular expression. This must, of +course, be quoted at the shell level if there are any shell meta-characters +within the expression. The expression is matched against each F<Conscript> +file which has been mentioned in a C<Build> statement, and only those +scripts with matching names are actually incorporated into the build +tree. Multiple such arguments are allowed, in which case a match against any +of them is sufficient to cause a script to be included. + +In the example, above, the F<hello> program will not be built, since Cons +will have no knowledge of the script F<hello/Conscript>. The F<libworld.a> +archive will be built, however, if need be. + +There are a couple of uses for build pruning via the command line. Perhaps +the most useful is the ability to make local changes, and then, with +sufficient knowledge of the consequences of those changes, restrict the size +of the build tree in order to speed up the rebuild time. A second use for +build pruning is to actively prevent the recompilation of certain files that +you know will recompile due to, for example, a modified header file. You may +know that either the changes to the header file are immaterial, or that the +changes may be safely ignored for most of the tree, for testing +purposes.With Cons, the view is that it is pragmatic to admit this type of +behavior, with the understanding that on the next full build everything that +needs to be rebuilt will be. There is no equivalent to a ``make touch'' +command, to mark files as permanently up-to-date. So any risk that is +incurred by build pruning is mitigated. For release quality work, obviously, +we recommend that you do not use build pruning (it's perfectly OK to use +during integration, however, for checking compilation, etc. Just be sure to +do an unconstrained build before committing the integration). + +--> + + <para> + + X + + </para> <section> <title>Selective Builds</title> diff --git a/doc/user/scanners.sgml b/doc/user/scanners.sgml index 3024c02..8d13b0c 100644 --- a/doc/user/scanners.sgml +++ b/doc/user/scanners.sgml @@ -22,6 +22,105 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + +<!-- + +=head1 Using and writing dependency scanners + +QuickScan allows simple target-independent scanners to be set up for +source files. Only one QuickScan scanner may be associated with any given +source file and environment, although the same scanner may (and should) +be used for multiple files of a given type. + +A QuickScan scanner is only ever invoked once for a given source file, +and it is only invoked if the file is used by some target in the tree +(i.e., there is a dependency on the source file). + +QuickScan is invoked as follows: + + QuickScan CONSENV CODEREF, FILENAME [, PATH] + +The subroutine referenced by CODEREF is expected to return a list of +filenames included directly by FILE. These filenames will, in turn, be +scanned. The optional PATH argument supplies a lookup path for finding +FILENAME and/or files returned by the user-supplied subroutine. The PATH +may be a reference to an array of lookup-directory names, or a string of +names separated by the system's separator character (':' on UNIX systems, +';' on Windows NT). + +The subroutine is called once for each line in the file, with $_ set to the +current line. If the subroutine needs to look at additional lines, or, for +that matter, the entire file, then it may read them itself, from the +filehandle SCAN. It may also terminate the loop, if it knows that no further +include information is available, by closing the filehandle. + +Whether or not a lookup path is provided, QuickScan first tries to lookup +the file relative to the current directory (for the top-level file +supplied directly to QuickScan), or from the directory containing the +file which referenced the file. This is not very general, but seems good +enough, especially if you have the luxury of writing your own utilities +and can control the use of the search path in a standard way. + +Here's a real example, taken from a F<Construct> file here: + + sub cons::SMFgen { + my($env, @tables) = @_; + foreach $t (@tables) { + $env->QuickScan(sub { /\b\S*?\.smf\b/g }, "$t.smf", + $env->{SMF_INCLUDE_PATH}); + $env->Command(["$t.smdb.cc","$t.smdb.h","$t.snmp.cc", + "$t.ami.cc", "$t.http.cc"], "$t.smf", + q(smfgen %( %SMF_INCLUDE_OPT %) %<)); + } + } + +The subroutine above finds all names of the form <name>.smf in the +file. It will return the names even if they're found within comments, +but that's OK (the mechanism is forgiving of extra files; they're just +ignored on the assumption that the missing file will be noticed when +the program, in this example, smfgen, is actually invoked). + +[NOTE that the form C<$env-E<gt>QuickScan ...> and C<$env-E<gt>Command +...> should not be necessary, but, for some reason, is required +for this particular invocation. This appears to be a bug in Perl or +a misunderstanding on my part; this invocation style does not always +appear to be necessary.] + +Here is another way to build the same scanner. This one uses an +explicit code reference, and also (unnecessarily, in this case) reads +the whole file itself: + + sub myscan { + my(@includes); + do { + push(@includes, /\b\S*?\.smf\b/g); + } while <SCAN>; + @includes + } + +Note that the order of the loop is reversed, with the loop test at the +end. This is because the first line is already read for you. This scanner +can be attached to a source file by: + + QuickScan $env \&myscan, "$_.smf"; + +This final example, which scans a different type of input file, takes +over the file scanning rather than being called for each input line: + + $env->QuickScan( + sub { my(@includes) = (); + do { + push(@includes, $3) + if /^(#include|import)\s+(\")(.+)(\")/ && $3 + } while <SCAN>; + @includes + }, + "$idlFileName", + "$env->{CPPPATH};$BUILD/ActiveContext/ACSCLientInterfaces" + ); + +--> + <para> X diff --git a/doc/user/separate.sgml b/doc/user/separate.sgml new file mode 100644 index 0000000..e1c0e49 --- /dev/null +++ b/doc/user/separate.sgml @@ -0,0 +1,128 @@ +<!-- + + Copyright (c) 2001, 2002, 2003 Steven Knight + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + +<!-- + +=head1 Separating source and build trees + +It's often desirable to keep any derived files from the build completely +separate from the source files. This makes it much easier to keep track of +just what is a source file, and also makes it simpler to handle B<variant> +builds, especially if you want the variant builds to co-exist. + +=head2 Separating build and source directories using the Link command + +Cons provides a simple mechanism that handles all of these requirements. The +C<Link> command is invoked as in this example: + + Link 'build' => 'src'; + +The specified directories are ``linked'' to the specified source +directory. Let's suppose that you setup a source directory, F<src>, with the +sub-directories F<world> and F<hello> below it, as in the previous +example. You could then substitute for the original build lines the +following: + + Build qw( + build/world/Conscript + build/hello/Conscript + ); + +Notice that you treat the F<Conscript> file as if it existed in the build +directory. Now if you type the same command as before, you will get the +following results: + + % cons export + Install build/world/world.h as export/include/world.h + cc -Iexport/include -c build/hello/hello.c -o build/hello/hello.o + cc -Iexport/include -c build/world/world.c -o build/world/world.o + ar r build/world/libworld.a build/world/world.o + ar: creating build/world/libworld.a + ranlib build/world/libworld.a + Install build/world/libworld.a as export/lib/libworld.a + cc -o build/hello/hello build/hello/hello.o -Lexport/lib -lworld + Install build/hello/hello as export/bin/hello + +Again, Cons has taken care of the details for you. In particular, you will +notice that all the builds are done using source files and object files from +the build directory. For example, F<build/world/world.o> is compiled from +F<build/world/world.c>, and F<export/include/world.h> is installed from +F<build/world/world.h>. This is accomplished on most systems by the simple +expedient of ``hard'' linking the required files from each source directory +into the appropriate build directory. + +The links are maintained correctly by Cons, no matter what you do to the +source directory. If you modify a source file, your editor may do this ``in +place'' or it may rename it first and create a new file. In the latter case, +any hard link will be lost. Cons will detect this condition the next time +the source file is needed, and will relink it appropriately. + +You'll also notice, by the way, that B<no> changes were required to the +underlying F<Conscript> files. And we can go further, as we shall see in the +next section. + +=head2 Explicit references to the source directory + +When using the C<Link> command on some operating systems or with some +tool chains, it's sometimes useful to have a command actually use +the path name to the source directory, not the build directory. For +example, on systems that must copy, not "hard link," the F<src/> and +F<build/> copies of C<Linked> files, using the F<src/> path of a file +name might make an editor aware that a syntax error must be fixed in the +source directory, not the build directory. + +You can tell Cons that you want to use the "source path" for a file by +preceding the file name with a ``!'' (exclamation point). For example, +if we add a ``!'' to the beginning of a source file: + + Program $env "foo", "!foo.c"; # Notice initial ! on foo.c + +Cons will compile the target as follows: + + cc -c src/foo.c -o build/foo.o + cc -o build/foo build/foo.o + +Notice that Cons has compiled the program from the the F<src/foo.c> +source file. Without the initial ``!'', Cons would have compiled the +program using the F<build/foo.c> path name. + +--> + + <para> + + X + + </para> + + <section> + <title>X</title> + + <para> + + X + + </para> + + </section> diff --git a/doc/user/simple.sgml b/doc/user/simple.sgml index 5de9d3c..9071160 100644 --- a/doc/user/simple.sgml +++ b/doc/user/simple.sgml @@ -22,85 +22,223 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + +<!-- + +=head2 Perl scripts + +Cons is Perl-based. That is, Cons scripts F<Conscript> and F<Construct> +files, the equivalent to F<Makefile> or F<makefile> are all written in +Perl. This provides an immediate benefit: the language for writing scripts +is a familiar one. Even if you don't happen to be a Perl programmer, it +helps to know that Perl is basically just a simple declarative language, +with a well-defined flow of control, and familiar semantics. It has +variables that behave basically the way you would expect them to, +subroutines, flow of control, and so on. There is no special syntax +introduced for Cons. The use of Perl as a scripting language simplifies +the task of expressing the appropriate solution to the often complex +requirements of a build. + +--> + <para> - X + Here's how to build the famous "Hello, World!" example using &SCons;. + Enter the following into a file name &SConstruct;: </para> - <section> - <title>The &SConstruct; File</title> + <programlisting> + int + main() + { + printf("Hello, world!\n"); + } + </programlisting> - <para> + <programlisting> + env = Environment() + env.Program('hello.c') + </programlisting> - X + <para> - </para> + That's it. Now run the &scons; command to build the program. + On a POSIX-compliant system like Linux or UNIX, + you'll see something like: - </section> + </para> - <section> - <title>The &Program; Builder</title> + <literallayout> + % <userinput>scons .</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + </literallayout> - <para> + <para> - X + On a Windows system with the Microsoft Visual C++ compiler, + you'll see something like: - </para> + </para> - </section> + <literallayout> + C:\><userinput>scons .</userinput> + cl /Fohello.obj hello.c + link /Fohello.exe hello.obj + </literallayout> + + <para> + + First, notice that you need to supply a '.' on the command line. + This tells &SCons; to build everything in the current directory + or its subdirectories. + We'll tell you later how to avoid having to use the '.' + + </para> + + <para> + + Next, notice that the same input &SConstruct; file + without any special input, + generates the right output file names on both systems: + <filename>hello.o</filename> and <filename>hello</filename> + on POSIX systems, + <filename>hello.obj</filename> and <filename>hello.exe</filename> + on Windows systems. + (We won't provide side-by-side examples of POSIX + and Windows runs for all future examples; + just know that XXX.) + + </para> <section> - <title>The &Library; Builder</title> + <title>The &SConstruct; File</title> <para> - X + If you're used to build systems like &Make; + you've already figured out that the &SConstruct; file + is the &SCons; equivalent of a &Makefile;. + That is, the &SConstruct; file is the input file + that &SCons; reads to control the build. </para> - </section> + <para> - <section> - <title>The &Install; Builder</title> + What may not be obvious, though, is that + there's an important difference between + an &SConstruct; file and a &Makefile: + the &SConstruct; file is actually a Python script. + If you're not already familiar with Python, don't worry; + you don't really need to know Python to be able to use + &SCons; effectively. + But you'll see that being able to use the power of a + real scripting language + can greatly simplify the solutions + to complex requirements of real-world builds. + + </para> <para> - X + For now, one ramification of using Python as the + scripting language means that you can put comments + in your &SConstruct; file using Python's commenting convention; + that is, everything between a '#' and the end of the line + will be ignored: </para> + <programlisting> + env = Environment() # Create an environment. + # Arrange to build the "hello" program. + env.Program('hello.c') + </programlisting> + </section> <section> - <title>Running &SCons;</title> + <title>Compiling Multiple Source Files</title> <para> - X + If you want </para> + <programlisting> + env = Environment() + env.Program('program', ['main.c', 'file1.c', 'file2.']) + </programlisting> + + <programlisting> + env = Environment() + env.Program('program', Split('main.c file1.c file2.')) + </programlisting> + + <literallayout> + % <userinput>scons .</userinput> + cc -c file1.c -o file1.o + cc -c file2.c -o file2.o + cc -c main.c -o main.o + cc -o program main.o file1.o file2.o + </literallayout> + </section> <section> - <title>The &Default; Method</title> + <title>Compiling Multiple Programs</title> <para> - X + If you want </para> + <programlisting> + env = Environment() + env.Program('foo.c') + env.Program('bar', ['bar1.c', 'bar2.c']) + </programlisting> + + <literallayout> + % <userinput>scons .</userinput> + cc -c bar1.c -o bar1.o + cc -c bar2.c -o bar2.o + cc -o bar bar1.o bar2.o + cc -c foo.c -o foo.o + cc -o foo foo.o + </literallayout> + </section> <section> - <title>The &Help; Method</title> + <title>Sharing Files Between Multiple Programs</title> <para> - X + If you want </para> + <programlisting> + common = ['common1.c', 'common2.c'] + env = Environment() + env.Program(['foo.c'] + common) + env.Program('bar', ['bar1.c', 'bar2.c'] + common) + </programlisting> + + <literallayout> + % <userinput>scons .</userinput> + cc -c bar1.c -o bar1.o + cc -c bar2.c -o bar2.o + cc -c common1.c -o common1.o + cc -c common2.c -o common2.o + cc -o bar bar1.o bar2.o common1.o common2.o + cc -c foo.c -o foo.o + cc -o foo foo.o common1.o common2.o + </literallayout> + </section> diff --git a/doc/user/troubleshoot.sgml b/doc/user/troubleshoot.sgml index 3024c02..448777f 100644 --- a/doc/user/troubleshoot.sgml +++ b/doc/user/troubleshoot.sgml @@ -22,6 +22,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + <para> X diff --git a/doc/user/variants.sgml b/doc/user/variants.sgml index 3024c02..fdd209e 100644 --- a/doc/user/variants.sgml +++ b/doc/user/variants.sgml @@ -22,6 +22,91 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + +<!-- + +=head1 Variant builds + + +=head2 Hello, World! for baNaNa and peAcH OS's + +Variant builds require just another simple extension. Let's take as an +example a requirement to allow builds for both the baNaNa and peAcH +operating systems. In this case, we are using a distributed file system, +such as NFS to access the particular system, and only one or the other of +the systems has to be compiled for any given invocation of C<cons>. Here's +one way we could set up the F<Construct> file for our B<Hello, World!> +application: + + # Construct file for Hello, World! + + die qq(OS must be specified) unless $OS = $ARG{OS}; + die qq(OS must be "peach" or "banana") + if $OS ne "peach" && $OS ne "banana"; + + # Where to put all our shared products. + $EXPORT = "#export/$OS"; + + Export qw( CONS INCLUDE LIB BIN ); + + # Standard directories for sharing products. + $INCLUDE = "$EXPORT/include"; + $LIB = "$EXPORT/lib"; + $BIN = "$EXPORT/bin"; + + # A standard construction environment. + $CONS = new cons ( + CPPPATH => $INCLUDE, # Include path for C Compilations + LIBPATH => $LIB, # Library path for linking programs + LIBS => '-lworld', # List of standard libraries + ); + + # $BUILD is where we will derive everything. + $BUILD = "#build/$OS"; + + # Tell cons where the source files for $BUILD are. + Link $BUILD => 'src'; + + Build ( + "$BUILD/hello/Conscript", + "$BUILD/world/Conscript", + ); + +Now if we login to a peAcH system, we can build our B<Hello, World!> +application for that platform: + + % cons export OS=peach + Install build/peach/world/world.h as export/peach/include/world.h + cc -Iexport/peach/include -c build/peach/hello/hello.c -o build/peach/hello/hello.o + cc -Iexport/peach/include -c build/peach/world/world.c -o build/peach/world/world.o + ar r build/peach/world/libworld.a build/peach/world/world.o + ar: creating build/peach/world/libworld.a + ranlib build/peach/world/libworld.a + Install build/peach/world/libworld.a as export/peach/lib/libworld.a + cc -o build/peach/hello/hello build/peach/hello/hello.o -Lexport/peach/lib -lworld + Install build/peach/hello/hello as export/peach/bin/hello + + +=head2 Variations on a theme + +Other variations of this model are possible. For example, you might decide +that you want to separate out your include files into platform dependent and +platform independent files. In this case, you'd have to define an +alternative to C<$INCLUDE> for platform-dependent files. Most F<Conscript> +files, generating purely platform-independent include files, would not have +to change. + +You might also want to be able to compile your whole system with debugging +or profiling, for example, enabled. You could do this with appropriate +command line options, such as C<DEBUG=on>. This would then be translated +into the appropriate platform-specific requirements to enable debugging +(this might include turning off optimization, for example). You could +optionally vary the name space for these different types of systems, but, as +we'll see in the next section, it's not B<essential> to do this, since Cons +is pretty smart about rebuilding things when you change options. + +--> + <para> X |